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:
parent
661a8b1261
commit
edf0d58eae
5 changed files with 222 additions and 105 deletions
8
TODO
8
TODO
|
@ -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
104
gui_qt/wandererchunk.cpp
Normal 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
32
gui_qt/wandererchunk.h
Normal 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
|
|
@ -16,16 +16,36 @@ WidgetWanderer::WidgetWanderer(QWidget *parent, CameraDefinition* camera):
|
|||
_base_camera = camera;
|
||||
cameraCopyDefinition(camera, &_current_camera);
|
||||
|
||||
this->terrain = terrainCreateDefinition();
|
||||
sceneryGetTerrain(&terrain);
|
||||
|
||||
this->water = waterCreateDefinition();
|
||||
sceneryGetWater(&water);
|
||||
_water = waterCreateDefinition();
|
||||
sceneryGetWater(&_water);
|
||||
|
||||
average_frame_time = 0.05;
|
||||
quality = 3;
|
||||
last_mouse_x = 0;
|
||||
last_mouse_y = 0;
|
||||
_renderer = sceneryCreateStandardRenderer();
|
||||
|
||||
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++;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
@ -29,15 +33,18 @@ protected:
|
|||
private:
|
||||
CameraDefinition _current_camera;
|
||||
CameraDefinition* _base_camera;
|
||||
|
||||
TerrainDefinition terrain;
|
||||
WaterDefinition water;
|
||||
|
||||
double average_frame_time;
|
||||
int quality;
|
||||
Renderer _renderer;
|
||||
|
||||
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
|
||||
|
|
Loading…
Reference in a new issue