2013-11-05 10:45:26 +00:00
|
|
|
#include "ExplorerChunkTerrain.h"
|
2012-06-08 12:28:46 +00:00
|
|
|
|
2013-12-23 13:09:52 +00:00
|
|
|
#include OPENGL_FUNCTIONS_INCLUDE
|
2013-11-05 10:45:26 +00:00
|
|
|
#include <cmath>
|
2013-12-23 13:09:52 +00:00
|
|
|
#include <QImage>
|
|
|
|
#include "ColorProfile.h"
|
2013-11-14 17:47:03 +00:00
|
|
|
#include "CameraDefinition.h"
|
2013-12-23 13:09:52 +00:00
|
|
|
#include "OpenGLRenderer.h"
|
2013-12-09 10:59:57 +00:00
|
|
|
#include "TerrainRenderer.h"
|
2013-12-23 16:24:05 +00:00
|
|
|
#include "VertexArray.h"
|
2012-06-08 12:28:46 +00:00
|
|
|
|
2013-12-23 13:09:52 +00:00
|
|
|
ExplorerChunkTerrain::ExplorerChunkTerrain(OpenGLRenderer* renderer, double x, double z, double size, int nbchunks, double water_height):
|
|
|
|
_renderer(renderer)
|
2012-06-08 12:28:46 +00:00
|
|
|
{
|
2013-12-24 10:44:39 +00:00
|
|
|
_color_profile = new ColorProfile(ColorProfile::TONE_MAPPING_REIHNARD, 2.0);
|
2013-12-23 13:09:52 +00:00
|
|
|
|
|
|
|
priority = 0.0;
|
|
|
|
_reset_needed = false;
|
|
|
|
|
2013-12-24 10:44:39 +00:00
|
|
|
_texture = new QImage(1, 1, QImage::Format_RGBA8888);
|
|
|
|
texture_id = 0;
|
2013-12-23 13:09:52 +00:00
|
|
|
_texture_changed = false;
|
|
|
|
_texture_current_size = 0;
|
|
|
|
_texture_max_size = 0;
|
|
|
|
|
2012-06-08 12:28:46 +00:00
|
|
|
_startx = x;
|
|
|
|
_startz = z;
|
|
|
|
_size = size;
|
2013-04-27 19:41:57 +00:00
|
|
|
_overall_step = size * (double) nbchunks;
|
2012-12-09 17:49:28 +00:00
|
|
|
|
2013-02-05 21:25:30 +00:00
|
|
|
_distance_to_camera = 0.0;
|
|
|
|
|
|
|
|
_water_height = water_height;
|
|
|
|
_overwater = false;
|
|
|
|
|
2013-12-23 16:24:05 +00:00
|
|
|
tessellation_count = 33;
|
|
|
|
tessellated = new VertexArray<TerrainVertex>();
|
|
|
|
tessellated->setGridSize(tessellation_count);
|
|
|
|
tessellated->setAutoGridIndices(tessellation_count);
|
|
|
|
_tessellation_max_size = tessellation_count - 1;
|
2012-06-08 12:28:46 +00:00
|
|
|
_tessellation_current_size = 0;
|
2013-04-27 19:41:57 +00:00
|
|
|
_tessellation_step = _size / (double) _tessellation_max_size;
|
2012-12-09 17:49:28 +00:00
|
|
|
|
2012-06-08 12:28:46 +00:00
|
|
|
setMaxTextureSize(128);
|
2012-12-09 17:49:28 +00:00
|
|
|
|
2012-06-08 12:28:46 +00:00
|
|
|
maintain();
|
|
|
|
}
|
|
|
|
|
|
|
|
ExplorerChunkTerrain::~ExplorerChunkTerrain()
|
|
|
|
{
|
|
|
|
_lock_data.lock();
|
2013-12-23 13:09:52 +00:00
|
|
|
delete _color_profile;
|
|
|
|
delete _texture;
|
2013-12-23 16:24:05 +00:00
|
|
|
delete tessellated;
|
2012-06-08 12:28:46 +00:00
|
|
|
_lock_data.unlock();
|
|
|
|
}
|
|
|
|
|
2013-12-23 13:09:52 +00:00
|
|
|
bool ExplorerChunkTerrain::maintain()
|
2012-06-08 12:28:46 +00:00
|
|
|
{
|
2013-12-23 13:09:52 +00:00
|
|
|
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);
|
2013-12-24 10:44:39 +00:00
|
|
|
//color = _color_profile->apply(color);
|
2013-12-23 13:09:52 +00:00
|
|
|
color.normalize();
|
2013-12-24 10:44:39 +00:00
|
|
|
new_image->setPixel(i, j, color.to32BitRGBA());
|
2013-12-23 13:09:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_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;
|
|
|
|
}
|
2012-06-08 12:28:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ExplorerChunkTerrain::onMaintainEvent()
|
|
|
|
{
|
|
|
|
// Improve heightmap resolution
|
|
|
|
if (_tessellation_current_size < _tessellation_max_size)
|
|
|
|
{
|
|
|
|
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;
|
2013-12-23 16:24:05 +00:00
|
|
|
float internal_step = 1.0f / (float)_tessellation_max_size;
|
2012-06-08 12:28:46 +00:00
|
|
|
for (int j = 0; j <= _tessellation_max_size; j += new_tessellation_inc)
|
|
|
|
{
|
|
|
|
for (int i = 0; i <= _tessellation_max_size; i += new_tessellation_inc)
|
|
|
|
{
|
|
|
|
if (_tessellation_current_size == 0 || i % old_tessellation_inc != 0 || j % old_tessellation_inc != 0)
|
|
|
|
{
|
2013-12-23 16:24:05 +00:00
|
|
|
double x = _startx + _tessellation_step * (float)i;
|
|
|
|
double z = _startz + _tessellation_step * (float)j;
|
|
|
|
|
|
|
|
double height = _renderer->getTerrainRenderer()->getHeight(x, z, 1);
|
2013-02-05 21:25:30 +00:00
|
|
|
if (height >= _water_height)
|
|
|
|
{
|
|
|
|
_overwater = true;
|
|
|
|
}
|
2013-12-23 16:24:05 +00:00
|
|
|
|
|
|
|
TerrainVertex v;
|
|
|
|
|
|
|
|
v.uv[0] = internal_step * (float)i;
|
|
|
|
v.uv[1] = internal_step * (float)j;
|
|
|
|
|
|
|
|
v.location[0] = x;
|
|
|
|
v.location[1] = height;
|
|
|
|
v.location[2] = z;
|
|
|
|
|
|
|
|
tessellated->setGridVertex(tessellation_count, i, j, v);
|
2012-06-08 12:28:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_lock_data.lock();
|
|
|
|
_tessellation_current_size = new_tessellation_size;
|
2013-12-23 16:24:05 +00:00
|
|
|
tessellated->setAutoGridIndices(tessellation_count, new_tessellation_inc);
|
2012-06-08 12:28:46 +00:00
|
|
|
_lock_data.unlock();
|
|
|
|
|
2013-02-05 21:25:30 +00:00
|
|
|
if (_tessellation_current_size < 4 && _tessellation_current_size < _tessellation_max_size)
|
2013-01-30 21:36:49 +00:00
|
|
|
{
|
|
|
|
onMaintainEvent();
|
|
|
|
}
|
|
|
|
|
2012-06-08 12:28:46 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-23 13:09:52 +00:00
|
|
|
void ExplorerChunkTerrain::updatePriority(CameraDefinition* camera)
|
2012-06-08 12:28:46 +00:00
|
|
|
{
|
2013-12-23 13:09:52 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2013-11-14 17:47:03 +00:00
|
|
|
Vector3 camera_location = camera->getLocation();
|
2013-04-27 19:41:57 +00:00
|
|
|
|
2012-06-08 12:28:46 +00:00
|
|
|
// Handle position
|
|
|
|
_lock_data.lock();
|
2013-04-27 19:41:57 +00:00
|
|
|
if (camera_location.x > _startx + _overall_step * 0.5)
|
2012-06-08 12:28:46 +00:00
|
|
|
{
|
|
|
|
_startx += _overall_step;
|
|
|
|
askReset();
|
|
|
|
}
|
2013-04-27 19:41:57 +00:00
|
|
|
if (camera_location.z > _startz + _overall_step * 0.5)
|
2012-06-08 12:28:46 +00:00
|
|
|
{
|
|
|
|
_startz += _overall_step;
|
|
|
|
askReset();
|
|
|
|
}
|
2013-04-27 19:41:57 +00:00
|
|
|
if (camera_location.x < _startx - _overall_step * 0.5)
|
2012-06-08 12:28:46 +00:00
|
|
|
{
|
|
|
|
_startx -= _overall_step;
|
|
|
|
askReset();
|
|
|
|
}
|
2013-04-27 19:41:57 +00:00
|
|
|
if (camera_location.z < _startz - _overall_step * 0.5)
|
2012-06-08 12:28:46 +00:00
|
|
|
{
|
|
|
|
_startz -= _overall_step;
|
|
|
|
askReset();
|
|
|
|
}
|
2013-02-05 21:25:30 +00:00
|
|
|
|
2013-12-11 10:32:10 +00:00
|
|
|
_distance_to_camera = getCenter().sub(camera_location).getNorm();
|
2013-03-31 20:27:21 +00:00
|
|
|
|
2012-06-08 12:28:46 +00:00
|
|
|
_lock_data.unlock();
|
|
|
|
}
|
|
|
|
|
2013-12-24 10:44:39 +00:00
|
|
|
void ExplorerChunkTerrain::render(QOpenGLShaderProgram* program, OpenGLFunctions* functions)
|
2012-06-08 12:28:46 +00:00
|
|
|
{
|
2013-12-23 13:09:52 +00:00
|
|
|
// Put texture in place
|
2012-06-08 12:28:46 +00:00
|
|
|
_lock_data.lock();
|
2013-12-23 13:09:52 +00:00
|
|
|
if (_texture_changed)
|
2012-06-08 12:28:46 +00:00
|
|
|
{
|
2013-12-23 13:09:52 +00:00
|
|
|
_texture_changed = false;
|
2013-12-24 10:44:39 +00:00
|
|
|
|
2013-12-23 13:09:52 +00:00
|
|
|
// TODO Only do the scale if not power-of-two textures are unsupported by GPU
|
2013-12-24 10:44:39 +00:00
|
|
|
QImage tex = _texture->scaled(_texture_current_size, _texture_current_size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
|
|
|
|
|
|
|
|
if (texture_id == 0)
|
|
|
|
{
|
|
|
|
GLuint texid;
|
|
|
|
functions->glGenTextures(1, &texid);
|
|
|
|
texture_id = texid;
|
|
|
|
}
|
|
|
|
|
|
|
|
functions->glBindTexture(GL_TEXTURE_2D, texture_id);
|
|
|
|
functions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
|
|
functions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
|
|
functions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
|
|
functions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
|
|
functions->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, tex.bits());
|
2012-06-08 12:28:46 +00:00
|
|
|
}
|
2013-12-23 13:09:52 +00:00
|
|
|
_lock_data.unlock();
|
2012-06-08 12:28:46 +00:00
|
|
|
|
2013-12-24 10:44:39 +00:00
|
|
|
// Render tessellated mesh
|
2013-12-23 13:09:52 +00:00
|
|
|
if (!_reset_needed)
|
2012-06-08 12:28:46 +00:00
|
|
|
{
|
2013-12-23 13:09:52 +00:00
|
|
|
_lock_data.lock();
|
|
|
|
int tessellation_size = _tessellation_current_size;
|
|
|
|
_lock_data.unlock();
|
|
|
|
|
|
|
|
if (tessellation_size <= 1 or not _overwater)
|
2012-06-08 12:28:46 +00:00
|
|
|
{
|
2013-12-23 13:09:52 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-12-23 16:24:05 +00:00
|
|
|
_lock_data.lock(); // TEMP
|
2013-12-24 10:44:39 +00:00
|
|
|
// TEMP
|
|
|
|
functions->glActiveTexture(GL_TEXTURE0 + 3);
|
|
|
|
functions->glBindTexture(GL_TEXTURE_2D, texture_id);
|
|
|
|
program->setUniformValue("groundTexture", 3);
|
|
|
|
|
|
|
|
tessellated->render(program, functions);
|
2013-12-23 16:24:05 +00:00
|
|
|
_lock_data.unlock(); // TEMP
|
2012-06-08 12:28:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-23 13:09:52 +00:00
|
|
|
void ExplorerChunkTerrain::askReset()
|
|
|
|
{
|
|
|
|
_reset_needed = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ExplorerChunkTerrain::setMaxTextureSize(int size)
|
|
|
|
{
|
|
|
|
_texture_max_size = size;
|
|
|
|
}
|
|
|
|
|
2012-06-17 09:40:40 +00:00
|
|
|
double ExplorerChunkTerrain::getDisplayedSizeHint(CameraDefinition* camera)
|
2012-06-08 12:28:46 +00:00
|
|
|
{
|
2012-06-17 09:40:40 +00:00
|
|
|
double distance;
|
2012-06-08 12:28:46 +00:00
|
|
|
Vector3 center;
|
|
|
|
|
2013-02-05 21:25:30 +00:00
|
|
|
if (not _overwater)
|
|
|
|
{
|
|
|
|
return -1000.0;
|
|
|
|
}
|
|
|
|
|
2012-06-08 12:28:46 +00:00
|
|
|
center = getCenter();
|
|
|
|
|
2013-11-14 17:47:03 +00:00
|
|
|
if (camera->isBoxInView(center, _size, 40.0, _size))
|
2012-06-08 12:28:46 +00:00
|
|
|
{
|
2013-02-05 21:25:30 +00:00
|
|
|
distance = _distance_to_camera;
|
2012-06-09 20:26:34 +00:00
|
|
|
distance = distance < 0.1 ? 0.1 : distance;
|
2013-04-27 19:41:57 +00:00
|
|
|
return (int) ceil(120.0 - distance / 1.5);
|
2012-06-09 20:26:34 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return -800.0;
|
2012-06-08 12:28:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-17 09:40:40 +00:00
|
|
|
Color ExplorerChunkTerrain::getTextureColor(double x, double y)
|
2012-06-08 12:28:46 +00:00
|
|
|
{
|
|
|
|
Vector3 location = {_startx + x * _size, 0.0, _startz + y * _size};
|
2013-12-23 13:09:52 +00:00
|
|
|
return _renderer->getTerrainRenderer()->getFinalColor(location, 0.01);
|
2012-06-08 12:28:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Vector3 ExplorerChunkTerrain::getCenter()
|
|
|
|
{
|
|
|
|
Vector3 result;
|
2012-12-09 17:49:28 +00:00
|
|
|
|
2012-06-08 12:28:46 +00:00
|
|
|
result.x = _startx + _size / 2.0;
|
|
|
|
result.y = 0.0;
|
|
|
|
result.z = _startz + _size / 2.0;
|
2012-12-09 17:49:28 +00:00
|
|
|
|
2012-06-08 12:28:46 +00:00
|
|
|
return result;
|
|
|
|
}
|