paysages : Explorer texturing (WIP).

git-svn-id: https://subversion.assembla.com/svn/thunderk/paysages@321 b1fd45b6-86a6-48da-8261-f70d1f35bdcc
This commit is contained in:
Michaël Lemaire 2012-05-08 12:07:15 +00:00 committed by ThunderK
parent 661a8b1261
commit edf0d58eae
5 changed files with 222 additions and 105 deletions

8
TODO
View file

@ -11,11 +11,17 @@ Technology Preview 2 :
- Add a zone editor dialog for localized textures.
- Add a terrain modifier dialog with zones.
- Add a noise filler (and maybe noise intervals ?).
- Fix the sun appearance.
- Fix the distorted sun appearance.
- Improve curve editor.
=> Add curve modes
=> Improve curve rendering
=> Add axis labels
- Improve 3d explorer
=> Store computed vertices in memory, using chunks
=> Compute the ground texture by chunk
=> Don't display the water if it's below all ground
=> Add the sun position
=> Try to overcome the near frustum cutting
- Water and terrain LOD moves with the camera, fix it like in the wanderer.
- Pause previews drawing of main window when a dialog is opened.
- Interrupt preview chunk renderings that will be discarded at commit, or that are no more visible.

104
gui_qt/wandererchunk.cpp Normal file
View file

@ -0,0 +1,104 @@
#include "wandererchunk.h"
#include <math.h>
#include <stdlib.h>
#include <QMutex>
#include <QImage>
#include <QColor>
#include <QGLWidget>
#include "../lib_paysages/color.h"
#include "../lib_paysages/tools.h"
WandererChunk::WandererChunk(double x, double z, double size)
{
_startx = x;
_startz = z;
_dirty = true;
_chunksize = size;
_nbsubchunks = 4;
_subchunksize = size / (double)_nbsubchunks;
_texture = new QImage(4, 4, QImage::Format_ARGB32);
_texture->fill(QColor(0, 200, 0));
_texture_id = 0;
_need_texture_upload = true;
_heightmap = (double*)malloc(sizeof(double) * (_nbsubchunks + 1) * (_nbsubchunks + 1));
//_heightmap[0] = _heightmap[1] = _heightmap[2] = _heightmap[3] = toolsRandom();
}
WandererChunk::~WandererChunk()
{
_lock.lock();
delete _texture;
free(_heightmap);
_lock.unlock();
}
void WandererChunk::render(QGLWidget* widget)
{
_lock.lock();
if (_need_texture_upload)
{
_need_texture_upload = false;
if (_texture_id)
{
widget->deleteTexture(_texture_id);
}
_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);
}
glBindTexture(GL_TEXTURE_2D, _texture_id);
double tsize = 1.0 / (double)_nbsubchunks;
for (int j = 0; j < _nbsubchunks; j++)
{
glBegin(GL_QUAD_STRIP);
for (int i = 0; i <= _nbsubchunks; i++)
{
glColor3f(1.0, 1.0, 1.0);
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));
}
glEnd();
}
_lock.unlock();
}
void WandererChunk::maintain(Renderer* renderer)
{
_lock.lock();
if (_dirty)
{
_dirty = false;
// Compute heightmap
for (int j = 0; j <= _nbsubchunks; j++)
{
for (int i = 0; i <= _nbsubchunks; i++)
{
_heightmap[j * (_nbsubchunks + 1) + i] = renderer->getTerrainHeight(renderer, _startx + _subchunksize * (double)i, _startz + _subchunksize * (double)j);
}
}
// Compute texture
int texture_size = 4;
double step_size = _chunksize / (double)(texture_size - 1);
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);
_texture->setPixel(i, j, colorTo32BitRGBA(&color));
}
}
_need_texture_upload = true;
}
_lock.unlock();
}

32
gui_qt/wandererchunk.h Normal file
View file

@ -0,0 +1,32 @@
#ifndef _PAYSAGES_QT_WANDERERCHUNK_H_
#define _PAYSAGES_QT_WANDERERCHUNK_H_
#include <QMutex>
#include <QImage>
#include <QGLWidget>
#include "../lib_paysages/renderer.h"
class WandererChunk
{
public:
WandererChunk(double x, double z, double size);
~WandererChunk();
void maintain(Renderer* renderer);
void render(QGLWidget* widget);
private:
QMutex _lock;
double _startx;
double _startz;
bool _dirty;
double _chunksize;
double _subchunksize;
int _nbsubchunks;
QImage* _texture;
GLuint _texture_id;
bool _need_texture_upload;
double* _heightmap;
};
#endif

View file

@ -16,16 +16,36 @@ WidgetWanderer::WidgetWanderer(QWidget *parent, CameraDefinition* camera):
_base_camera = camera;
cameraCopyDefinition(camera, &_current_camera);
this->terrain = terrainCreateDefinition();
sceneryGetTerrain(&terrain);
_water = waterCreateDefinition();
sceneryGetWater(&_water);
this->water = waterCreateDefinition();
sceneryGetWater(&water);
_renderer = sceneryCreateStandardRenderer();
average_frame_time = 0.05;
quality = 3;
last_mouse_x = 0;
last_mouse_y = 0;
int chunks = 16;
double size = 30.0;
double chunksize = size / (double)chunks;
double start = -size / 2.0;
for (int i = 0; i < chunks; i++)
{
for (int j = 0; j < chunks; j++)
{
_chunks.append(new WandererChunk(start + chunksize * (double)i, start + chunksize * (double)j, chunksize));
}
}
_average_frame_time = 0.05;
_quality = 3;
_last_mouse_x = 0;
_last_mouse_y = 0;
}
WidgetWanderer::~WidgetWanderer()
{
for (int i = 0; i < _chunks.count(); i++)
{
delete _chunks[i];
}
waterDeleteDefinition(&_water);
}
void WidgetWanderer::resetCamera()
@ -95,8 +115,8 @@ void WidgetWanderer::keyPressEvent(QKeyEvent* event)
void WidgetWanderer::mousePressEvent(QMouseEvent* event)
{
last_mouse_x = event->x();
last_mouse_y = event->y();
_last_mouse_x = event->x();
_last_mouse_y = event->y();
event->ignore();
}
@ -121,15 +141,15 @@ void WidgetWanderer::mouseMoveEvent(QMouseEvent* event)
if (event->buttons() & Qt::LeftButton)
{
cameraRotateYaw(&_current_camera, (double)(event->x() - last_mouse_x) * factor * 0.1);
cameraRotatePitch(&_current_camera, (double)(event->y() - last_mouse_y) * factor * 0.1);
cameraRotateYaw(&_current_camera, (double)(event->x() - _last_mouse_x) * factor * 0.1);
cameraRotatePitch(&_current_camera, (double)(event->y() - _last_mouse_y) * factor * 0.1);
updateGL();
event->accept();
}
else if (event->buttons() & Qt::RightButton)
{
cameraStrafeRight(&_current_camera, (double)(last_mouse_x - event->x()) * factor);
cameraStrafeUp(&_current_camera, (double)(event->y() - last_mouse_y) * factor);
cameraStrafeRight(&_current_camera, (double)(_last_mouse_x - event->x()) * factor);
cameraStrafeUp(&_current_camera, (double)(event->y() - _last_mouse_y) * factor);
updateGL();
event->accept();
}
@ -138,8 +158,8 @@ void WidgetWanderer::mouseMoveEvent(QMouseEvent* event)
event->ignore();
}
last_mouse_x = event->x();
last_mouse_y = event->y();
_last_mouse_x = event->x();
_last_mouse_y = event->y();
}
void WidgetWanderer::wheelEvent(QWheelEvent* event)
@ -174,7 +194,6 @@ void WidgetWanderer::initializeGL()
glClearColor(0.4, 0.7, 0.8, 0.0);
glDisable(GL_LIGHTING);
glDisable(GL_TEXTURE);
glFrontFace(GL_CCW);
glCullFace(GL_BACK);
@ -187,6 +206,10 @@ void WidgetWanderer::initializeGL()
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glEnable(GL_LINE_SMOOTH);
glLineWidth(1.0);
glDisable(GL_FOG);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
void WidgetWanderer::resizeGL(int w, int h)
@ -198,74 +221,8 @@ void WidgetWanderer::resizeGL(int w, int h)
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(_current_camera.yfov * 180.0 / M_PI, _current_camera.xratio, _current_camera.znear, _current_camera.zfar);
}
static inline void _renderTerrainQuad(TerrainDefinition* terrain, double x, double z, double size)
{
double y1, y2, y3, y4;
y1 = terrainGetHeight(terrain, x, z);
y2 = terrainGetHeight(terrain, x, z + size);
y3 = terrainGetHeight(terrain, x + size, z + size);
y4 = terrainGetHeight(terrain, x + size, z);
glColor3f(0.0, 1.0, 0.0);
glBegin(GL_LINE_LOOP);
glVertex3f(x, y1, z);
glVertex3f(x, y2, z + size);
glVertex3f(x + size, y3, z + size);
glVertex3f(x + size, y4, z);
glEnd();
glColor3f(0.0, 0.5, 0.0);
glBegin(GL_QUADS);
glVertex3f(x, y1, z);
glVertex3f(x, y2, z + size);
glVertex3f(x + size, y3, z + size);
glVertex3f(x + size, y4, z);
glEnd();
}
static void _renderTerrain(TerrainDefinition* terrain, CameraDefinition* camera, int quality)
{
int chunk_factor, chunk_count, i;
double min_chunk_size, visible_chunk_size;
double radius_int, radius_ext, chunk_size;
double cx, cz;
min_chunk_size = 1.0 / (double)quality;
visible_chunk_size = 1.0 / (double)quality;
cx = camera->location.x - fmod(camera->location.x, min_chunk_size * 16.0);
cz = camera->location.z - fmod(camera->location.z, min_chunk_size * 16.0);
chunk_factor = 1;
chunk_count = 2;
radius_int = 0.0;
radius_ext = min_chunk_size;
chunk_size = min_chunk_size;
while (radius_ext < 100.0)
{
for (i = 0; i < chunk_count - 1; i++)
{
_renderTerrainQuad(terrain, cx - radius_ext + chunk_size * i, cz - radius_ext, chunk_size);
_renderTerrainQuad(terrain, cx + radius_int, cz - radius_ext + chunk_size * i, chunk_size);
_renderTerrainQuad(terrain, cx + radius_int - chunk_size * i, cz + radius_int, chunk_size);
_renderTerrainQuad(terrain, cx - radius_ext, cz + radius_int - chunk_size * i, chunk_size);
}
if (chunk_count % 32 == 0 && chunk_size / radius_int < visible_chunk_size)
{
chunk_count /= 2;
chunk_factor *= 2;
/* TODO Fill in gaps with triangles */
}
chunk_count += 2;
chunk_size = min_chunk_size * chunk_factor;
radius_int = radius_ext;
radius_ext += chunk_size;
}
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
void WidgetWanderer::paintGL()
@ -282,29 +239,40 @@ void WidgetWanderer::paintGL()
gluLookAt(_current_camera.location.x, _current_camera.location.y, _current_camera.location.z, _current_camera.target.x, _current_camera.target.y, _current_camera.target.z, _current_camera.up.x, _current_camera.up.y, _current_camera.up.z);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
// Render water
glDisable(GL_TEXTURE);
glDisable(GL_TEXTURE_2D);
glColor3f(0.0, 0.0, 1.0);
glBegin(GL_QUADS);
glVertex3f(_current_camera.location.x - 500.0, water.height, _current_camera.location.z - 500.0);
glVertex3f(_current_camera.location.x - 500.0, water.height, _current_camera.location.z + 500.0);
glVertex3f(_current_camera.location.x + 500.0, water.height, _current_camera.location.z + 500.0);
glVertex3f(_current_camera.location.x + 500.0, water.height, _current_camera.location.z - 500.0);
glVertex3f(_current_camera.location.x - 500.0, _water.height, _current_camera.location.z - 500.0);
glVertex3f(_current_camera.location.x - 500.0, _water.height, _current_camera.location.z + 500.0);
glVertex3f(_current_camera.location.x + 500.0, _water.height, _current_camera.location.z + 500.0);
glVertex3f(_current_camera.location.x + 500.0, _water.height, _current_camera.location.z - 500.0);
glEnd();
_renderTerrain(&terrain, &_current_camera, quality);
// Render terrain chunks
glEnable(GL_TEXTURE);
glEnable(GL_TEXTURE_2D);
for (int i = 0; i < _chunks.count(); i++)
{
_chunks[i]->maintain(&_renderer);
_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;
_average_frame_time = _average_frame_time * 0.8 + frame_time * 0.2;
//printf("%d %f\n", quality, average_frame_time);
if (average_frame_time > 0.1 && quality > 1)
if (_average_frame_time > 0.1 && _quality > 1)
{
quality--;
_quality--;
}
if (average_frame_time < 0.04 && quality < 10)
if (_average_frame_time < 0.04 && _quality < 10)
{
quality++;
_quality++;
}
}

View file

@ -2,15 +2,19 @@
#define _PAYSAGES_QT_WIDGETWANDERER_H_
#include <QGLWidget>
#include "wandererchunk.h"
#include "../lib_paysages/atmosphere.h"
#include "../lib_paysages/camera.h"
#include "../lib_paysages/terrain.h"
#include "../lib_paysages/water.h"
#include "../lib_paysages/renderer.h"
class WidgetWanderer : public QGLWidget
{
Q_OBJECT
public:
WidgetWanderer(QWidget* parent, CameraDefinition* camera);
~WidgetWanderer();
public slots:
void resetCamera();
@ -30,14 +34,17 @@ private:
CameraDefinition _current_camera;
CameraDefinition* _base_camera;
TerrainDefinition terrain;
WaterDefinition water;
Renderer _renderer;
double average_frame_time;
int quality;
QVector<WandererChunk*> _chunks;
int last_mouse_x;
int last_mouse_y;
WaterDefinition _water;
double _average_frame_time;
int _quality;
int _last_mouse_x;
int _last_mouse_y;
};
#endif