From ac5c0fd584e2359bf10038bd627b416aa06f6e02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Lemaire?= Date: Mon, 23 Dec 2013 14:09:52 +0100 Subject: [PATCH] Refactored opengl terrain rendering for future use of shaders --- src/render/opengl/BaseExplorerChunk.cpp | 170 -------------------- src/render/opengl/BaseExplorerChunk.h | 58 ------- src/render/opengl/ExplorerChunkTerrain.cpp | 161 +++++++++++++++---- src/render/opengl/ExplorerChunkTerrain.h | 34 +++- src/render/opengl/OpenGLRenderer.cpp | 7 + src/render/opengl/OpenGLRenderer.h | 1 + src/render/opengl/OpenGLTerrain.cpp | 144 +++++++++++++++++ src/render/opengl/OpenGLTerrain.h | 40 +++++ src/render/opengl/WidgetExplorer.cpp | 178 +-------------------- src/render/opengl/WidgetExplorer.h | 14 -- src/render/opengl/opengl.pro | 8 +- src/render/opengl/opengl_global.h | 3 +- src/system/ParallelPool.cpp | 55 +++++++ src/system/ParallelPool.h | 43 +++++ src/system/system.pro | 6 +- src/system/system_global.h | 1 + 16 files changed, 465 insertions(+), 458 deletions(-) delete mode 100644 src/render/opengl/BaseExplorerChunk.cpp delete mode 100644 src/render/opengl/BaseExplorerChunk.h create mode 100644 src/render/opengl/OpenGLTerrain.cpp create mode 100644 src/render/opengl/OpenGLTerrain.h create mode 100644 src/system/ParallelPool.cpp create mode 100644 src/system/ParallelPool.h diff --git a/src/render/opengl/BaseExplorerChunk.cpp b/src/render/opengl/BaseExplorerChunk.cpp deleted file mode 100644 index 82f7322..0000000 --- a/src/render/opengl/BaseExplorerChunk.cpp +++ /dev/null @@ -1,170 +0,0 @@ -#include "BaseExplorerChunk.h" - -#include -#include -#include "ColorProfile.h" - -#ifndef GL_CLAMP_TO_EDGE -#define GL_CLAMP_TO_EDGE 0x812F -#endif - -BaseExplorerChunk::BaseExplorerChunk(SoftwareRenderer* renderer) -{ - _renderer = renderer; - _color_profile = new ColorProfile; - - priority = 0.0; - _reset_needed = false; - - _texture = new QImage(1, 1, QImage::Format_ARGB32); - _texture_id = 0; - _texture_changed = false; - _texture_current_size = 0; - _texture_max_size = 0; -} - -BaseExplorerChunk::~BaseExplorerChunk() -{ - _lock_data.lock(); - delete _color_profile; - delete _texture; - _lock_data.unlock(); -} - -bool BaseExplorerChunk::maintain() -{ - bool subchanged; - - _lock_data.lock(); - if (_reset_needed) - { - _reset_needed = false; - _texture_current_size = 0; - onResetEvent(); - } - _lock_data.unlock(); - - subchanged = onMaintainEvent(); - - // Improve texture resolution - if (_texture_current_size < _texture_max_size) - { - int new_texture_size = _texture_current_size ? _texture_current_size * 2 : 1; - QImage* new_image = new QImage(_texture->scaled(new_texture_size + 1, new_texture_size + 1, Qt::IgnoreAspectRatio, Qt::FastTransformation)); - for (int j = 0; j <= new_texture_size; j++) - { - for (int i = 0; i <= new_texture_size; i++) - { - if (_texture_current_size <= 1 || i % 2 != 0 || j % 2 != 0) - { - Color color = getTextureColor((double)i / (double)new_texture_size, 1.0 - (double)j / (double)new_texture_size); - color = _color_profile->apply(color); - color.normalize(); - new_image->setPixel(i, j, color.to32BitBGRA()); - } - } - } - - _lock_data.lock(); - delete _texture; - _texture = new_image; - _texture_current_size = new_texture_size; - _texture_changed = true; - _lock_data.unlock(); - - /*if (_texture_current_size < 4 && _texture_current_size < _texture_max_size) - { - maintain(); - }*/ - - return true; - } - else - { - return subchanged; - } -} - -void BaseExplorerChunk::updatePriority(CameraDefinition* camera) -{ - if (_reset_needed || (_texture_max_size > 1 && _texture_current_size <= 1)) - { - priority = 1000.0; - } - else if (_texture_current_size == _texture_max_size) - { - priority = -1000.0; - } - else - { - priority = getDisplayedSizeHint(camera) - _texture_current_size; - } - onCameraEvent(camera); -} - -void BaseExplorerChunk::render(QGLWidget* widget) -{ - // Put texture in place - _lock_data.lock(); - if (_texture_changed) - { - _texture_changed = false; - if (_texture_id) - { - widget->deleteTexture(_texture_id); - } - // TODO Only do the scale if not power-of-two textures are unsupported by GPU - _texture_id = widget->bindTexture(_texture->scaled(_texture_current_size, _texture_current_size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); - //_texture_id = widget->bindTexture(*_texture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } - else - { - glBindTexture(GL_TEXTURE_2D, _texture_id); - } - _lock_data.unlock(); - - // Delegate poly rendering to subclass - if (!_reset_needed) - { - onRenderEvent(widget); - } -} - -void BaseExplorerChunk::askReset() -{ - _reset_needed = true; -} - -void BaseExplorerChunk::setMaxTextureSize(int size) -{ - _texture_max_size = size; -} - -void BaseExplorerChunk::onCameraEvent(CameraDefinition*) -{ -} - -void BaseExplorerChunk::onResetEvent() -{ -} - -bool BaseExplorerChunk::onMaintainEvent() -{ - return false; -} - -void BaseExplorerChunk::onRenderEvent(QGLWidget*) -{ -} - -double BaseExplorerChunk::getDisplayedSizeHint(CameraDefinition*) -{ - return 0.0; -} - -Color BaseExplorerChunk::getTextureColor(double, double) -{ - return COLOR_TRANSPARENT; -} diff --git a/src/render/opengl/BaseExplorerChunk.h b/src/render/opengl/BaseExplorerChunk.h deleted file mode 100644 index 08c9780..0000000 --- a/src/render/opengl/BaseExplorerChunk.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef BASEEXPLORERCHUNK_H -#define BASEEXPLORERCHUNK_H - -#include "opengl_global.h" - -#include -#include "Color.h" - -class QImage; -class QGLWidget; - -namespace paysages { -namespace opengl { - -class BaseExplorerChunk -{ -public: - virtual ~BaseExplorerChunk(); - - bool maintain(); - void updatePriority(CameraDefinition* camera); - void render(QGLWidget* widget); - - double priority; -protected: - BaseExplorerChunk(SoftwareRenderer* renderer); - - inline SoftwareRenderer* renderer() {return _renderer;} - - void askReset(); - void setMaxTextureSize(int size); - - virtual void onCameraEvent(CameraDefinition* camera); - virtual void onResetEvent(); - virtual bool onMaintainEvent(); - virtual void onRenderEvent(QGLWidget* widget); - virtual double getDisplayedSizeHint(CameraDefinition* camera); - virtual Color getTextureColor(double x, double y); - - QMutex _lock_data; - -private: - SoftwareRenderer* _renderer; - ColorProfile* _color_profile; - - bool _reset_needed; - - QImage* _texture; - unsigned int _texture_id; - bool _texture_changed; - int _texture_current_size; - int _texture_max_size; -}; - -} -} - -#endif // BASEEXPLORERCHUNK_H diff --git a/src/render/opengl/ExplorerChunkTerrain.cpp b/src/render/opengl/ExplorerChunkTerrain.cpp index ed0d595..4fd3acb 100644 --- a/src/render/opengl/ExplorerChunkTerrain.cpp +++ b/src/render/opengl/ExplorerChunkTerrain.cpp @@ -1,13 +1,28 @@ #include "ExplorerChunkTerrain.h" +#include OPENGL_FUNCTIONS_INCLUDE #include -#include +#include +#include +#include "ColorProfile.h" #include "CameraDefinition.h" -#include "SoftwareRenderer.h" +#include "OpenGLRenderer.h" #include "TerrainRenderer.h" -ExplorerChunkTerrain::ExplorerChunkTerrain(SoftwareRenderer* renderer, double x, double z, double size, int nbchunks, double water_height) : BaseExplorerChunk(renderer) +ExplorerChunkTerrain::ExplorerChunkTerrain(OpenGLRenderer* renderer, double x, double z, double size, int nbchunks, double water_height): + _renderer(renderer) { + _color_profile = new ColorProfile; + + priority = 0.0; + _reset_needed = false; + + _texture = new QImage(1, 1, QImage::Format_ARGB32); + texture = new QOpenGLTexture(*_texture); + _texture_changed = false; + _texture_current_size = 0; + _texture_max_size = 0; + _startx = x; _startz = z; _size = size; @@ -31,20 +46,70 @@ ExplorerChunkTerrain::ExplorerChunkTerrain(SoftwareRenderer* renderer, double x, ExplorerChunkTerrain::~ExplorerChunkTerrain() { _lock_data.lock(); + delete _color_profile; + delete _texture; + delete texture; delete [] _tessellation; _lock_data.unlock(); } -void ExplorerChunkTerrain::onResetEvent() +bool ExplorerChunkTerrain::maintain() { - _tessellation_current_size = 0; - _overwater = false; + bool subchanged; + + _lock_data.lock(); + if (_reset_needed) + { + _reset_needed = false; + _texture_current_size = 0; + _tessellation_current_size = 0; + _overwater = false; + } + _lock_data.unlock(); + + subchanged = onMaintainEvent(); + + // Improve texture resolution + if (_texture_current_size < _texture_max_size) + { + int new_texture_size = _texture_current_size ? _texture_current_size * 2 : 1; + QImage* new_image = new QImage(_texture->scaled(new_texture_size + 1, new_texture_size + 1, Qt::IgnoreAspectRatio, Qt::FastTransformation)); + for (int j = 0; j <= new_texture_size; j++) + { + for (int i = 0; i <= new_texture_size; i++) + { + if (_texture_current_size <= 1 || i % 2 != 0 || j % 2 != 0) + { + Color color = getTextureColor((double)i / (double)new_texture_size, (double)j / (double)new_texture_size); + color = _color_profile->apply(color); + color.normalize(); + new_image->setPixel(i, j, color.to32BitBGRA()); + } + } + } + + _lock_data.lock(); + delete _texture; + _texture = new_image; + _texture_current_size = new_texture_size; + _texture_changed = true; + _lock_data.unlock(); + + /*if (_texture_current_size < 4 && _texture_current_size < _texture_max_size) + { + maintain(); + }*/ + + return true; + } + else + { + return subchanged; + } } bool ExplorerChunkTerrain::onMaintainEvent() { - SoftwareRenderer* renderer = this->renderer(); - // Improve heightmap resolution if (_tessellation_current_size < _tessellation_max_size) { @@ -57,7 +122,7 @@ bool ExplorerChunkTerrain::onMaintainEvent() { if (_tessellation_current_size == 0 || i % old_tessellation_inc != 0 || j % old_tessellation_inc != 0) { - double height = renderer->getTerrainRenderer()->getHeight(_startx + _tessellation_step * (double) i, _startz + _tessellation_step * (double) j, 1); + double height = _renderer->getTerrainRenderer()->getHeight(_startx + _tessellation_step * (double) i, _startz + _tessellation_step * (double) j, 1); if (height >= _water_height) { _overwater = true; @@ -84,8 +149,21 @@ bool ExplorerChunkTerrain::onMaintainEvent() } } -void ExplorerChunkTerrain::onCameraEvent(CameraDefinition* camera) +void ExplorerChunkTerrain::updatePriority(CameraDefinition* camera) { + if (_reset_needed || (_texture_max_size > 1 && _texture_current_size <= 1)) + { + priority = 1000.0; + } + else if (_texture_current_size == _texture_max_size) + { + priority = -1000.0; + } + else + { + priority = getDisplayedSizeHint(camera) - _texture_current_size; + } + Vector3 camera_location = camera->getLocation(); // Handle position @@ -116,33 +194,62 @@ void ExplorerChunkTerrain::onCameraEvent(CameraDefinition* camera) _lock_data.unlock(); } -void ExplorerChunkTerrain::onRenderEvent(QGLWidget*) +void ExplorerChunkTerrain::render(OpenGLFunctions* functions) { + // Put texture in place _lock_data.lock(); - int tessellation_size = _tessellation_current_size; - double tsize = 1.0 / (double) _tessellation_max_size; + if (_texture_changed) + { + _texture_changed = false; + texture->destroy(); + // TODO Only do the scale if not power-of-two textures are unsupported by GPU + texture->setData(_texture->scaled(_texture_current_size, _texture_current_size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); + //texture->setData(*_texture); + texture->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::ClampToEdge); + texture->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::ClampToEdge); + } + texture->bind(); _lock_data.unlock(); - if (tessellation_size <= 1 or not _overwater) + // Delegate poly rendering to subclass + if (!_reset_needed) { - return; - } + _lock_data.lock(); + int tessellation_size = _tessellation_current_size; + double tsize = 1.0 / (double) _tessellation_max_size; + _lock_data.unlock(); - int tessellation_inc = _tessellation_max_size / (double) tessellation_size; - for (int j = 0; j < _tessellation_max_size; j += tessellation_inc) - { - glBegin(GL_QUAD_STRIP); - for (int i = 0; i <= _tessellation_max_size; i += tessellation_inc) + if (tessellation_size <= 1 or not _overwater) { - glTexCoord2d(tsize * (double) i, tsize * (double) j); - glVertex3d(_startx + _tessellation_step * (double) i, _tessellation[j * (_tessellation_max_size + 1) + i], _startz + _tessellation_step * (double) j); - glTexCoord2d(tsize * (double) i, tsize * (double) (j + tessellation_inc)); - glVertex3d(_startx + _tessellation_step * (double) i, _tessellation[(j + tessellation_inc) * (_tessellation_max_size + 1) + i], _startz + _tessellation_step * (double) (j + tessellation_inc)); + return; + } + + int tessellation_inc = _tessellation_max_size / (double) tessellation_size; + for (int j = 0; j < _tessellation_max_size; j += tessellation_inc) + { + functions->glBegin(GL_QUAD_STRIP); + for (int i = 0; i <= _tessellation_max_size; i += tessellation_inc) + { + functions->glTexCoord2d(tsize * (double) i, tsize * (double) j); + functions->glVertex3d(_startx + _tessellation_step * (double) i, _tessellation[j * (_tessellation_max_size + 1) + i], _startz + _tessellation_step * (double) j); + functions->glTexCoord2d(tsize * (double) i, tsize * (double) (j + tessellation_inc)); + functions->glVertex3d(_startx + _tessellation_step * (double) i, _tessellation[(j + tessellation_inc) * (_tessellation_max_size + 1) + i], _startz + _tessellation_step * (double) (j + tessellation_inc)); + } + functions->glEnd(); } - glEnd(); } } +void ExplorerChunkTerrain::askReset() +{ + _reset_needed = true; +} + +void ExplorerChunkTerrain::setMaxTextureSize(int size) +{ + _texture_max_size = size; +} + double ExplorerChunkTerrain::getDisplayedSizeHint(CameraDefinition* camera) { double distance; @@ -170,7 +277,7 @@ double ExplorerChunkTerrain::getDisplayedSizeHint(CameraDefinition* camera) Color ExplorerChunkTerrain::getTextureColor(double x, double y) { Vector3 location = {_startx + x * _size, 0.0, _startz + y * _size}; - return renderer()->getTerrainRenderer()->getFinalColor(location, 0.01); + return _renderer->getTerrainRenderer()->getFinalColor(location, 0.01); } Vector3 ExplorerChunkTerrain::getCenter() diff --git a/src/render/opengl/ExplorerChunkTerrain.h b/src/render/opengl/ExplorerChunkTerrain.h index ce21462..2c7c911 100644 --- a/src/render/opengl/ExplorerChunkTerrain.h +++ b/src/render/opengl/ExplorerChunkTerrain.h @@ -1,26 +1,34 @@ #ifndef EXPLORERCHUNKTERRAIN_H #define EXPLORERCHUNKTERRAIN_H -#include "BaseExplorerChunk.h" +#include "opengl_global.h" -#include "Vector3.h" +#include +class QImage; +class QOpenGLTexture; namespace paysages { namespace opengl { -class OPENGLSHARED_EXPORT ExplorerChunkTerrain:public BaseExplorerChunk +class OPENGLSHARED_EXPORT ExplorerChunkTerrain { public: - ExplorerChunkTerrain(SoftwareRenderer* renderer, double x, double z, double size, int nbchunks, double water_height); + ExplorerChunkTerrain(OpenGLRenderer* renderer, double x, double z, double size, int nbchunks, double water_height); ~ExplorerChunkTerrain(); - void onCameraEvent(CameraDefinition* camera); - void onResetEvent(); + bool maintain(); + void updatePriority(CameraDefinition* camera); + void render(OpenGLFunctions* functions); + + void askReset(); + void setMaxTextureSize(int size); + bool onMaintainEvent(); - void onRenderEvent(QGLWidget* widget); double getDisplayedSizeHint(CameraDefinition* camera); Color getTextureColor(double x, double y); + double priority; + private: Vector3 getCenter(); @@ -38,6 +46,18 @@ private: int _tessellation_current_size; double _tessellation_step; + QMutex _lock_data; + + OpenGLRenderer* _renderer; + ColorProfile* _color_profile; + + bool _reset_needed; + + QImage* _texture; + QOpenGLTexture* texture; + bool _texture_changed; + int _texture_current_size; + int _texture_max_size; }; } diff --git a/src/render/opengl/OpenGLRenderer.cpp b/src/render/opengl/OpenGLRenderer.cpp index d3e943d..311de4d 100644 --- a/src/render/opengl/OpenGLRenderer.cpp +++ b/src/render/opengl/OpenGLRenderer.cpp @@ -5,6 +5,7 @@ #include "OpenGLSharedState.h" #include "OpenGLSkybox.h" #include "OpenGLWater.h" +#include "OpenGLTerrain.h" OpenGLRenderer::OpenGLRenderer(Scenery* scenery): SoftwareRenderer(scenery) @@ -16,12 +17,14 @@ OpenGLRenderer::OpenGLRenderer(Scenery* scenery): skybox = new OpenGLSkybox(this); water = new OpenGLWater(this); + terrain = new OpenGLTerrain(this); } OpenGLRenderer::~OpenGLRenderer() { delete skybox; delete water; + delete terrain; delete functions; delete shared_state; @@ -60,6 +63,9 @@ void OpenGLRenderer::initialize() water->initialize(); water->updateScenery(); + + terrain->initialize(); + terrain->updateScenery(); } } @@ -79,6 +85,7 @@ void OpenGLRenderer::paint() functions->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); skybox->render(); + terrain->render(); water->render(); } } diff --git a/src/render/opengl/OpenGLRenderer.h b/src/render/opengl/OpenGLRenderer.h index fc4f7de..d4daeab 100644 --- a/src/render/opengl/OpenGLRenderer.h +++ b/src/render/opengl/OpenGLRenderer.h @@ -37,6 +37,7 @@ private: OpenGLSkybox* skybox; OpenGLWater* water; + OpenGLTerrain* terrain; }; } diff --git a/src/render/opengl/OpenGLTerrain.cpp b/src/render/opengl/OpenGLTerrain.cpp new file mode 100644 index 0000000..5d083f0 --- /dev/null +++ b/src/render/opengl/OpenGLTerrain.cpp @@ -0,0 +1,144 @@ +#include "OpenGLTerrain.h" + +#include OPENGL_FUNCTIONS_INCLUDE +#include "OpenGLRenderer.h" +#include "OpenGLShaderProgram.h" +#include "ParallelPool.h" +#include "Thread.h" +#include "ExplorerChunkTerrain.h" +#include "WaterRenderer.h" +#include "CameraDefinition.h" +#include "Scenery.h" + +class ChunkMaintenanceThreads:public ParallelPool +{ +public: + ChunkMaintenanceThreads(OpenGLTerrain* terrain): + terrain(terrain) + { + } + + virtual void work() override + { + while (running) + { + terrain->performChunksMaintenance(); + Thread::timeSleepMs(10); + } + } + +private: + OpenGLTerrain* terrain; +}; + +OpenGLTerrain::OpenGLTerrain(OpenGLRenderer *renderer): + OpenGLPart(renderer) +{ + work = new ChunkMaintenanceThreads(this); +} + +OpenGLTerrain::~OpenGLTerrain() +{ + delete work; + + for (int i = 0; i < _chunks.count(); i++) + { + delete _chunks[i]; + } +} + +void OpenGLTerrain::initialize() +{ + // Prepare shader programs + program = createShader("terrain"); + program->addVertexSource("terrain"); + program->addFragmentSource("bruneton"); + program->addFragmentSource("tonemapping"); + program->addFragmentSource("terrain"); + + // Add terrain chunks + int chunks = 20; + double size = 400.0; + double chunksize = size / (double) chunks; + double start = -size / 2.0; + double water_height = renderer->getWaterRenderer()->getHeightInfo().base_height; + for (int i = 0; i < chunks; i++) + { + for (int j = 0; j < chunks; j++) + { + ExplorerChunkTerrain* chunk = new ExplorerChunkTerrain(renderer, start + chunksize * (double) i, start + chunksize * (double) j, chunksize, chunks, water_height); + _chunks.append(chunk); + _updateQueue.append(chunk); + } + } + + // Start chunks maintenance + work->start(); +} + +void OpenGLTerrain::update() +{ +} + +// TEMP +#include "GL/gl.h" +#include "GL/glu.h" + +void OpenGLTerrain::render() +{ + CameraDefinition* camera = renderer->getScenery()->getCamera(); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + CameraPerspective perspective = camera->getPerspective(); + gluPerspective(perspective.yfov * 180.0 / M_PI, perspective.xratio, perspective.znear, perspective.zfar); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + Vector3 camera_location = camera->getLocation(); + Vector3 camera_target = camera->getTarget(); + Vector3 camera_up = camera->getUpVector(); + gluLookAt(camera_location.x, camera_location.y, camera_location.z, camera_target.x, camera_target.y, camera_target.z, camera_up.x, camera_up.y, camera_up.z); + + // Render chunks + glEnable(GL_TEXTURE_2D); + for (int i = 0; i < _chunks.count(); i++) + { + glColor3f(1.0, 1.0, 1.0); + _chunks[i]->render(renderer->getOpenGlFunctions()); + } +} + +static bool _cmpChunks(const ExplorerChunkTerrain* c1, const ExplorerChunkTerrain* c2) +{ + return c1->priority > c2->priority; +} + +void OpenGLTerrain::performChunksMaintenance() +{ + CameraDefinition* camera = renderer->getScenery()->getCamera(); + ExplorerChunkTerrain* chunk; + + _lock_chunks.lock(); + if (_updateQueue.count() > 0) + { + chunk = _updateQueue.takeFirst(); + _lock_chunks.unlock(); + } + else + { + _lock_chunks.unlock(); + return; + } + + chunk->maintain(); + + _lock_chunks.lock(); + _updateQueue.append(chunk); + for (int i = 0; i < _chunks.count(); i++) + { + _chunks[i]->updatePriority(camera); + } + qSort(_updateQueue.begin(), _updateQueue.end(), _cmpChunks); + _lock_chunks.unlock(); +} diff --git a/src/render/opengl/OpenGLTerrain.h b/src/render/opengl/OpenGLTerrain.h new file mode 100644 index 0000000..d61c657 --- /dev/null +++ b/src/render/opengl/OpenGLTerrain.h @@ -0,0 +1,40 @@ +#ifndef OPENGLTERRAIN_H +#define OPENGLTERRAIN_H + +#include "opengl_global.h" + +#include "OpenGLPart.h" + +#include +#include +#include + +namespace paysages { +namespace opengl { + +class OPENGLSHARED_EXPORT OpenGLTerrain:public OpenGLPart +{ +public: + OpenGLTerrain(OpenGLRenderer* renderer); + virtual ~OpenGLTerrain(); + + virtual void initialize() override; + virtual void update() override; + virtual void render() override; + + void performChunksMaintenance(); + +private: + OpenGLShaderProgram* program; + + ParallelPool* work; + + QVector _chunks; + QList _updateQueue; + QMutex _lock_chunks; +}; + +} +} + +#endif // OPENGLTERRAIN_H diff --git a/src/render/opengl/WidgetExplorer.cpp b/src/render/opengl/WidgetExplorer.cpp index b1e00b0..00e191d 100644 --- a/src/render/opengl/WidgetExplorer.cpp +++ b/src/render/opengl/WidgetExplorer.cpp @@ -17,44 +17,6 @@ #include "Scenery.h" #include "LightingManager.h" -class ChunkMaintenanceThread : public QThread -{ -public: - - ChunkMaintenanceThread(WidgetExplorer* wanderer) - { - _wanderer = wanderer; - _running = true; - } - - void askStop() - { - _running = false; - } - - static inline void usleep(unsigned long us) - { - QThread::usleep(us); - } - -protected: - - void run() - { - while (_running) - { - _wanderer->performChunksMaintenance(); - QThread::usleep(10000); - } - } - -private: - bool _running; - WidgetExplorer* _wanderer; -}; - -static QVector _threads; - WidgetExplorer::WidgetExplorer(QWidget *parent, CameraDefinition* camera, Scenery* scenery) : QGLWidget(parent) { @@ -71,9 +33,6 @@ QGLWidget(parent) _renderer->getLightingManager()->setSpecularity(false); _renderer->disableClouds(); - _inited = false; - _updated = false; - _average_frame_time = 0.05; _quality = 3; _last_mouse_x = 0; @@ -84,103 +43,10 @@ QGLWidget(parent) WidgetExplorer::~WidgetExplorer() { - stopRendering(); - - for (int i = 0; i < _chunks.count(); i++) - { - delete _chunks[i]; - } delete _current_camera; delete _renderer; } -void WidgetExplorer::startRendering() -{ - // Add terrain - int chunks = 20; - double size = 400.0; - double chunksize = size / (double) chunks; - double start = -size / 2.0; - double water_height = _renderer->getWaterRenderer()->getHeightInfo().base_height; - for (int i = 0; i < chunks; i++) - { - for (int j = 0; j < chunks; j++) - { - ExplorerChunkTerrain* chunk = new ExplorerChunkTerrain(_renderer, start + chunksize * (double) i, start + chunksize * (double) j, chunksize, chunks, water_height); - _chunks.append(chunk); - _updateQueue.append(chunk); - } - } - - // Start rendering workers - int nbcore; - _alive = true; - - nbcore = QThread::idealThreadCount(); - if (nbcore < 1) - { - nbcore = 1; - } - - for (int i = 0; i < nbcore; i++) - { - _threads.append(new ChunkMaintenanceThread(this)); - } - for (int i = 0; i < _threads.count(); i++) - { - _threads[i]->start(); - } -} - -void WidgetExplorer::stopRendering() -{ - for (int i = 0; i < _threads.count(); i++) - { - _threads[i]->askStop(); - } - _alive = false; - for (int i = 0; i < _threads.count(); i++) - { - _threads[i]->wait(); - } -} - -bool _cmpChunks(const BaseExplorerChunk* c1, const BaseExplorerChunk* c2) -{ - return c1->priority > c2->priority; -} - -void WidgetExplorer::performChunksMaintenance() -{ - BaseExplorerChunk* chunk; - - _lock_chunks.lock(); - if (_updateQueue.count() > 0) - { - chunk = _updateQueue.takeFirst(); - _lock_chunks.unlock(); - } - else - { - _lock_chunks.unlock(); - return; - } - - if (chunk->maintain()) - { - if (!_alive) - { - return; - } - - _updated = true; - } - - _lock_chunks.lock(); - _updateQueue.append(chunk); - _lock_chunks.unlock(); -} - void WidgetExplorer::resetCamera() { _base_camera->copy(_current_camera); @@ -323,25 +189,7 @@ void WidgetExplorer::wheelEvent(QWheelEvent* event) void WidgetExplorer::timerEvent(QTimerEvent*) { - if (!_inited) - { - _inited = true; - startRendering(); - } - - if (_updated) - { - _updated = false; - updateGL(); - } - - for (int i = 0; i < _chunks.count(); i++) - { - _chunks[i]->updatePriority(_current_camera); - } - _lock_chunks.lock(); - qSort(_updateQueue.begin(), _updateQueue.end(), _cmpChunks); - _lock_chunks.unlock(); + updateGL(); } void WidgetExplorer::initializeGL() @@ -353,11 +201,6 @@ void WidgetExplorer::resizeGL(int w, int h) { _current_camera->setRenderSize(w, h); _renderer->resize(w, h); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - CameraPerspective perspective = _current_camera->getPerspective(); - gluPerspective(perspective.yfov * 180.0 / M_PI, perspective.xratio, perspective.znear, perspective.zfar); } void WidgetExplorer::paintGL() @@ -376,21 +219,6 @@ void WidgetExplorer::paintGL() // Background _renderer->paint(); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - Vector3 camera_location = _current_camera->getLocation(); - Vector3 camera_target = _current_camera->getTarget(); - Vector3 camera_up = _current_camera->getUpVector(); - gluLookAt(camera_location.x, camera_location.y, camera_location.z, camera_target.x, camera_target.y, camera_target.z, camera_up.x, camera_up.y, camera_up.z); - - // Render chunks - glEnable(GL_TEXTURE_2D); - for (int i = 0; i < _chunks.count(); i++) - { - glColor3f(1.0, 1.0, 1.0); - _chunks[i]->render(this); - } - frame_time = 0.001 * (double) start_time.msecsTo(QTime::currentTime()); _average_frame_time = _average_frame_time * 0.8 + frame_time * 0.2; @@ -406,13 +234,13 @@ void WidgetExplorer::paintGL() } // Messages - if (!_inited) + /*if (!_inited) { glColor3f(0.0, 0.0, 0.0); renderText(6, height() - 10, tr("Please wait while loading scene...")); glColor3f(1.0, 1.0, 1.0); renderText(5, height() - 9, tr("Please wait while loading scene...")); - } + }*/ while ((error_code = glGetError()) != GL_NO_ERROR) { diff --git a/src/render/opengl/WidgetExplorer.h b/src/render/opengl/WidgetExplorer.h index fb7994f..6da061f 100644 --- a/src/render/opengl/WidgetExplorer.h +++ b/src/render/opengl/WidgetExplorer.h @@ -5,8 +5,6 @@ #include -#include - namespace paysages { namespace opengl { @@ -17,8 +15,6 @@ public: WidgetExplorer(QWidget* parent, CameraDefinition* camera, Scenery* scenery); ~WidgetExplorer(); - void performChunksMaintenance(); - public slots: void resetCamera(); void validateCamera(); @@ -35,20 +31,10 @@ protected: void paintGL(); private: - void startRendering(); - void stopRendering(); - CameraDefinition* _current_camera; CameraDefinition* _base_camera; OpenGLRenderer* _renderer; - bool _inited; - bool _updated; - - QVector _chunks; - QList _updateQueue; - bool _alive; - QMutex _lock_chunks; double _average_frame_time; int _quality; diff --git a/src/render/opengl/opengl.pro b/src/render/opengl/opengl.pro index 17807eb..fce63a4 100644 --- a/src/render/opengl/opengl.pro +++ b/src/render/opengl/opengl.pro @@ -15,7 +15,6 @@ include(../../common.pri) SOURCES += \ OpenGLRenderer.cpp \ - BaseExplorerChunk.cpp \ ExplorerChunkTerrain.cpp \ WidgetExplorer.cpp \ OpenGLShaderProgram.cpp \ @@ -23,12 +22,12 @@ SOURCES += \ OpenGLSkybox.cpp \ OpenGLWater.cpp \ OpenGLSharedState.cpp \ - OpenGLVariable.cpp + OpenGLVariable.cpp \ + OpenGLTerrain.cpp HEADERS +=\ opengl_global.h \ OpenGLRenderer.h \ - BaseExplorerChunk.h \ ExplorerChunkTerrain.h \ WidgetExplorer.h \ OpenGLShaderProgram.h \ @@ -36,7 +35,8 @@ HEADERS +=\ OpenGLSkybox.h \ OpenGLWater.h \ OpenGLSharedState.h \ - OpenGLVariable.h + OpenGLVariable.h \ + OpenGLTerrain.h unix:!symbian { maemo5 { diff --git a/src/render/opengl/opengl_global.h b/src/render/opengl/opengl_global.h index d74c89d..9496f54 100644 --- a/src/render/opengl/opengl_global.h +++ b/src/render/opengl/opengl_global.h @@ -15,12 +15,13 @@ namespace paysages { namespace opengl { class WidgetExplorer; class OpenGLRenderer; - class BaseExplorerChunk; class OpenGLShaderProgram; class OpenGLSharedState; class OpenGLVariable; class OpenGLSkybox; class OpenGLWater; + class OpenGLTerrain; + class ExplorerChunkTerrain; } } using namespace paysages::opengl; diff --git a/src/system/ParallelPool.cpp b/src/system/ParallelPool.cpp new file mode 100644 index 0000000..941868e --- /dev/null +++ b/src/system/ParallelPool.cpp @@ -0,0 +1,55 @@ +#include "ParallelPool.h" + +#include "System.h" +#include "Thread.h" + +static void* _threadFunction(void* data) +{ + ParallelPool* pool = (ParallelPool*)data; + pool->work(); + return NULL; +} + +ParallelPool::ParallelPool() +{ + running = false; +} + +ParallelPool::~ParallelPool() +{ + if (running) + { + interrupt(); + } + for (auto thread : threads) + { + thread->join(); + delete thread; + } + threads.clear(); +} + +void ParallelPool::start(int thread_count) +{ + if (running) + { + qCritical("Starting an already started parallel pool !"); + return; + } + running = true; + if (thread_count < 0) + { + thread_count = System::getCoreCount(); + } + for (int i = 0; i < thread_count; i++) + { + Thread* thread = new Thread(_threadFunction); + thread->start(this); + threads.push_back(thread); + } +} + +void ParallelPool::interrupt() +{ + running = false; +} diff --git a/src/system/ParallelPool.h b/src/system/ParallelPool.h new file mode 100644 index 0000000..350d41e --- /dev/null +++ b/src/system/ParallelPool.h @@ -0,0 +1,43 @@ +#ifndef PARALLELPOOL_H +#define PARALLELPOOL_H + +#include "system_global.h" + +namespace paysages { +namespace system { + +/*! + * Pool to handle a group of threads doing the same task. + */ +class ParallelPool +{ +public: + ParallelPool(); + virtual ~ParallelPool(); + + /*! + * Start the effective work. + */ + void start(int thread_count=-1); + + /*! + * Method called from each thread to do actual work. + */ + virtual void work() = 0; + + /*! + * Method called once to interrupt all threads. + */ + virtual void interrupt(); + +protected: + bool running; + +private: + std::vector threads; +}; + +} +} + +#endif // PARALLELPOOL_H diff --git a/src/system/system.pro b/src/system/system.pro index 2aa7ac0..5de52fa 100644 --- a/src/system/system.pro +++ b/src/system/system.pro @@ -24,7 +24,8 @@ SOURCES += \ ParallelQueue.cpp \ CacheFile.cpp \ PictureWriter.cpp \ - Logs.cpp + Logs.cpp \ + ParallelPool.cpp HEADERS += \ system_global.h \ @@ -38,7 +39,8 @@ HEADERS += \ ParallelQueue.h \ CacheFile.h \ PictureWriter.h \ - Logs.h + Logs.h \ + ParallelPool.h unix:!symbian { maemo5 { diff --git a/src/system/system_global.h b/src/system/system_global.h index 5b5dfb2..b557937 100644 --- a/src/system/system_global.h +++ b/src/system/system_global.h @@ -15,6 +15,7 @@ namespace system { class PackStream; class ParallelQueue; class ParallelWork; + class ParallelPool; class Thread; class Mutex; }