diff --git a/gui_qt/wandererchunk.cpp b/gui_qt/wandererchunk.cpp index fa1ff8f..395df00 100644 --- a/gui_qt/wandererchunk.cpp +++ b/gui_qt/wandererchunk.cpp @@ -4,46 +4,51 @@ #include #include #include +#include #include "../lib_paysages/color.h" +#include "../lib_paysages/euclid.h" #include "../lib_paysages/tools.h" -WandererChunk::WandererChunk(double x, double z, double size) +WandererChunk::WandererChunk(Renderer* renderer, double x, double z, double size) { + _renderer = renderer; + _startx = x; _startz = z; - _dirty = 3; - _chunksize = size; - _nbsubchunks = 8; - _subchunksize = size / (double)_nbsubchunks; + _size = size; + + _ideal_tessellation = 1; + _ideal_priority = 0.0; + + _tessellation_max_size = 32; + _tessellation = new double[(_tessellation_max_size + 1) * (_tessellation_max_size + 1)]; + _tessellation_current_size = 0; + _tessellation_step = _size / (double)_tessellation_max_size; + + _texture_max_size = 32; + _texture_current_size = 0; _texture = new QImage(1, 1, QImage::Format_ARGB32); - _texture->fill(QColor(0, 200, 0)); _texture_id = 0; - _need_texture_upload = true; - _heightmap = new double[(_nbsubchunks + 1) * (_nbsubchunks + 1)]; - for (int j = 0; j <= _nbsubchunks; j++) - { - for (int i = 0; i <= _nbsubchunks; i++) - { - _heightmap[j * (_nbsubchunks + 1) + i] = -100.0; - } - } + _texture_changed = false; + + maintain(VECTOR_ZERO); } WandererChunk::~WandererChunk() { - _lock.lock(); + _lock_data.lock(); delete _texture; - delete [] _heightmap; - _lock.unlock(); + delete [] _tessellation; + _lock_data.unlock(); } void WandererChunk::render(QGLWidget* widget) { - _lock.lock(); + _lock_data.lock(); - if (_need_texture_upload) + if (_texture_changed) { - _need_texture_upload = false; + _texture_changed = false; if (_texture_id) { widget->deleteTexture(_texture_id); @@ -52,111 +57,109 @@ void WandererChunk::render(QGLWidget* widget) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } - glBindTexture(GL_TEXTURE_2D, _texture_id); + else + { + glBindTexture(GL_TEXTURE_2D, _texture_id); + } - double tsize = 1.0 / (double)_nbsubchunks; - for (int j = 0; j < _nbsubchunks; j++) + int tessellation_size = _tessellation_current_size; + int tessellation_inc = _tessellation_max_size / (double)tessellation_size; + double tsize = 1.0 / (double)_tessellation_max_size; + + _lock_data.unlock(); + + for (int j = 0; j < _tessellation_max_size; j += tessellation_inc) { glBegin(GL_QUAD_STRIP); - for (int i = 0; i <= _nbsubchunks; i++) + for (int i = 0; i <= _tessellation_max_size; i += tessellation_inc) { glTexCoord2d(tsize * (double)i, 1.0 - tsize * (double)j); - glVertex3d(_startx + _subchunksize * (double)i, _heightmap[j * (_nbsubchunks + 1) + i], _startz + _subchunksize * (double)j); - glTexCoord2d(tsize * (double)i, 1.0 - tsize * (double)(j + 1)); - glVertex3d(_startx + _subchunksize * (double)i, _heightmap[(j + 1) * (_nbsubchunks + 1) + i], _startz + _subchunksize * (double)(j + 1)); + glVertex3d(_startx + _tessellation_step * (double)i, _tessellation[j * (_tessellation_max_size + 1) + i], _startz + _tessellation_step * (double)j); + glTexCoord2d(tsize * (double)i, 1.0 - 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)); } glEnd(); } - - _lock.unlock(); } -bool WandererChunk::maintain(Renderer* renderer) +bool WandererChunk::maintain(Vector3 camera_location) { - _lock_dirty.lock(); - if (_dirty) + bool result; + + if (_tessellation_current_size < _tessellation_max_size || _texture_current_size < _texture_max_size) { - int dirty = _dirty--; - _lock_dirty.unlock(); - - // Compute heightmap - if (dirty == 3) + // Improve heightmap resolution + if (_tessellation_current_size < _tessellation_max_size) { - double* new_heightmap = new double[(_nbsubchunks + 1) * (_nbsubchunks + 1)]; - for (int j = 0; j <= _nbsubchunks; j++) + int new_tessellation_size = _tessellation_current_size ? _tessellation_current_size * 4 : 2; + int old_tessellation_inc = _tessellation_current_size ? _tessellation_max_size / _tessellation_current_size : 1; + int new_tessellation_inc = _tessellation_max_size / new_tessellation_size; + for (int j = 0; j <= _tessellation_max_size; j += new_tessellation_inc) { - for (int i = 0; i <= _nbsubchunks; i++) + for (int i = 0; i <= _tessellation_max_size; i += new_tessellation_inc) { - new_heightmap[j * (_nbsubchunks + 1) + i] = renderer->getTerrainHeight(renderer, _startx + _subchunksize * (double)i, _startz + _subchunksize * (double)j); + if (_tessellation_current_size == 0 || i % old_tessellation_inc != 0 || j % old_tessellation_inc != 0) + { + double height = _renderer->getTerrainHeight(_renderer, _startx + _tessellation_step * (double)i, _startz + _tessellation_step * (double)j); + _tessellation[j * (_tessellation_max_size + 1) + i] = height; + } } } - _lock.lock(); - delete [] _heightmap; - _heightmap = new_heightmap; - _lock.unlock(); + + _lock_data.lock(); + _tessellation_current_size = new_tessellation_size; + _lock_data.unlock(); } - // Compute low-res texture - if (dirty == 2) + // Improve texture resolution + if (_texture_current_size < _texture_max_size) { - int texture_size = 4; - double step_size = _chunksize / (double)(texture_size - 1); - QImage* new_image = new QImage(texture_size, texture_size, QImage::Format_ARGB32); - for (int j = 0; j < texture_size; j++) + int new_texture_size = _texture_current_size ? _texture_current_size * 2 : 1; + double step_size = _texture_current_size ? _size / (double)(new_texture_size - 1) : 0.1; + QImage* new_image = new QImage(new_texture_size, new_texture_size, QImage::Format_ARGB32); + for (int j = 0; j < new_texture_size; j++) { - for (int i = 0; i < texture_size; i++) + for (int i = 0; i < new_texture_size; i++) { Vector3 location = {_startx + step_size * (double)i, 0.0, _startz + step_size * (double)j}; - Color color = renderer->applyTextures(renderer, location, step_size); + Color color = _renderer->applyTextures(_renderer, location, step_size); new_image->setPixel(i, j, colorTo32BitRGBA(&color)); } } - _lock.lock(); + + _lock_data.lock(); delete _texture; _texture = new_image; - _need_texture_upload = true; - _lock.unlock(); + _texture_current_size = new_texture_size; + _texture_changed = true; + _lock_data.unlock(); } - // Compute texture - if (dirty == 1) - { - int texture_size = 32; - double step_size = _chunksize / (double)(texture_size - 1); - QImage* new_image = new QImage(texture_size, texture_size, QImage::Format_ARGB32); - for (int j = 0; j < texture_size; j++) - { - for (int i = 0; i < texture_size; i++) - { - Vector3 location = {_startx + step_size * (double)i, 0.0, _startz + step_size * (double)j}; - Color color = renderer->applyTextures(renderer, location, step_size); - new_image->setPixel(i, j, colorTo32BitRGBA(&color)); - } - } - _lock.lock(); - delete _texture; - _texture = new_image; - _need_texture_upload = true; - _lock.unlock(); - } - - return true; + result = true; } else { - _lock_dirty.unlock(); - - return false; + result = false; } + + // Compute new priority + _lock_data.lock(); + double distance = v3Norm(v3Sub(camera_location, getCenter())); + distance = distance < 0.1 ? 0.1 : distance; + _ideal_tessellation = (int)ceil(120.0 - distance / 3.0); + _ideal_priority = _ideal_tessellation - _texture_current_size; + _lock_data.unlock(); + + return result; } Vector3 WandererChunk::getCenter() { Vector3 result; - result.x = _startz + _chunksize / 2.0; + result.x = _startx + _size / 2.0; result.y = 0.0; - result.z = _startz + _chunksize / 2.0; + result.z = _startz + _size / 2.0; return result; } diff --git a/gui_qt/wandererchunk.h b/gui_qt/wandererchunk.h index 04efa5f..7b88348 100644 --- a/gui_qt/wandererchunk.h +++ b/gui_qt/wandererchunk.h @@ -9,27 +9,36 @@ class WandererChunk { public: - WandererChunk(double x, double z, double size); + WandererChunk(Renderer* renderer, double x, double z, double size); ~WandererChunk(); - bool maintain(Renderer* renderer); + bool maintain(Vector3 camera_location); void render(QGLWidget* widget); Vector3 getCenter(); + double _ideal_priority; + private: - QMutex _lock; - QMutex _lock_dirty; + QMutex _lock_data; + Renderer* _renderer; + double _startx; double _startz; - int _dirty; - double _chunksize; - double _subchunksize; - int _nbsubchunks; + double _size; + + int _ideal_tessellation; + + double* _tessellation; + int _tessellation_max_size; + int _tessellation_current_size; + double _tessellation_step; + QImage* _texture; GLuint _texture_id; - bool _need_texture_upload; - double* _heightmap; + bool _texture_changed; + int _texture_max_size; + int _texture_current_size; }; #endif diff --git a/gui_qt/widgetwanderer.cpp b/gui_qt/widgetwanderer.cpp index 79723a8..4b80a31 100644 --- a/gui_qt/widgetwanderer.cpp +++ b/gui_qt/widgetwanderer.cpp @@ -70,7 +70,7 @@ WidgetWanderer::WidgetWanderer(QWidget *parent, CameraDefinition* camera): { for (int j = 0; j < chunks; j++) { - WandererChunk* chunk = new WandererChunk(start + chunksize * (double)i, start + chunksize * (double)j, chunksize); + WandererChunk* chunk = new WandererChunk(&_renderer, start + chunksize * (double)i, start + chunksize * (double)j, chunksize); _chunks.append(chunk); _updateQueue.append(chunk); } @@ -131,6 +131,11 @@ void WidgetWanderer::stopThreads() } } +bool _cmpChunks(const WandererChunk* c1, const WandererChunk* c2) +{ + return c1->_ideal_priority > c2->_ideal_priority; +} + void WidgetWanderer::performChunksMaintenance() { WandererChunk* chunk; @@ -147,7 +152,7 @@ void WidgetWanderer::performChunksMaintenance() return; } - if (chunk->maintain(&_renderer)) + if (chunk->maintain(_current_camera.location)) { if (!_alive) { @@ -159,6 +164,7 @@ void WidgetWanderer::performChunksMaintenance() _lock_chunks.lock(); _updateQueue.append(chunk); + qSort(_updateQueue.begin(), _updateQueue.end(), _cmpChunks); _lock_chunks.unlock(); }