paysages : Explorer texturing (WIP).
git-svn-id: https://subversion.assembla.com/svn/thunderk/paysages@323 b1fd45b6-86a6-48da-8261-f70d1f35bdcc
This commit is contained in:
parent
891c8112ad
commit
b34a2cc59d
3 changed files with 115 additions and 97 deletions
|
@ -4,46 +4,51 @@
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
#include <QColor>
|
#include <QColor>
|
||||||
#include <QGLWidget>
|
#include <QGLWidget>
|
||||||
|
#include <math.h>
|
||||||
#include "../lib_paysages/color.h"
|
#include "../lib_paysages/color.h"
|
||||||
|
#include "../lib_paysages/euclid.h"
|
||||||
#include "../lib_paysages/tools.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;
|
_startx = x;
|
||||||
_startz = z;
|
_startz = z;
|
||||||
_dirty = 3;
|
_size = size;
|
||||||
_chunksize = size;
|
|
||||||
_nbsubchunks = 8;
|
_ideal_tessellation = 1;
|
||||||
_subchunksize = size / (double)_nbsubchunks;
|
_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 = new QImage(1, 1, QImage::Format_ARGB32);
|
||||||
_texture->fill(QColor(0, 200, 0));
|
|
||||||
_texture_id = 0;
|
_texture_id = 0;
|
||||||
_need_texture_upload = true;
|
_texture_changed = false;
|
||||||
_heightmap = new double[(_nbsubchunks + 1) * (_nbsubchunks + 1)];
|
|
||||||
for (int j = 0; j <= _nbsubchunks; j++)
|
maintain(VECTOR_ZERO);
|
||||||
{
|
|
||||||
for (int i = 0; i <= _nbsubchunks; i++)
|
|
||||||
{
|
|
||||||
_heightmap[j * (_nbsubchunks + 1) + i] = -100.0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WandererChunk::~WandererChunk()
|
WandererChunk::~WandererChunk()
|
||||||
{
|
{
|
||||||
_lock.lock();
|
_lock_data.lock();
|
||||||
delete _texture;
|
delete _texture;
|
||||||
delete [] _heightmap;
|
delete [] _tessellation;
|
||||||
_lock.unlock();
|
_lock_data.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WandererChunk::render(QGLWidget* widget)
|
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)
|
if (_texture_id)
|
||||||
{
|
{
|
||||||
widget->deleteTexture(_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_S, GL_CLAMP_TO_EDGE);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, 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;
|
int tessellation_size = _tessellation_current_size;
|
||||||
for (int j = 0; j < _nbsubchunks; j++)
|
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);
|
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);
|
glTexCoord2d(tsize * (double)i, 1.0 - tsize * (double)j);
|
||||||
glVertex3d(_startx + _subchunksize * (double)i, _heightmap[j * (_nbsubchunks + 1) + i], _startz + _subchunksize * (double)j);
|
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 + 1));
|
glTexCoord2d(tsize * (double)i, 1.0 - tsize * (double)(j + tessellation_inc));
|
||||||
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_inc) * (_tessellation_max_size + 1) + i], _startz + _tessellation_step * (double)(j + tessellation_inc));
|
||||||
}
|
}
|
||||||
glEnd();
|
glEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
_lock.unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WandererChunk::maintain(Renderer* renderer)
|
bool WandererChunk::maintain(Vector3 camera_location)
|
||||||
{
|
{
|
||||||
_lock_dirty.lock();
|
bool result;
|
||||||
if (_dirty)
|
|
||||||
|
if (_tessellation_current_size < _tessellation_max_size || _texture_current_size < _texture_max_size)
|
||||||
{
|
{
|
||||||
int dirty = _dirty--;
|
// Improve heightmap resolution
|
||||||
_lock_dirty.unlock();
|
if (_tessellation_current_size < _tessellation_max_size)
|
||||||
|
|
||||||
// Compute heightmap
|
|
||||||
if (dirty == 3)
|
|
||||||
{
|
{
|
||||||
double* new_heightmap = new double[(_nbsubchunks + 1) * (_nbsubchunks + 1)];
|
int new_tessellation_size = _tessellation_current_size ? _tessellation_current_size * 4 : 2;
|
||||||
for (int j = 0; j <= _nbsubchunks; j++)
|
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;
|
_lock_data.lock();
|
||||||
_heightmap = new_heightmap;
|
_tessellation_current_size = new_tessellation_size;
|
||||||
_lock.unlock();
|
_lock_data.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute low-res texture
|
// Improve texture resolution
|
||||||
if (dirty == 2)
|
if (_texture_current_size < _texture_max_size)
|
||||||
{
|
{
|
||||||
int texture_size = 4;
|
int new_texture_size = _texture_current_size ? _texture_current_size * 2 : 1;
|
||||||
double step_size = _chunksize / (double)(texture_size - 1);
|
double step_size = _texture_current_size ? _size / (double)(new_texture_size - 1) : 0.1;
|
||||||
QImage* new_image = new QImage(texture_size, texture_size, QImage::Format_ARGB32);
|
QImage* new_image = new QImage(new_texture_size, new_texture_size, QImage::Format_ARGB32);
|
||||||
for (int j = 0; j < texture_size; j++)
|
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};
|
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));
|
new_image->setPixel(i, j, colorTo32BitRGBA(&color));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_lock.lock();
|
|
||||||
|
_lock_data.lock();
|
||||||
delete _texture;
|
delete _texture;
|
||||||
_texture = new_image;
|
_texture = new_image;
|
||||||
_need_texture_upload = true;
|
_texture_current_size = new_texture_size;
|
||||||
_lock.unlock();
|
_texture_changed = true;
|
||||||
|
_lock_data.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute texture
|
result = true;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_lock_dirty.unlock();
|
result = false;
|
||||||
|
|
||||||
return 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 WandererChunk::getCenter()
|
||||||
{
|
{
|
||||||
Vector3 result;
|
Vector3 result;
|
||||||
|
|
||||||
result.x = _startz + _chunksize / 2.0;
|
result.x = _startx + _size / 2.0;
|
||||||
result.y = 0.0;
|
result.y = 0.0;
|
||||||
result.z = _startz + _chunksize / 2.0;
|
result.z = _startz + _size / 2.0;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,27 +9,36 @@
|
||||||
class WandererChunk
|
class WandererChunk
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
WandererChunk(double x, double z, double size);
|
WandererChunk(Renderer* renderer, double x, double z, double size);
|
||||||
~WandererChunk();
|
~WandererChunk();
|
||||||
|
|
||||||
bool maintain(Renderer* renderer);
|
bool maintain(Vector3 camera_location);
|
||||||
void render(QGLWidget* widget);
|
void render(QGLWidget* widget);
|
||||||
|
|
||||||
Vector3 getCenter();
|
Vector3 getCenter();
|
||||||
|
|
||||||
|
double _ideal_priority;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QMutex _lock;
|
QMutex _lock_data;
|
||||||
QMutex _lock_dirty;
|
Renderer* _renderer;
|
||||||
|
|
||||||
double _startx;
|
double _startx;
|
||||||
double _startz;
|
double _startz;
|
||||||
int _dirty;
|
double _size;
|
||||||
double _chunksize;
|
|
||||||
double _subchunksize;
|
int _ideal_tessellation;
|
||||||
int _nbsubchunks;
|
|
||||||
|
double* _tessellation;
|
||||||
|
int _tessellation_max_size;
|
||||||
|
int _tessellation_current_size;
|
||||||
|
double _tessellation_step;
|
||||||
|
|
||||||
QImage* _texture;
|
QImage* _texture;
|
||||||
GLuint _texture_id;
|
GLuint _texture_id;
|
||||||
bool _need_texture_upload;
|
bool _texture_changed;
|
||||||
double* _heightmap;
|
int _texture_max_size;
|
||||||
|
int _texture_current_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -70,7 +70,7 @@ WidgetWanderer::WidgetWanderer(QWidget *parent, CameraDefinition* camera):
|
||||||
{
|
{
|
||||||
for (int j = 0; j < chunks; j++)
|
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);
|
_chunks.append(chunk);
|
||||||
_updateQueue.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()
|
void WidgetWanderer::performChunksMaintenance()
|
||||||
{
|
{
|
||||||
WandererChunk* chunk;
|
WandererChunk* chunk;
|
||||||
|
@ -147,7 +152,7 @@ void WidgetWanderer::performChunksMaintenance()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chunk->maintain(&_renderer))
|
if (chunk->maintain(_current_camera.location))
|
||||||
{
|
{
|
||||||
if (!_alive)
|
if (!_alive)
|
||||||
{
|
{
|
||||||
|
@ -159,6 +164,7 @@ void WidgetWanderer::performChunksMaintenance()
|
||||||
|
|
||||||
_lock_chunks.lock();
|
_lock_chunks.lock();
|
||||||
_updateQueue.append(chunk);
|
_updateQueue.append(chunk);
|
||||||
|
qSort(_updateQueue.begin(), _updateQueue.end(), _cmpChunks);
|
||||||
_lock_chunks.unlock();
|
_lock_chunks.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue