Switched OpenGL to core profile
This commit is contained in:
parent
c7e868ef11
commit
f242f55f81
36 changed files with 966 additions and 864 deletions
2
Makefile
2
Makefile
|
@ -64,7 +64,7 @@ profile_cli:build
|
||||||
|
|
||||||
gltrace:build
|
gltrace:build
|
||||||
rm -f *.trace
|
rm -f *.trace
|
||||||
LD_PRELOAD=/usr/lib/x86_64-linux-gnu/apitrace/wrappers/glxtrace.so LD_LIBRARY_PATH=$(LIBRARY_PATH) ${BUILDPATH}/interface/modeler/quickapp/paysages-modeler $(ARGS)
|
LD_PRELOAD="$(wildcard /usr/lib/x86_64-linux-gnu/apitrace/wrappers/glxtrace.so /usr/local/lib/x86_64-linux-gnu/apitrace/wrappers/glxtrace.so)" LD_LIBRARY_PATH=$(LIBRARY_PATH) ${BUILDPATH}/interface/modeler/quickapp/paysages-modeler $(ARGS)
|
||||||
qapitrace paysages-modeler.trace
|
qapitrace paysages-modeler.trace
|
||||||
|
|
||||||
package:build
|
package:build
|
||||||
|
|
3
TODO
3
TODO
|
@ -5,7 +5,8 @@ Technlology Preview 2 :
|
||||||
- Add clouds to OpenGL with 3d textures.
|
- Add clouds to OpenGL with 3d textures.
|
||||||
- Refactor medium traversal to unify clouds, atmosphere and god rays.
|
- Refactor medium traversal to unify clouds, atmosphere and god rays.
|
||||||
- Fix potential holes in land rendering (OpenGL and software).
|
- Fix potential holes in land rendering (OpenGL and software).
|
||||||
- Fix sun size not being consistent between opengl and software
|
- Fix sun size not being consistent between opengl and software.
|
||||||
|
- Remove Qt dependency in OpenGL renderer, except for OpenGLFunctions.
|
||||||
|
|
||||||
Technology Preview 3 :
|
Technology Preview 3 :
|
||||||
- Alter aerial perspective using estimation of the amount of light left after cloud layers traversal.
|
- Alter aerial perspective using estimation of the amount of light left after cloud layers traversal.
|
||||||
|
|
|
@ -16,10 +16,10 @@
|
||||||
#include <QGuiApplication>
|
#include <QGuiApplication>
|
||||||
|
|
||||||
MainModelerWindow::MainModelerWindow() {
|
MainModelerWindow::MainModelerWindow() {
|
||||||
/*QSurfaceFormat new_format = format();
|
QSurfaceFormat new_format = format();
|
||||||
new_format.setVersion(3, 3);
|
new_format.setVersion(OPENGL_MAJOR_VERSION, OPENGL_MINOR_VERSION);
|
||||||
new_format.setProfile(QSurfaceFormat::CoreProfile);
|
new_format.setProfile(QSurfaceFormat::CoreProfile);
|
||||||
setFormat(new_format);*/
|
setFormat(new_format);
|
||||||
|
|
||||||
scenery = new Scenery();
|
scenery = new Scenery();
|
||||||
scenery->autoPreset();
|
scenery->autoPreset();
|
||||||
|
|
|
@ -52,8 +52,8 @@ void OpenGLView::paint() {
|
||||||
resized = false;
|
resized = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderer->prepareOpenGLState();
|
renderer->prepareOpenGLState(false);
|
||||||
renderer->paint();
|
renderer->paint(false);
|
||||||
|
|
||||||
if (window) {
|
if (window) {
|
||||||
window->resetOpenGLState();
|
window->resetOpenGLState();
|
||||||
|
|
|
@ -1,296 +0,0 @@
|
||||||
#include "ExplorerChunkTerrain.h"
|
|
||||||
|
|
||||||
#include <cmath>
|
|
||||||
#include <QImage>
|
|
||||||
#include "OpenGLFunctions.h"
|
|
||||||
#include "ColorProfile.h"
|
|
||||||
#include "CameraDefinition.h"
|
|
||||||
#include "OpenGLRenderer.h"
|
|
||||||
#include "TerrainRenderer.h"
|
|
||||||
#include "VertexArray.h"
|
|
||||||
#include "Scenery.h"
|
|
||||||
#include "TerrainDefinition.h"
|
|
||||||
|
|
||||||
ExplorerChunkTerrain::ExplorerChunkTerrain(OpenGLRenderer *renderer, double x, double z, double size, int nbchunks)
|
|
||||||
: _renderer(renderer) {
|
|
||||||
priority = 0.0;
|
|
||||||
_reset_topology = false;
|
|
||||||
_reset_texture = false;
|
|
||||||
|
|
||||||
interrupt = false;
|
|
||||||
|
|
||||||
_texture = new QImage(1, 1, QImage::Format_RGBA8888);
|
|
||||||
texture_id = 0;
|
|
||||||
_texture_changed = false;
|
|
||||||
_texture_current_size = 0;
|
|
||||||
_texture_wanted_size = 0;
|
|
||||||
_texture_max_size = 256;
|
|
||||||
|
|
||||||
_startx = x;
|
|
||||||
_startz = z;
|
|
||||||
_size = size;
|
|
||||||
_overall_step = size * (double)nbchunks;
|
|
||||||
|
|
||||||
distance_to_camera = 0.0;
|
|
||||||
underwater = false;
|
|
||||||
lowest = 0.0;
|
|
||||||
highest = 0.0;
|
|
||||||
|
|
||||||
tessellation_count = 65;
|
|
||||||
tessellated = new VertexArray<TerrainVertex>();
|
|
||||||
tessellated->setGridSize(tessellation_count);
|
|
||||||
tessellated->setAutoGridIndices(tessellation_count);
|
|
||||||
_tessellation_max_size = tessellation_count - 1;
|
|
||||||
_tessellation_current_size = 0;
|
|
||||||
_tessellation_step = _size / (double)_tessellation_max_size;
|
|
||||||
|
|
||||||
maintain();
|
|
||||||
}
|
|
||||||
|
|
||||||
ExplorerChunkTerrain::~ExplorerChunkTerrain() {
|
|
||||||
_lock_data.lock();
|
|
||||||
delete _texture;
|
|
||||||
delete tessellated;
|
|
||||||
_lock_data.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ExplorerChunkTerrain::maintain() {
|
|
||||||
bool subchanged;
|
|
||||||
|
|
||||||
_lock_data.lock();
|
|
||||||
if (_reset_topology) {
|
|
||||||
_reset_topology = false;
|
|
||||||
_tessellation_current_size = 0;
|
|
||||||
lowest = 10000.0;
|
|
||||||
highest = -10000.0;
|
|
||||||
underwater = false;
|
|
||||||
}
|
|
||||||
if (_reset_texture) {
|
|
||||||
_reset_texture = false;
|
|
||||||
_texture_current_size = 0;
|
|
||||||
underwater = false;
|
|
||||||
}
|
|
||||||
_lock_data.unlock();
|
|
||||||
|
|
||||||
if (underwater) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Improve heightmap resolution
|
|
||||||
if (_tessellation_current_size < _tessellation_max_size) {
|
|
||||||
while (_tessellation_current_size < _tessellation_max_size) {
|
|
||||||
int new_tessellation_size = _tessellation_current_size ? _tessellation_current_size * 4 : 4;
|
|
||||||
int old_tessellation_inc =
|
|
||||||
_tessellation_current_size ? _tessellation_max_size / _tessellation_current_size : 1;
|
|
||||||
int new_tessellation_inc = _tessellation_max_size / new_tessellation_size;
|
|
||||||
float internal_step = 1.0f / (float)_tessellation_max_size;
|
|
||||||
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) {
|
|
||||||
double x = _startx + _tessellation_step * (float)i;
|
|
||||||
double z = _startz + _tessellation_step * (float)j;
|
|
||||||
|
|
||||||
double height = _renderer->getTerrainRenderer()->getHeight(x, z, true, false);
|
|
||||||
if (height >= highest) {
|
|
||||||
highest = height;
|
|
||||||
}
|
|
||||||
if (height <= lowest) {
|
|
||||||
lowest = height;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (interrupt or _reset_topology) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
underwater = highest < -_renderer->getScenery()->getTerrain()->getWaterOffset();
|
|
||||||
|
|
||||||
_lock_data.lock();
|
|
||||||
_tessellation_current_size = new_tessellation_size;
|
|
||||||
tessellated->setAutoGridIndices(tessellation_count, new_tessellation_inc);
|
|
||||||
_lock_data.unlock();
|
|
||||||
|
|
||||||
if (_tessellation_current_size >= 4) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
subchanged = true;
|
|
||||||
} else {
|
|
||||||
subchanged = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Improve texture resolution
|
|
||||||
if (_texture_current_size < _texture_wanted_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);
|
|
||||||
color.normalize();
|
|
||||||
new_image->setPixel(i, j, color.to32BitRGBA());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (interrupt or _reset_texture) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_lock_data.lock();
|
|
||||||
delete _texture;
|
|
||||||
_texture = new_image;
|
|
||||||
_texture_current_size = new_texture_size;
|
|
||||||
_texture_changed = true;
|
|
||||||
_lock_data.unlock();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return subchanged;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExplorerChunkTerrain::updatePriority(CameraDefinition *camera) {
|
|
||||||
// Under water check
|
|
||||||
underwater = highest < -_renderer->getScenery()->getTerrain()->getWaterOffset();
|
|
||||||
if (underwater) {
|
|
||||||
priority = -10000.0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector3 camera_location = camera->getLocation();
|
|
||||||
|
|
||||||
// Handle position
|
|
||||||
_lock_data.lock();
|
|
||||||
if (camera_location.x > _startx + _overall_step * 0.5) {
|
|
||||||
_startx += _overall_step;
|
|
||||||
askReset();
|
|
||||||
}
|
|
||||||
if (camera_location.z > _startz + _overall_step * 0.5) {
|
|
||||||
_startz += _overall_step;
|
|
||||||
askReset();
|
|
||||||
}
|
|
||||||
if (camera_location.x < _startx - _overall_step * 0.5) {
|
|
||||||
_startx -= _overall_step;
|
|
||||||
askReset();
|
|
||||||
}
|
|
||||||
if (camera_location.z < _startz - _overall_step * 0.5) {
|
|
||||||
_startz -= _overall_step;
|
|
||||||
askReset();
|
|
||||||
}
|
|
||||||
distance_to_camera = getCenter().sub(camera_location).getNorm();
|
|
||||||
_lock_data.unlock();
|
|
||||||
|
|
||||||
// Update wanted LOD
|
|
||||||
if (distance_to_camera < 60.0) {
|
|
||||||
_texture_wanted_size = _texture_max_size;
|
|
||||||
} else if (distance_to_camera < 140.0) {
|
|
||||||
_texture_wanted_size = _texture_max_size / 4;
|
|
||||||
} else if (distance_to_camera < 300.0) {
|
|
||||||
_texture_wanted_size = _texture_max_size / 8;
|
|
||||||
} else {
|
|
||||||
_texture_wanted_size = 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update priority
|
|
||||||
if (_reset_topology || _reset_texture || (_texture_max_size > 1 && _texture_current_size <= 1)) {
|
|
||||||
priority = 1000.0;
|
|
||||||
} else if (_texture_current_size == _texture_wanted_size) {
|
|
||||||
priority = -1000.0;
|
|
||||||
} else {
|
|
||||||
priority = _texture_wanted_size / _texture_current_size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExplorerChunkTerrain::render(QOpenGLShaderProgram *program, OpenGLFunctions *functions) {
|
|
||||||
if (underwater) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Put texture in place
|
|
||||||
_lock_data.lock();
|
|
||||||
if (_texture_changed) {
|
|
||||||
_texture_changed = false;
|
|
||||||
|
|
||||||
// TODO Only do the scale if not power-of-two textures are unsupported by GPU
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
_lock_data.unlock();
|
|
||||||
|
|
||||||
// Render tessellated mesh
|
|
||||||
if (!_reset_topology) {
|
|
||||||
_lock_data.lock();
|
|
||||||
int tessellation_size = _tessellation_current_size;
|
|
||||||
_lock_data.unlock();
|
|
||||||
|
|
||||||
if (tessellation_size <= 1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_lock_data.lock();
|
|
||||||
// TEMP
|
|
||||||
functions->glActiveTexture(GL_TEXTURE0 + 7);
|
|
||||||
functions->glBindTexture(GL_TEXTURE_2D, texture_id);
|
|
||||||
program->setUniformValue("groundTexture", 7);
|
|
||||||
tessellated->render(program, functions);
|
|
||||||
_lock_data.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExplorerChunkTerrain::askReset(bool topology, bool texture) {
|
|
||||||
_reset_topology = _reset_topology or topology;
|
|
||||||
_reset_texture = _reset_texture or texture;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExplorerChunkTerrain::askInterrupt() {
|
|
||||||
interrupt = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExplorerChunkTerrain::askResume() {
|
|
||||||
interrupt = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Color ExplorerChunkTerrain::getTextureColor(double x, double y) {
|
|
||||||
Vector3 location = {_startx + x * _size, 0.0, _startz + y * _size};
|
|
||||||
return _renderer->getTerrainRenderer()->getFinalColor(location, 0.01);
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector3 ExplorerChunkTerrain::getCenter() {
|
|
||||||
Vector3 result;
|
|
||||||
|
|
||||||
result.x = _startx + _size / 2.0;
|
|
||||||
result.y = 0.0;
|
|
||||||
result.z = _startz + _size / 2.0;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
|
@ -1,74 +0,0 @@
|
||||||
#ifndef EXPLORERCHUNKTERRAIN_H
|
|
||||||
#define EXPLORERCHUNKTERRAIN_H
|
|
||||||
|
|
||||||
#include "opengl_global.h"
|
|
||||||
|
|
||||||
#include <QMutex>
|
|
||||||
class QImage;
|
|
||||||
class QOpenGLShaderProgram;
|
|
||||||
|
|
||||||
namespace paysages {
|
|
||||||
namespace opengl {
|
|
||||||
|
|
||||||
class OPENGLSHARED_EXPORT ExplorerChunkTerrain {
|
|
||||||
public:
|
|
||||||
typedef struct {
|
|
||||||
float location[3];
|
|
||||||
float uv[2];
|
|
||||||
} TerrainVertex;
|
|
||||||
|
|
||||||
public:
|
|
||||||
ExplorerChunkTerrain(OpenGLRenderer *renderer, double x, double z, double size, int nbchunks);
|
|
||||||
~ExplorerChunkTerrain();
|
|
||||||
|
|
||||||
bool maintain();
|
|
||||||
void updatePriority(CameraDefinition *camera);
|
|
||||||
void render(QOpenGLShaderProgram *program, OpenGLFunctions *functions);
|
|
||||||
|
|
||||||
void askReset(bool topology = true, bool texture = true);
|
|
||||||
void askInterrupt();
|
|
||||||
void askResume();
|
|
||||||
|
|
||||||
Color getTextureColor(double x, double y);
|
|
||||||
|
|
||||||
double priority;
|
|
||||||
|
|
||||||
private:
|
|
||||||
Vector3 getCenter();
|
|
||||||
|
|
||||||
double _startx;
|
|
||||||
double _startz;
|
|
||||||
double _size;
|
|
||||||
double _overall_step;
|
|
||||||
|
|
||||||
int tessellation_count;
|
|
||||||
VertexArray<TerrainVertex> *tessellated;
|
|
||||||
int _tessellation_max_size;
|
|
||||||
int _tessellation_current_size;
|
|
||||||
double _tessellation_step;
|
|
||||||
|
|
||||||
QMutex _lock_data;
|
|
||||||
|
|
||||||
OpenGLRenderer *_renderer;
|
|
||||||
|
|
||||||
bool _reset_topology;
|
|
||||||
bool _reset_texture;
|
|
||||||
bool interrupt;
|
|
||||||
|
|
||||||
QImage *_texture;
|
|
||||||
unsigned int texture_id;
|
|
||||||
bool _texture_changed;
|
|
||||||
int _texture_current_size;
|
|
||||||
int _texture_wanted_size;
|
|
||||||
int _texture_max_size;
|
|
||||||
|
|
||||||
// LOD control
|
|
||||||
bool underwater;
|
|
||||||
double lowest;
|
|
||||||
double highest;
|
|
||||||
double distance_to_camera;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // EXPLORERCHUNKTERRAIN_H
|
|
|
@ -1,32 +1,27 @@
|
||||||
#include "OpenGLPart.h"
|
#include "OpenGLPart.h"
|
||||||
|
|
||||||
#include <QDir>
|
|
||||||
#include <cmath>
|
|
||||||
#include "OpenGLRenderer.h"
|
|
||||||
#include "OpenGLShaderProgram.h"
|
#include "OpenGLShaderProgram.h"
|
||||||
#include "CameraDefinition.h"
|
#include "OpenGLVertexArray.h"
|
||||||
#include "AtmosphereDefinition.h"
|
|
||||||
#include "AtmosphereRenderer.h"
|
|
||||||
#include "Scenery.h"
|
|
||||||
|
|
||||||
OpenGLPart::OpenGLPart(OpenGLRenderer *renderer) : renderer(renderer) {
|
OpenGLPart::OpenGLPart(OpenGLRenderer *renderer) : renderer(renderer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenGLPart::~OpenGLPart() {
|
OpenGLPart::~OpenGLPart() {
|
||||||
QMapIterator<QString, OpenGLShaderProgram *> i(shaders);
|
for (auto &pair: shaders) {
|
||||||
while (i.hasNext()) {
|
delete pair.second;
|
||||||
i.next();
|
}
|
||||||
delete i.value();
|
for (auto &array: arrays) {
|
||||||
|
delete array;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLPart::interrupt() {
|
void OpenGLPart::interrupt() {
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenGLShaderProgram *OpenGLPart::createShader(QString name) {
|
OpenGLShaderProgram *OpenGLPart::createShader(const std::string &name) {
|
||||||
OpenGLShaderProgram *program = new OpenGLShaderProgram(name.toStdString(), renderer);
|
OpenGLShaderProgram *program = new OpenGLShaderProgram(name, renderer);
|
||||||
|
|
||||||
if (!shaders.contains(name)) {
|
if (shaders.find(name) == shaders.end()) {
|
||||||
shaders[name] = program;
|
shaders[name] = program;
|
||||||
return program;
|
return program;
|
||||||
} else {
|
} else {
|
||||||
|
@ -34,6 +29,13 @@ OpenGLShaderProgram *OpenGLPart::createShader(QString name) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OpenGLVertexArray *OpenGLPart::createVertexArray(bool has_uv, bool strip)
|
||||||
|
{
|
||||||
|
OpenGLVertexArray *result = new OpenGLVertexArray(has_uv, strip);
|
||||||
|
arrays.push_back(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void OpenGLPart::updateScenery(bool onlyCommon) {
|
void OpenGLPart::updateScenery(bool onlyCommon) {
|
||||||
// Let subclass do its own collecting
|
// Let subclass do its own collecting
|
||||||
if (not onlyCommon) {
|
if (not onlyCommon) {
|
||||||
|
|
|
@ -3,14 +3,15 @@
|
||||||
|
|
||||||
#include "opengl_global.h"
|
#include "opengl_global.h"
|
||||||
|
|
||||||
#include <QMap>
|
#include <map>
|
||||||
#include <QString>
|
#include <vector>
|
||||||
|
|
||||||
namespace paysages {
|
namespace paysages {
|
||||||
namespace opengl {
|
namespace opengl {
|
||||||
|
|
||||||
// Class that can be inherited by scenery parts, to use OpenGL features
|
/**
|
||||||
|
* Class that can be inherited by scenery parts, to use OpenGL features.
|
||||||
|
*/
|
||||||
class OPENGLSHARED_EXPORT OpenGLPart {
|
class OPENGLSHARED_EXPORT OpenGLPart {
|
||||||
public:
|
public:
|
||||||
OpenGLPart(OpenGLRenderer *renderer);
|
OpenGLPart(OpenGLRenderer *renderer);
|
||||||
|
@ -31,14 +32,26 @@ class OPENGLSHARED_EXPORT OpenGLPart {
|
||||||
void updateScenery(bool onlyCommon = false);
|
void updateScenery(bool onlyCommon = false);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Create a shader program
|
/**
|
||||||
OpenGLShaderProgram *createShader(QString name);
|
* Create a shader program.
|
||||||
|
*
|
||||||
|
* The returned shader's ownership remains in this object. It will taks care of the destruction.
|
||||||
|
*/
|
||||||
|
OpenGLShaderProgram *createShader(const std::string &name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a vertex array.
|
||||||
|
*
|
||||||
|
* The returned array's ownership remains in this object. It will taks care of the destruction.
|
||||||
|
*/
|
||||||
|
OpenGLVertexArray *createVertexArray(bool has_uv, bool strip);
|
||||||
|
|
||||||
// Access to the main scenery renderer
|
// Access to the main scenery renderer
|
||||||
OpenGLRenderer *renderer;
|
OpenGLRenderer *renderer;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QMap<QString, OpenGLShaderProgram *> shaders;
|
std::map<std::string, OpenGLShaderProgram *> shaders;
|
||||||
|
std::vector<OpenGLVertexArray *> arrays;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,10 +97,8 @@ void OpenGLRenderer::initialize() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLRenderer::prepareOpenGLState() {
|
void OpenGLRenderer::prepareOpenGLState(bool clear) {
|
||||||
if (ready) {
|
if (ready) {
|
||||||
functions->glDisable(GL_LIGHTING);
|
|
||||||
|
|
||||||
functions->glFrontFace(GL_CCW);
|
functions->glFrontFace(GL_CCW);
|
||||||
functions->glCullFace(GL_BACK);
|
functions->glCullFace(GL_BACK);
|
||||||
functions->glEnable(GL_CULL_FACE);
|
functions->glEnable(GL_CULL_FACE);
|
||||||
|
@ -110,16 +108,16 @@ void OpenGLRenderer::prepareOpenGLState() {
|
||||||
functions->glEnable(GL_DEPTH_TEST);
|
functions->glEnable(GL_DEPTH_TEST);
|
||||||
|
|
||||||
functions->glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
functions->glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||||
functions->glEnable(GL_LINE_SMOOTH);
|
/*functions->glEnable(GL_LINE_SMOOTH);
|
||||||
functions->glLineWidth(1.0);
|
functions->glLineWidth(1.0);*/
|
||||||
|
|
||||||
functions->glDisable(GL_FOG);
|
|
||||||
|
|
||||||
functions->glEnable(GL_BLEND);
|
functions->glEnable(GL_BLEND);
|
||||||
functions->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
functions->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
functions->glClearColor(0.0, 0.0, 0.0, 0.0);
|
functions->glClearColor(0.0, 0.0, 0.0, 0.0);
|
||||||
functions->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
if (clear) {
|
||||||
|
functions->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
functions->glViewport(0, 0, vp_width, vp_height);
|
functions->glViewport(0, 0, vp_width, vp_height);
|
||||||
}
|
}
|
||||||
|
@ -146,10 +144,12 @@ void OpenGLRenderer::resize(int width, int height) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLRenderer::paint() {
|
void OpenGLRenderer::paint(bool clear) {
|
||||||
if (ready and not paused) {
|
if (ready and not paused) {
|
||||||
checkForErrors("before_paint");
|
checkForErrors("before_paint");
|
||||||
functions->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
if (clear) {
|
||||||
|
functions->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
skybox->render();
|
skybox->render();
|
||||||
checkForErrors("skybox");
|
checkForErrors("skybox");
|
||||||
|
|
|
@ -39,9 +39,9 @@ class OPENGLSHARED_EXPORT OpenGLRenderer : public SoftwareRenderer {
|
||||||
void checkForErrors(const std::string &domain);
|
void checkForErrors(const std::string &domain);
|
||||||
|
|
||||||
void initialize();
|
void initialize();
|
||||||
void prepareOpenGLState();
|
void prepareOpenGLState(bool clear=true);
|
||||||
void resize(int width, int height);
|
void resize(int width, int height);
|
||||||
void paint();
|
void paint(bool clear=true);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reset the whole state (when the scenery has been massively updated).
|
* Reset the whole state (when the scenery has been massively updated).
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "OpenGLFunctions.h"
|
#include "OpenGLFunctions.h"
|
||||||
#include "OpenGLRenderer.h"
|
#include "OpenGLRenderer.h"
|
||||||
#include "OpenGLSharedState.h"
|
#include "OpenGLSharedState.h"
|
||||||
|
#include "OpenGLVertexArray.h"
|
||||||
#include "Texture2D.h"
|
#include "Texture2D.h"
|
||||||
#include "Texture3D.h"
|
#include "Texture3D.h"
|
||||||
#include "Texture4D.h"
|
#include "Texture4D.h"
|
||||||
|
@ -22,8 +23,8 @@ OpenGLShaderProgram::~OpenGLShaderProgram() {
|
||||||
delete program;
|
delete program;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLShaderProgram::addVertexSource(QString path) {
|
void OpenGLShaderProgram::addVertexSource(const std::string &path) {
|
||||||
QFile file(QString(":/shaders/%1.vert").arg(path));
|
QFile file(QString(":/shaders/%1.vert").arg(QString::fromStdString(path)));
|
||||||
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||||
source_vertex += QString(file.readAll()).toStdString();
|
source_vertex += QString(file.readAll()).toStdString();
|
||||||
} else {
|
} else {
|
||||||
|
@ -31,8 +32,8 @@ void OpenGLShaderProgram::addVertexSource(QString path) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLShaderProgram::addFragmentSource(QString path) {
|
void OpenGLShaderProgram::addFragmentSource(const std::string &path) {
|
||||||
QFile file(QString(":/shaders/%1.frag").arg(path));
|
QFile file(QString(":/shaders/%1.frag").arg(QString::fromStdString(path)));
|
||||||
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||||
source_fragment += QString(file.readAll()).toStdString();
|
source_fragment += QString(file.readAll()).toStdString();
|
||||||
} else {
|
} else {
|
||||||
|
@ -41,8 +42,13 @@ void OpenGLShaderProgram::addFragmentSource(QString path) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLShaderProgram::compile() {
|
void OpenGLShaderProgram::compile() {
|
||||||
program->addShaderFromSourceCode(QOpenGLShader::Vertex, QString::fromStdString(source_vertex));
|
std::string prefix = std::string("#version ") + OPENGL_GLSL_VERSION + "\n\n";
|
||||||
program->addShaderFromSourceCode(QOpenGLShader::Fragment, QString::fromStdString(source_fragment));
|
|
||||||
|
program->addShaderFromSourceCode(QOpenGLShader::Vertex, QString::fromStdString(prefix + source_vertex));
|
||||||
|
program->addShaderFromSourceCode(QOpenGLShader::Fragment, QString::fromStdString(prefix + source_fragment));
|
||||||
|
|
||||||
|
program->bindAttributeLocation("vertex", 0);
|
||||||
|
program->bindAttributeLocation("uv", 1);
|
||||||
|
|
||||||
if (not program->link()) {
|
if (not program->link()) {
|
||||||
Logs::warning() << "[OpenGL] Error while compiling shader " << name << std::endl
|
Logs::warning() << "[OpenGL] Error while compiling shader " << name << std::endl
|
||||||
|
@ -55,7 +61,7 @@ void OpenGLShaderProgram::compile() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OpenGLShaderProgram::bind() {
|
bool OpenGLShaderProgram::bind(OpenGLSharedState *state) {
|
||||||
if (not compiled) {
|
if (not compiled) {
|
||||||
compile();
|
compile();
|
||||||
compiled = true;
|
compiled = true;
|
||||||
|
@ -64,6 +70,9 @@ bool OpenGLShaderProgram::bind() {
|
||||||
if (program->bind()) {
|
if (program->bind()) {
|
||||||
int texture_unit = 0;
|
int texture_unit = 0;
|
||||||
renderer->getSharedState()->apply(this, texture_unit);
|
renderer->getSharedState()->apply(this, texture_unit);
|
||||||
|
if (state) {
|
||||||
|
state->apply(this, texture_unit);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
@ -74,29 +83,9 @@ void OpenGLShaderProgram::release() {
|
||||||
program->release();
|
program->release();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLShaderProgram::drawTriangles(float *vertices, int triangle_count) {
|
void OpenGLShaderProgram::draw(OpenGLVertexArray *vertices, OpenGLSharedState *state) {
|
||||||
if (bind()) {
|
if (bind(state)) {
|
||||||
GLuint vertex = program->attributeLocation("vertex");
|
vertices->render(functions);
|
||||||
program->setAttributeArray(vertex, GL_FLOAT, vertices, 3);
|
|
||||||
program->enableAttributeArray(vertex);
|
|
||||||
|
|
||||||
functions->glDrawArrays(GL_TRIANGLES, 0, triangle_count * 3);
|
|
||||||
|
|
||||||
program->disableAttributeArray(vertex);
|
|
||||||
|
|
||||||
release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLShaderProgram::drawTriangleStrip(float *vertices, int vertex_count) {
|
|
||||||
if (bind()) {
|
|
||||||
GLuint vertex = program->attributeLocation("vertex");
|
|
||||||
program->setAttributeArray(vertex, GL_FLOAT, vertices, 3);
|
|
||||||
program->enableAttributeArray(vertex);
|
|
||||||
|
|
||||||
functions->glDrawArrays(GL_TRIANGLE_STRIP, 0, vertex_count);
|
|
||||||
|
|
||||||
program->disableAttributeArray(vertex);
|
|
||||||
|
|
||||||
release();
|
release();
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
|
|
||||||
#include "opengl_global.h"
|
#include "opengl_global.h"
|
||||||
|
|
||||||
#include <QString>
|
|
||||||
|
|
||||||
class QOpenGLShaderProgram;
|
class QOpenGLShaderProgram;
|
||||||
|
|
||||||
namespace paysages {
|
namespace paysages {
|
||||||
|
@ -15,18 +13,25 @@ class OPENGLSHARED_EXPORT OpenGLShaderProgram {
|
||||||
OpenGLShaderProgram(const std::string &name, OpenGLRenderer *renderer);
|
OpenGLShaderProgram(const std::string &name, OpenGLRenderer *renderer);
|
||||||
~OpenGLShaderProgram();
|
~OpenGLShaderProgram();
|
||||||
|
|
||||||
void addVertexSource(QString path);
|
void addVertexSource(const std::string &path);
|
||||||
void addFragmentSource(QString path);
|
void addFragmentSource(const std::string &path);
|
||||||
|
|
||||||
void drawTriangles(float *vertices, int triangle_count);
|
/**
|
||||||
void drawTriangleStrip(float *vertices, int vertex_count);
|
* Draw a VertexArray object.
|
||||||
|
*
|
||||||
bool bind();
|
* This will bind the program (compile it if needed), set the uniform variables, and
|
||||||
void release();
|
* ask the array object to bind its VAO and render itself.
|
||||||
|
*
|
||||||
|
* *state* is optional and may add ponctual variables to the global state.
|
||||||
|
*/
|
||||||
|
void draw(OpenGLVertexArray *vertices, OpenGLSharedState *state = NULL);
|
||||||
|
|
||||||
inline QOpenGLShaderProgram *getProgram() const {
|
inline QOpenGLShaderProgram *getProgram() const {
|
||||||
return program;
|
return program;
|
||||||
}
|
}
|
||||||
|
inline OpenGLFunctions *getFunctions() const {
|
||||||
|
return functions;
|
||||||
|
}
|
||||||
inline OpenGLRenderer *getRenderer() const {
|
inline OpenGLRenderer *getRenderer() const {
|
||||||
return renderer;
|
return renderer;
|
||||||
}
|
}
|
||||||
|
@ -35,6 +40,8 @@ class OPENGLSHARED_EXPORT OpenGLShaderProgram {
|
||||||
friend class OpenGLVariable;
|
friend class OpenGLVariable;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool bind(OpenGLSharedState *state = NULL);
|
||||||
|
void release();
|
||||||
void compile();
|
void compile();
|
||||||
|
|
||||||
bool compiled;
|
bool compiled;
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
#include "OpenGLVariable.h"
|
#include "OpenGLVariable.h"
|
||||||
|
|
||||||
|
class QImage;
|
||||||
|
|
||||||
namespace paysages {
|
namespace paysages {
|
||||||
namespace opengl {
|
namespace opengl {
|
||||||
|
|
||||||
|
@ -31,6 +33,9 @@ class OPENGLSHARED_EXPORT OpenGLSharedState {
|
||||||
inline void set(const std::string &name, const Texture2D *texture, bool repeat = false, bool color = true) {
|
inline void set(const std::string &name, const Texture2D *texture, bool repeat = false, bool color = true) {
|
||||||
get(name)->set(texture, repeat, color);
|
get(name)->set(texture, repeat, color);
|
||||||
}
|
}
|
||||||
|
inline void set(const std::string &name, const QImage &texture, bool repeat = false, bool color = true) {
|
||||||
|
get(name)->set(texture, repeat, color);
|
||||||
|
}
|
||||||
inline void set(const std::string &name, const Texture3D *texture, bool repeat = false, bool color = true) {
|
inline void set(const std::string &name, const Texture3D *texture, bool repeat = false, bool color = true) {
|
||||||
get(name)->set(texture, repeat, color);
|
get(name)->set(texture, repeat, color);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "OpenGLRenderer.h"
|
#include "OpenGLRenderer.h"
|
||||||
#include "OpenGLShaderProgram.h"
|
#include "OpenGLShaderProgram.h"
|
||||||
#include "OpenGLSharedState.h"
|
#include "OpenGLSharedState.h"
|
||||||
|
#include "OpenGLVertexArray.h"
|
||||||
#include "Scenery.h"
|
#include "Scenery.h"
|
||||||
#include "AtmosphereDefinition.h"
|
#include "AtmosphereDefinition.h"
|
||||||
#include "AtmosphereRenderer.h"
|
#include "AtmosphereRenderer.h"
|
||||||
|
@ -11,42 +12,43 @@
|
||||||
#include "FloatNode.h"
|
#include "FloatNode.h"
|
||||||
|
|
||||||
OpenGLSkybox::OpenGLSkybox(OpenGLRenderer *renderer) : OpenGLPart(renderer) {
|
OpenGLSkybox::OpenGLSkybox(OpenGLRenderer *renderer) : OpenGLPart(renderer) {
|
||||||
vertices = new float[14 * 3];
|
|
||||||
}
|
|
||||||
|
|
||||||
OpenGLSkybox::~OpenGLSkybox() {
|
|
||||||
delete[] vertices;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLSkybox::initialize() {
|
|
||||||
program = createShader("skybox");
|
program = createShader("skybox");
|
||||||
program->addVertexSource("skybox");
|
program->addVertexSource("skybox");
|
||||||
program->addFragmentSource("atmosphere");
|
program->addFragmentSource("atmosphere");
|
||||||
program->addFragmentSource("tonemapping");
|
program->addFragmentSource("tonemapping");
|
||||||
program->addFragmentSource("skybox");
|
program->addFragmentSource("skybox");
|
||||||
|
|
||||||
setVertex(0, 1.0f, 1.0f, 1.0f);
|
vertices = createVertexArray(false, true);
|
||||||
setVertex(12, 1.0f, 1.0f, 1.0f);
|
|
||||||
|
|
||||||
setVertex(1, 1.0f, -1.0f, 1.0f);
|
vertices->setVertexCount(14);
|
||||||
setVertex(5, 1.0f, -1.0f, 1.0f);
|
|
||||||
setVertex(13, 1.0f, -1.0f, 1.0f);
|
|
||||||
|
|
||||||
setVertex(2, -1.0f, 1.0f, 1.0f);
|
vertices->set(0, Vector3(1.0f, 1.0f, 1.0f));
|
||||||
setVertex(10, -1.0f, 1.0f, 1.0f);
|
vertices->set(12, Vector3(1.0f, 1.0f, 1.0f));
|
||||||
|
|
||||||
setVertex(3, -1.0f, -1.0f, 1.0f);
|
vertices->set(1, Vector3(1.0f, -1.0f, 1.0f));
|
||||||
|
vertices->set(5, Vector3(1.0f, -1.0f, 1.0f));
|
||||||
|
vertices->set(13, Vector3(1.0f, -1.0f, 1.0f));
|
||||||
|
|
||||||
setVertex(4, -1.0f, -1.0f, -1.0f);
|
vertices->set(2, Vector3(-1.0f, 1.0f, 1.0f));
|
||||||
setVertex(8, -1.0f, -1.0f, -1.0f);
|
vertices->set(10, Vector3(-1.0f, 1.0f, 1.0f));
|
||||||
|
|
||||||
setVertex(6, 1.0f, -1.0f, -1.0f);
|
vertices->set(3, Vector3(-1.0f, -1.0f, 1.0f));
|
||||||
|
|
||||||
setVertex(7, 1.0f, 1.0f, -1.0f);
|
vertices->set(4, Vector3(-1.0f, -1.0f, -1.0f));
|
||||||
setVertex(11, 1.0f, 1.0f, -1.0f);
|
vertices->set(8, Vector3(-1.0f, -1.0f, -1.0f));
|
||||||
|
|
||||||
setVertex(9, -1.0f, 1.0f, -1.0f);
|
vertices->set(6, Vector3(1.0f, -1.0f, -1.0f));
|
||||||
|
|
||||||
|
vertices->set(7, Vector3(1.0f, 1.0f, -1.0f));
|
||||||
|
vertices->set(11, Vector3(1.0f, 1.0f, -1.0f));
|
||||||
|
|
||||||
|
vertices->set(9, Vector3(-1.0f, 1.0f, -1.0f));
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenGLSkybox::~OpenGLSkybox() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLSkybox::initialize() {
|
||||||
// Watch for definition changes
|
// Watch for definition changes
|
||||||
renderer->getScenery()->getAtmosphere()->propDayTime()->addWatcher(this, true);
|
renderer->getScenery()->getAtmosphere()->propDayTime()->addWatcher(this, true);
|
||||||
renderer->getScenery()->getAtmosphere()->propHumidity()->addWatcher(this, true);
|
renderer->getScenery()->getAtmosphere()->propHumidity()->addWatcher(this, true);
|
||||||
|
@ -61,7 +63,7 @@ void OpenGLSkybox::update() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLSkybox::render() {
|
void OpenGLSkybox::render() {
|
||||||
program->drawTriangleStrip(vertices, 14);
|
program->draw(vertices);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLSkybox::nodeChanged(const DefinitionNode *node, const DefinitionDiff *) {
|
void OpenGLSkybox::nodeChanged(const DefinitionNode *node, const DefinitionDiff *) {
|
||||||
|
@ -81,9 +83,3 @@ void OpenGLSkybox::nodeChanged(const DefinitionNode *node, const DefinitionDiff
|
||||||
renderer->getScenery()->getAtmosphere()->propSunRadius()->getValue());
|
renderer->getScenery()->getAtmosphere()->propSunRadius()->getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLSkybox::setVertex(int i, float x, float y, float z) {
|
|
||||||
vertices[i * 3] = x;
|
|
||||||
vertices[i * 3 + 1] = y;
|
|
||||||
vertices[i * 3 + 2] = z;
|
|
||||||
}
|
|
||||||
|
|
|
@ -21,10 +21,8 @@ class OPENGLSHARED_EXPORT OpenGLSkybox : public OpenGLPart, public DefinitionWat
|
||||||
virtual void nodeChanged(const DefinitionNode *node, const DefinitionDiff *diff) override;
|
virtual void nodeChanged(const DefinitionNode *node, const DefinitionDiff *diff) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setVertex(int i, float x, float y, float z);
|
|
||||||
|
|
||||||
OpenGLShaderProgram *program;
|
OpenGLShaderProgram *program;
|
||||||
float *vertices;
|
OpenGLVertexArray *vertices;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#include "OpenGLShaderProgram.h"
|
#include "OpenGLShaderProgram.h"
|
||||||
#include "ParallelPool.h"
|
#include "ParallelPool.h"
|
||||||
#include "Thread.h"
|
#include "Thread.h"
|
||||||
#include "ExplorerChunkTerrain.h"
|
#include "OpenGLTerrainChunk.h"
|
||||||
#include "WaterRenderer.h"
|
#include "WaterRenderer.h"
|
||||||
#include "CameraDefinition.h"
|
#include "CameraDefinition.h"
|
||||||
#include "AtmosphereDefinition.h"
|
#include "AtmosphereDefinition.h"
|
||||||
|
@ -35,6 +35,14 @@ class ChunkMaintenanceThreads : public ParallelPool {
|
||||||
OpenGLTerrain::OpenGLTerrain(OpenGLRenderer *renderer) : OpenGLPart(renderer) {
|
OpenGLTerrain::OpenGLTerrain(OpenGLRenderer *renderer) : OpenGLPart(renderer) {
|
||||||
work = new ChunkMaintenanceThreads(this);
|
work = new ChunkMaintenanceThreads(this);
|
||||||
paused = false;
|
paused = false;
|
||||||
|
|
||||||
|
program = createShader("terrain");
|
||||||
|
program->addVertexSource("terrain");
|
||||||
|
program->addFragmentSource("atmosphere");
|
||||||
|
program->addFragmentSource("tonemapping");
|
||||||
|
program->addFragmentSource("fadeout");
|
||||||
|
program->addFragmentSource("ui");
|
||||||
|
program->addFragmentSource("terrain");
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenGLTerrain::~OpenGLTerrain() {
|
OpenGLTerrain::~OpenGLTerrain() {
|
||||||
|
@ -46,15 +54,6 @@ OpenGLTerrain::~OpenGLTerrain() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLTerrain::initialize() {
|
void OpenGLTerrain::initialize() {
|
||||||
// Prepare shader programs
|
|
||||||
program = createShader("terrain");
|
|
||||||
program->addVertexSource("terrain");
|
|
||||||
program->addFragmentSource("atmosphere");
|
|
||||||
program->addFragmentSource("tonemapping");
|
|
||||||
program->addFragmentSource("fadeout");
|
|
||||||
program->addFragmentSource("ui");
|
|
||||||
program->addFragmentSource("terrain");
|
|
||||||
|
|
||||||
// Add terrain chunks
|
// Add terrain chunks
|
||||||
int chunks = 12;
|
int chunks = 12;
|
||||||
double size = 800.0;
|
double size = 800.0;
|
||||||
|
@ -62,7 +61,7 @@ void OpenGLTerrain::initialize() {
|
||||||
double start = -size / 2.0;
|
double start = -size / 2.0;
|
||||||
for (int i = 0; i < chunks; i++) {
|
for (int i = 0; i < chunks; i++) {
|
||||||
for (int j = 0; j < chunks; j++) {
|
for (int j = 0; j < chunks; j++) {
|
||||||
ExplorerChunkTerrain *chunk = new ExplorerChunkTerrain(renderer, start + chunksize * (double)i,
|
OpenGLTerrainChunk *chunk = new OpenGLTerrainChunk(renderer, start + chunksize * (double)i,
|
||||||
start + chunksize * (double)j, chunksize, chunks);
|
start + chunksize * (double)j, chunksize, chunks);
|
||||||
_chunks.append(chunk);
|
_chunks.append(chunk);
|
||||||
_updateQueue.append(chunk);
|
_updateQueue.append(chunk);
|
||||||
|
@ -84,13 +83,9 @@ void OpenGLTerrain::update() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLTerrain::render() {
|
void OpenGLTerrain::render() {
|
||||||
program->bind();
|
|
||||||
|
|
||||||
for (int i = 0; i < _chunks.count(); i++) {
|
for (int i = 0; i < _chunks.count(); i++) {
|
||||||
_chunks[i]->render(program->getProgram(), renderer->getOpenGlFunctions());
|
_chunks[i]->render(program);
|
||||||
}
|
}
|
||||||
|
|
||||||
program->release();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLTerrain::interrupt() {
|
void OpenGLTerrain::interrupt() {
|
||||||
|
@ -117,13 +112,13 @@ void OpenGLTerrain::resetTextures() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _cmpChunks(const ExplorerChunkTerrain *c1, const ExplorerChunkTerrain *c2) {
|
static bool _cmpChunks(const OpenGLTerrainChunk *c1, const OpenGLTerrainChunk *c2) {
|
||||||
return c1->priority > c2->priority;
|
return c1->priority > c2->priority;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLTerrain::performChunksMaintenance() {
|
void OpenGLTerrain::performChunksMaintenance() {
|
||||||
CameraDefinition *camera = renderer->getScenery()->getCamera();
|
CameraDefinition *camera = renderer->getScenery()->getCamera();
|
||||||
ExplorerChunkTerrain *chunk;
|
OpenGLTerrainChunk *chunk;
|
||||||
|
|
||||||
_lock_chunks.lock();
|
_lock_chunks.lock();
|
||||||
if (_updateQueue.count() > 0) {
|
if (_updateQueue.count() > 0) {
|
||||||
|
|
|
@ -44,8 +44,8 @@ class OPENGLSHARED_EXPORT OpenGLTerrain : public OpenGLPart, public DefinitionWa
|
||||||
ParallelPool *work;
|
ParallelPool *work;
|
||||||
bool paused;
|
bool paused;
|
||||||
|
|
||||||
QVector<ExplorerChunkTerrain *> _chunks;
|
QVector<OpenGLTerrainChunk *> _chunks;
|
||||||
QList<ExplorerChunkTerrain *> _updateQueue;
|
QList<OpenGLTerrainChunk *> _updateQueue;
|
||||||
QMutex _lock_chunks;
|
QMutex _lock_chunks;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
261
src/render/opengl/OpenGLTerrainChunk.cpp
Normal file
261
src/render/opengl/OpenGLTerrainChunk.cpp
Normal file
|
@ -0,0 +1,261 @@
|
||||||
|
#include "OpenGLTerrainChunk.h"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <cassert>
|
||||||
|
#include <QImage>
|
||||||
|
#include "OpenGLShaderProgram.h"
|
||||||
|
#include "OpenGLVertexArray.h"
|
||||||
|
#include "OpenGLSharedState.h"
|
||||||
|
#include "ColorProfile.h"
|
||||||
|
#include "CameraDefinition.h"
|
||||||
|
#include "OpenGLRenderer.h"
|
||||||
|
#include "TexturesRenderer.h"
|
||||||
|
#include "Scenery.h"
|
||||||
|
#include "TerrainDefinition.h"
|
||||||
|
#include "Texture2D.h"
|
||||||
|
#include "Mutex.h"
|
||||||
|
#include "Logs.h"
|
||||||
|
|
||||||
|
OpenGLTerrainChunk::OpenGLTerrainChunk(OpenGLRenderer *renderer, double x, double z, double size, int nbchunks)
|
||||||
|
: _renderer(renderer) {
|
||||||
|
priority = 0.0;
|
||||||
|
_reset_topology = false;
|
||||||
|
_reset_texture = false;
|
||||||
|
|
||||||
|
interrupt = false;
|
||||||
|
|
||||||
|
_lock_data = new Mutex();
|
||||||
|
|
||||||
|
_texture = new QImage(1, 1, QImage::Format_RGBA8888);
|
||||||
|
_texture_changed = false;
|
||||||
|
_texture_current_size = 0;
|
||||||
|
_texture_wanted_size = 0;
|
||||||
|
_texture_max_size = 256;
|
||||||
|
|
||||||
|
_startx = x;
|
||||||
|
_startz = z;
|
||||||
|
_size = size;
|
||||||
|
_overall_step = size * (double)nbchunks;
|
||||||
|
|
||||||
|
distance_to_camera = 0.0;
|
||||||
|
|
||||||
|
vertices = new OpenGLVertexArray(true);
|
||||||
|
vertices_level = 0;
|
||||||
|
glstate = new OpenGLSharedState();
|
||||||
|
Texture2D empty(1, 1);
|
||||||
|
glstate->set("groundTexture", &empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenGLTerrainChunk::~OpenGLTerrainChunk() {
|
||||||
|
_lock_data->acquire();
|
||||||
|
|
||||||
|
delete _texture;
|
||||||
|
delete vertices;
|
||||||
|
delete glstate;
|
||||||
|
|
||||||
|
_lock_data->release();
|
||||||
|
|
||||||
|
delete _lock_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenGLTerrainChunk::maintain() {
|
||||||
|
bool subchanged;
|
||||||
|
|
||||||
|
_lock_data->acquire();
|
||||||
|
if (_reset_topology) {
|
||||||
|
_reset_topology = false;
|
||||||
|
vertices_level = 0;
|
||||||
|
}
|
||||||
|
if (_reset_texture) {
|
||||||
|
_reset_texture = false;
|
||||||
|
_texture_current_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
_lock_data->release();
|
||||||
|
|
||||||
|
// Improve heightmap resolution
|
||||||
|
if (vertices_level < 8) {
|
||||||
|
if (vertices_level) {
|
||||||
|
augmentVertices();
|
||||||
|
} else {
|
||||||
|
setFirstStepVertices();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else if (vertices_level < 64) {
|
||||||
|
augmentVertices();
|
||||||
|
subchanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Improve texture resolution
|
||||||
|
if (_texture_current_size < _texture_wanted_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));
|
||||||
|
double factor = _size / (double)new_texture_size;
|
||||||
|
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) {
|
||||||
|
double x = _startx + factor * (double)i;
|
||||||
|
double z = _startz + factor * (double)j;
|
||||||
|
Color color = _renderer->getTexturesRenderer()->applyToTerrain(x, z).final_color;
|
||||||
|
color.normalize();
|
||||||
|
new_image->setPixel(i, j, color.to32BitRGBA());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (interrupt or _reset_texture) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_lock_data->acquire();
|
||||||
|
delete _texture;
|
||||||
|
_texture = new_image;
|
||||||
|
_texture_current_size = new_texture_size;
|
||||||
|
_texture_changed = true;
|
||||||
|
_lock_data->release();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return subchanged;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLTerrainChunk::updatePriority(CameraDefinition *camera) {
|
||||||
|
Vector3 camera_location = camera->getLocation();
|
||||||
|
|
||||||
|
// Handle position
|
||||||
|
_lock_data->acquire();
|
||||||
|
if (camera_location.x > _startx + _overall_step * 0.5) {
|
||||||
|
_startx += _overall_step;
|
||||||
|
askReset();
|
||||||
|
}
|
||||||
|
if (camera_location.z > _startz + _overall_step * 0.5) {
|
||||||
|
_startz += _overall_step;
|
||||||
|
askReset();
|
||||||
|
}
|
||||||
|
if (camera_location.x < _startx - _overall_step * 0.5) {
|
||||||
|
_startx -= _overall_step;
|
||||||
|
askReset();
|
||||||
|
}
|
||||||
|
if (camera_location.z < _startz - _overall_step * 0.5) {
|
||||||
|
_startz -= _overall_step;
|
||||||
|
askReset();
|
||||||
|
}
|
||||||
|
distance_to_camera = getCenter().sub(camera_location).getNorm();
|
||||||
|
_lock_data->release();
|
||||||
|
|
||||||
|
// Update wanted LOD
|
||||||
|
if (distance_to_camera < 60.0) {
|
||||||
|
_texture_wanted_size = _texture_max_size;
|
||||||
|
} else if (distance_to_camera < 140.0) {
|
||||||
|
_texture_wanted_size = _texture_max_size / 4;
|
||||||
|
} else if (distance_to_camera < 300.0) {
|
||||||
|
_texture_wanted_size = _texture_max_size / 8;
|
||||||
|
} else {
|
||||||
|
_texture_wanted_size = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update priority
|
||||||
|
if (_reset_topology || _reset_texture || (_texture_max_size > 1 && _texture_current_size <= 1) ||
|
||||||
|
vertices_level < 8) {
|
||||||
|
priority = 1000.0 - (double)vertices_level;
|
||||||
|
} else if (_texture_current_size == _texture_wanted_size) {
|
||||||
|
priority = -1000.0;
|
||||||
|
} else {
|
||||||
|
priority = _texture_wanted_size / _texture_current_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLTerrainChunk::render(OpenGLShaderProgram *program) {
|
||||||
|
// Put texture in place
|
||||||
|
_lock_data->acquire();
|
||||||
|
if (_texture_changed) {
|
||||||
|
_texture_changed = false;
|
||||||
|
glstate->set("groundTexture", *_texture);
|
||||||
|
/*glstate->set("groundTexture", _texture->scaled(_texture_current_size, _texture_current_size,
|
||||||
|
Qt::IgnoreAspectRatio, Qt::SmoothTransformation));*/
|
||||||
|
}
|
||||||
|
_lock_data->release();
|
||||||
|
|
||||||
|
// FIXME Should update *vertices* inside lock
|
||||||
|
program->draw(vertices, glstate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLTerrainChunk::askReset(bool topology, bool texture) {
|
||||||
|
_reset_topology = _reset_topology or topology;
|
||||||
|
_reset_texture = _reset_texture or texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLTerrainChunk::askInterrupt() {
|
||||||
|
interrupt = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLTerrainChunk::askResume() {
|
||||||
|
interrupt = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLTerrainChunk::setFirstStepVertices() {
|
||||||
|
OpenGLVertexArray next(true);
|
||||||
|
next.setVertexCount(6);
|
||||||
|
fillVerticesFromSquare(&next, 0, _startx, _startz, _size);
|
||||||
|
updateVertices(next, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLTerrainChunk::augmentVertices() {
|
||||||
|
OpenGLVertexArray next(true);
|
||||||
|
next.setVertexCount(vertices->getVertexCount() * 4);
|
||||||
|
int next_vertices_level = vertices_level * 2;
|
||||||
|
|
||||||
|
// TODO Re-use existing vertices from previous level when possible
|
||||||
|
double quad_size = _size / (double)next_vertices_level;
|
||||||
|
for (int iz = 0; iz < next_vertices_level; iz++) {
|
||||||
|
for (int ix = 0; ix < next_vertices_level; ix++) {
|
||||||
|
fillVerticesFromSquare(&next, (iz * next_vertices_level + ix) * 6, _startx + quad_size * (double)ix,
|
||||||
|
_startz + quad_size * (double)iz, quad_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateVertices(next, next_vertices_level);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLTerrainChunk::updateVertices(const OpenGLVertexArray &source, int vertice_level) {
|
||||||
|
assert(source.getVertexCount() == vertice_level * vertice_level * 6);
|
||||||
|
|
||||||
|
_lock_data->acquire();
|
||||||
|
|
||||||
|
source.copyTo(vertices);
|
||||||
|
vertices_level = vertice_level;
|
||||||
|
|
||||||
|
_lock_data->release();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLTerrainChunk::fillVerticesFromSquare(OpenGLVertexArray *array, int index_offset, double x, double z,
|
||||||
|
double size) {
|
||||||
|
Vector3 c1(x, _renderer->getTerrainRenderer()->getHeight(x, z, true, false), z);
|
||||||
|
Vector3 c2(x, _renderer->getTerrainRenderer()->getHeight(x, z + size, true, false), z + size);
|
||||||
|
Vector3 c3(x + size, _renderer->getTerrainRenderer()->getHeight(x + size, z + size, true, false), z + size);
|
||||||
|
Vector3 c4(x + size, _renderer->getTerrainRenderer()->getHeight(x + size, z, true, false), z);
|
||||||
|
|
||||||
|
double u = (x - _startx) / _size;
|
||||||
|
double v = (z - _startz) / _size;
|
||||||
|
double dt = size / _size;
|
||||||
|
|
||||||
|
array->set(index_offset, c1, u, v);
|
||||||
|
array->set(index_offset + 1, c2, u, v + dt);
|
||||||
|
array->set(index_offset + 2, c4, u + dt, v);
|
||||||
|
|
||||||
|
array->set(index_offset + 3, c3, u + dt, v + dt);
|
||||||
|
array->set(index_offset + 4, c4, u + dt, v);
|
||||||
|
array->set(index_offset + 5, c2, u, v + dt);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3 OpenGLTerrainChunk::getCenter() {
|
||||||
|
Vector3 result;
|
||||||
|
|
||||||
|
result.x = _startx + _size / 2.0;
|
||||||
|
result.y = 0.0;
|
||||||
|
result.z = _startz + _size / 2.0;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
87
src/render/opengl/OpenGLTerrainChunk.h
Normal file
87
src/render/opengl/OpenGLTerrainChunk.h
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
#ifndef OPENGLTERRAINCHUNK_H
|
||||||
|
#define OPENGLTERRAINCHUNK_H
|
||||||
|
|
||||||
|
#include "opengl_global.h"
|
||||||
|
|
||||||
|
class QImage;
|
||||||
|
|
||||||
|
namespace paysages {
|
||||||
|
namespace opengl {
|
||||||
|
|
||||||
|
class OPENGLSHARED_EXPORT OpenGLTerrainChunk {
|
||||||
|
public:
|
||||||
|
OpenGLTerrainChunk(OpenGLRenderer *renderer, double x, double z, double size, int nbchunks);
|
||||||
|
~OpenGLTerrainChunk();
|
||||||
|
|
||||||
|
bool maintain();
|
||||||
|
void updatePriority(CameraDefinition *camera);
|
||||||
|
void render(OpenGLShaderProgram *program);
|
||||||
|
|
||||||
|
void askReset(bool topology = true, bool texture = true);
|
||||||
|
void askInterrupt();
|
||||||
|
void askResume();
|
||||||
|
|
||||||
|
inline int getVerticesLevel() const {
|
||||||
|
return vertices_level;
|
||||||
|
}
|
||||||
|
inline const OpenGLVertexArray *getVertices() const {
|
||||||
|
return vertices;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fill *vertices* with a quick initial set of vertices, that can be augmented later using *augmentVertices*.
|
||||||
|
*/
|
||||||
|
void setFirstStepVertices();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Improve the level of detail of tessellated vertices in *vertices*.
|
||||||
|
*
|
||||||
|
* This will double the existing resolution.
|
||||||
|
*/
|
||||||
|
void augmentVertices();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update *vertices* using *source*.
|
||||||
|
*/
|
||||||
|
void updateVertices(const OpenGLVertexArray &source, int vertice_level);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a square (two triangles) in *vertices_next*.
|
||||||
|
*/
|
||||||
|
void fillVerticesFromSquare(OpenGLVertexArray *array, int index_offset, double x, double z, double size);
|
||||||
|
|
||||||
|
double priority;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Vector3 getCenter();
|
||||||
|
|
||||||
|
double _startx;
|
||||||
|
double _startz;
|
||||||
|
double _size;
|
||||||
|
double _overall_step;
|
||||||
|
|
||||||
|
OpenGLVertexArray *vertices;
|
||||||
|
int vertices_level;
|
||||||
|
|
||||||
|
Mutex *_lock_data;
|
||||||
|
|
||||||
|
OpenGLRenderer *_renderer;
|
||||||
|
OpenGLSharedState *glstate;
|
||||||
|
|
||||||
|
bool _reset_topology;
|
||||||
|
bool _reset_texture;
|
||||||
|
bool interrupt;
|
||||||
|
|
||||||
|
QImage *_texture;
|
||||||
|
bool _texture_changed;
|
||||||
|
int _texture_current_size;
|
||||||
|
int _texture_wanted_size;
|
||||||
|
int _texture_max_size;
|
||||||
|
|
||||||
|
// LOD control
|
||||||
|
double distance_to_camera;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // OPENGLTERRAINCHUNK_H
|
|
@ -1,7 +1,12 @@
|
||||||
#include "OpenGLVariable.h"
|
#include "OpenGLVariable.h"
|
||||||
|
|
||||||
#include <QOpenGLShaderProgram>
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <QOpenGLShaderProgram>
|
||||||
|
#include <QColor>
|
||||||
|
#include <QVector3D>
|
||||||
|
#include <QMatrix4x4>
|
||||||
|
#include <QImage>
|
||||||
|
#include "Logs.h"
|
||||||
#include "OpenGLFunctions.h"
|
#include "OpenGLFunctions.h"
|
||||||
#include "OpenGLRenderer.h"
|
#include "OpenGLRenderer.h"
|
||||||
#include "OpenGLShaderProgram.h"
|
#include "OpenGLShaderProgram.h"
|
||||||
|
@ -16,6 +21,22 @@ OpenGLVariable::OpenGLVariable(const std::string &name) : name(name) {
|
||||||
type = TYPE_NONE;
|
type = TYPE_NONE;
|
||||||
texture_toupload = false;
|
texture_toupload = false;
|
||||||
texture_id = 0;
|
texture_id = 0;
|
||||||
|
|
||||||
|
value_color = new QColor;
|
||||||
|
value_matrix4 = new QMatrix4x4;
|
||||||
|
value_vector3 = new QVector3D;
|
||||||
|
value_texture_data = new float[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenGLVariable::~OpenGLVariable() {
|
||||||
|
delete value_color;
|
||||||
|
delete value_matrix4;
|
||||||
|
delete value_vector3;
|
||||||
|
delete[] value_texture_data;
|
||||||
|
|
||||||
|
if (texture_id) {
|
||||||
|
Logs::warning() << "[OpenGL] Texture ID not freed " << texture_id << std::endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLVariable::apply(OpenGLShaderProgram *program, int &texture_unit) {
|
void OpenGLVariable::apply(OpenGLShaderProgram *program, int &texture_unit) {
|
||||||
|
@ -32,13 +53,13 @@ void OpenGLVariable::apply(OpenGLShaderProgram *program, int &texture_unit) {
|
||||||
pr->setUniformValue(name.c_str(), value_float);
|
pr->setUniformValue(name.c_str(), value_float);
|
||||||
break;
|
break;
|
||||||
case TYPE_COLOR:
|
case TYPE_COLOR:
|
||||||
pr->setUniformValue(name.c_str(), value_color);
|
pr->setUniformValue(name.c_str(), *value_color);
|
||||||
break;
|
break;
|
||||||
case TYPE_VECTOR3:
|
case TYPE_VECTOR3:
|
||||||
pr->setUniformValue(name.c_str(), value_vector3);
|
pr->setUniformValue(name.c_str(), *value_vector3);
|
||||||
break;
|
break;
|
||||||
case TYPE_MATRIX4:
|
case TYPE_MATRIX4:
|
||||||
pr->setUniformValue(name.c_str(), value_matrix4);
|
pr->setUniformValue(name.c_str(), *value_matrix4);
|
||||||
break;
|
break;
|
||||||
case TYPE_TEXTURE_2D:
|
case TYPE_TEXTURE_2D:
|
||||||
functions->glActiveTexture(GL_TEXTURE0 + texture_unit);
|
functions->glActiveTexture(GL_TEXTURE0 + texture_unit);
|
||||||
|
@ -62,7 +83,61 @@ void OpenGLVariable::set(const Texture2D *texture, bool repeat, bool color) {
|
||||||
assert(type == TYPE_NONE or type == TYPE_TEXTURE_2D);
|
assert(type == TYPE_NONE or type == TYPE_TEXTURE_2D);
|
||||||
|
|
||||||
type = TYPE_TEXTURE_2D;
|
type = TYPE_TEXTURE_2D;
|
||||||
value_tex2d = texture;
|
|
||||||
|
int sx, sy;
|
||||||
|
texture->getSize(&sx, &sy);
|
||||||
|
float *pixels = new float[sx * sy * 4];
|
||||||
|
for (int x = 0; x < sx; x++) {
|
||||||
|
for (int y = 0; y < sy; y++) {
|
||||||
|
float *pixel = pixels + (y * sx + x) * 4;
|
||||||
|
Color col = texture->getPixel(x, y);
|
||||||
|
pixel[0] = (float)col.r;
|
||||||
|
pixel[1] = (float)col.g;
|
||||||
|
pixel[2] = (float)col.b;
|
||||||
|
pixel[3] = (float)col.a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float *old_pixels = value_texture_data;
|
||||||
|
value_texture_data = pixels;
|
||||||
|
delete[] old_pixels;
|
||||||
|
|
||||||
|
texture_size_x = sx;
|
||||||
|
texture_size_y = sy;
|
||||||
|
texture_size_z = 0;
|
||||||
|
|
||||||
|
texture_toupload = true;
|
||||||
|
texture_repeat = repeat;
|
||||||
|
texture_color = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLVariable::set(const QImage &texture, bool repeat, bool color)
|
||||||
|
{
|
||||||
|
assert(type == TYPE_NONE or type == TYPE_TEXTURE_2D);
|
||||||
|
|
||||||
|
type = TYPE_TEXTURE_2D;
|
||||||
|
|
||||||
|
int sx = texture.width(), sy = texture.height();
|
||||||
|
float *pixels = new float[sx * sy * 4];
|
||||||
|
for (int x = 0; x < sx; x++) {
|
||||||
|
for (int y = 0; y < sy; y++) {
|
||||||
|
float *pixel = pixels + (y * sx + x) * 4;
|
||||||
|
Color col = Color::from32BitRGBA(texture.pixel(x, y));
|
||||||
|
pixel[0] = (float)col.r;
|
||||||
|
pixel[1] = (float)col.g;
|
||||||
|
pixel[2] = (float)col.b;
|
||||||
|
pixel[3] = (float)col.a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float *old_pixels = value_texture_data;
|
||||||
|
value_texture_data = pixels;
|
||||||
|
delete[] old_pixels;
|
||||||
|
|
||||||
|
texture_size_x = sx;
|
||||||
|
texture_size_y = sy;
|
||||||
|
texture_size_z = 0;
|
||||||
|
|
||||||
texture_toupload = true;
|
texture_toupload = true;
|
||||||
texture_repeat = repeat;
|
texture_repeat = repeat;
|
||||||
texture_color = color;
|
texture_color = color;
|
||||||
|
@ -71,8 +146,31 @@ void OpenGLVariable::set(const Texture2D *texture, bool repeat, bool color) {
|
||||||
void OpenGLVariable::set(const Texture3D *texture, bool repeat, bool color) {
|
void OpenGLVariable::set(const Texture3D *texture, bool repeat, bool color) {
|
||||||
assert(type == TYPE_NONE or type == TYPE_TEXTURE_3D);
|
assert(type == TYPE_NONE or type == TYPE_TEXTURE_3D);
|
||||||
|
|
||||||
|
int sx, sy, sz;
|
||||||
|
texture->getSize(&sx, &sy, &sz);
|
||||||
|
float *pixels = new float[sx * sy * sz * 4];
|
||||||
|
for (int x = 0; x < sx; x++) {
|
||||||
|
for (int y = 0; y < sy; y++) {
|
||||||
|
for (int z = 0; z < sz; z++) {
|
||||||
|
float *pixel = pixels + (z * (sx * sy) + y * sx + x) * 4;
|
||||||
|
Color col = texture->getPixel(x, y, z);
|
||||||
|
pixel[0] = (float)col.r;
|
||||||
|
pixel[1] = (float)col.g;
|
||||||
|
pixel[2] = (float)col.b;
|
||||||
|
pixel[3] = (float)col.a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float *old_pixels = value_texture_data;
|
||||||
|
value_texture_data = pixels;
|
||||||
|
delete[] old_pixels;
|
||||||
|
|
||||||
|
texture_size_x = sx;
|
||||||
|
texture_size_y = sy;
|
||||||
|
texture_size_z = sz;
|
||||||
|
|
||||||
type = TYPE_TEXTURE_3D;
|
type = TYPE_TEXTURE_3D;
|
||||||
value_tex3d = texture;
|
|
||||||
texture_toupload = true;
|
texture_toupload = true;
|
||||||
texture_repeat = repeat;
|
texture_repeat = repeat;
|
||||||
texture_color = color;
|
texture_color = color;
|
||||||
|
@ -81,8 +179,33 @@ void OpenGLVariable::set(const Texture3D *texture, bool repeat, bool color) {
|
||||||
void OpenGLVariable::set(const Texture4D *texture, bool repeat, bool color) {
|
void OpenGLVariable::set(const Texture4D *texture, bool repeat, bool color) {
|
||||||
assert(type == TYPE_NONE or type == TYPE_TEXTURE_4D);
|
assert(type == TYPE_NONE or type == TYPE_TEXTURE_4D);
|
||||||
|
|
||||||
|
int sx, sy, sz, sw;
|
||||||
|
texture->getSize(&sx, &sy, &sz, &sw);
|
||||||
|
float *pixels = new float[sx * sy * sz * sw * 4];
|
||||||
|
for (int x = 0; x < sx; x++) {
|
||||||
|
for (int y = 0; y < sy; y++) {
|
||||||
|
for (int z = 0; z < sz; z++) {
|
||||||
|
for (int w = 0; w < sw; w++) {
|
||||||
|
float *pixel = pixels + (w * (sx * sy * sz) + z * (sx * sy) + y * sx + x) * 4;
|
||||||
|
Color col = texture->getPixel(x, y, z, w);
|
||||||
|
pixel[0] = (float)col.r;
|
||||||
|
pixel[1] = (float)col.g;
|
||||||
|
pixel[2] = (float)col.b;
|
||||||
|
pixel[3] = (float)col.a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float *old_pixels = value_texture_data;
|
||||||
|
value_texture_data = pixels;
|
||||||
|
delete[] old_pixels;
|
||||||
|
|
||||||
|
texture_size_x = sx;
|
||||||
|
texture_size_y = sy;
|
||||||
|
texture_size_z = sz * sw;
|
||||||
|
|
||||||
type = TYPE_TEXTURE_4D;
|
type = TYPE_TEXTURE_4D;
|
||||||
value_tex4d = texture;
|
|
||||||
texture_toupload = true;
|
texture_toupload = true;
|
||||||
texture_repeat = repeat;
|
texture_repeat = repeat;
|
||||||
texture_color = color;
|
texture_color = color;
|
||||||
|
@ -103,7 +226,7 @@ void OpenGLVariable::set(const QVector3D &vector) {
|
||||||
assert(type == TYPE_NONE or type == TYPE_VECTOR3);
|
assert(type == TYPE_NONE or type == TYPE_VECTOR3);
|
||||||
|
|
||||||
type = TYPE_VECTOR3;
|
type = TYPE_VECTOR3;
|
||||||
value_vector3 = vector;
|
*value_vector3 = vector;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLVariable::set(const Matrix4 &matrix) {
|
void OpenGLVariable::set(const Matrix4 &matrix) {
|
||||||
|
@ -114,14 +237,14 @@ void OpenGLVariable::set(const QMatrix4x4 &matrix) {
|
||||||
assert(type == TYPE_NONE or type == TYPE_MATRIX4);
|
assert(type == TYPE_NONE or type == TYPE_MATRIX4);
|
||||||
|
|
||||||
type = TYPE_MATRIX4;
|
type = TYPE_MATRIX4;
|
||||||
value_matrix4 = matrix;
|
*value_matrix4 = matrix;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLVariable::set(const Color &color) {
|
void OpenGLVariable::set(const Color &color) {
|
||||||
assert(type == TYPE_NONE or type == TYPE_COLOR);
|
assert(type == TYPE_NONE or type == TYPE_COLOR);
|
||||||
|
|
||||||
type = TYPE_COLOR;
|
type = TYPE_COLOR;
|
||||||
value_color = QColor::fromRgbF(color.r, color.g, color.b);
|
*value_color = QColor::fromRgbF(color.r, color.g, color.b);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLVariable::uploadTexture(OpenGLRenderer *renderer) {
|
void OpenGLVariable::uploadTexture(OpenGLRenderer *renderer) {
|
||||||
|
@ -149,61 +272,8 @@ void OpenGLVariable::uploadTexture(OpenGLRenderer *renderer) {
|
||||||
int dest_format = texture_color ? GL_RGBA : GL_RED;
|
int dest_format = texture_color ? GL_RGBA : GL_RED;
|
||||||
|
|
||||||
if (type == TYPE_TEXTURE_2D) {
|
if (type == TYPE_TEXTURE_2D) {
|
||||||
int sx, sy;
|
functions->glTexImage2D(GL_TEXTURE_2D, 0, dest_format, texture_size_x, texture_size_y, 0, GL_RGBA, GL_FLOAT, value_texture_data);
|
||||||
value_tex2d->getSize(&sx, &sy);
|
|
||||||
float *pixels = new float[sx * sy * 4];
|
|
||||||
for (int x = 0; x < sx; x++) {
|
|
||||||
for (int y = 0; y < sy; y++) {
|
|
||||||
float *pixel = pixels + (y * sx + x) * 4;
|
|
||||||
Color col = value_tex2d->getPixel(x, y);
|
|
||||||
pixel[0] = (float)col.r;
|
|
||||||
pixel[1] = (float)col.g;
|
|
||||||
pixel[2] = (float)col.b;
|
|
||||||
pixel[3] = (float)col.a;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
functions->glTexImage2D(GL_TEXTURE_2D, 0, dest_format, sx, sy, 0, GL_RGBA, GL_FLOAT, pixels);
|
|
||||||
delete[] pixels;
|
|
||||||
} else if (type == TYPE_TEXTURE_3D) {
|
|
||||||
int sx, sy, sz;
|
|
||||||
value_tex3d->getSize(&sx, &sy, &sz);
|
|
||||||
float *pixels = new float[sx * sy * sz * 4];
|
|
||||||
for (int x = 0; x < sx; x++) {
|
|
||||||
for (int y = 0; y < sy; y++) {
|
|
||||||
for (int z = 0; z < sz; z++) {
|
|
||||||
float *pixel = pixels + (z * (sx * sy) + y * sx + x) * 4;
|
|
||||||
Color col = value_tex3d->getPixel(x, y, z);
|
|
||||||
pixel[0] = (float)col.r;
|
|
||||||
pixel[1] = (float)col.g;
|
|
||||||
pixel[2] = (float)col.b;
|
|
||||||
pixel[3] = (float)col.a;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
functions->glTexImage3D(GL_TEXTURE_3D, 0, dest_format, sx, sy, sz, 0, GL_RGBA, GL_FLOAT, pixels);
|
|
||||||
delete[] pixels;
|
|
||||||
} else {
|
} else {
|
||||||
int sx, sy, sz, sw;
|
functions->glTexImage3D(GL_TEXTURE_3D, 0, dest_format, texture_size_x, texture_size_y, texture_size_z, 0, GL_RGBA, GL_FLOAT, value_texture_data);
|
||||||
value_tex4d->getSize(&sx, &sy, &sz, &sw);
|
|
||||||
float *pixels = new float[sx * sy * sz * sw * 4];
|
|
||||||
for (int x = 0; x < sx; x++) {
|
|
||||||
for (int y = 0; y < sy; y++) {
|
|
||||||
for (int z = 0; z < sz; z++) {
|
|
||||||
for (int w = 0; w < sw; w++) {
|
|
||||||
float *pixel = pixels + (w * (sx * sy * sz) + z * (sx * sy) + y * sx + x) * 4;
|
|
||||||
Color col = value_tex4d->getPixel(x, y, z, w);
|
|
||||||
pixel[0] = (float)col.r;
|
|
||||||
pixel[1] = (float)col.g;
|
|
||||||
pixel[2] = (float)col.b;
|
|
||||||
pixel[3] = (float)col.a;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
functions->glTexImage3D(GL_TEXTURE_3D, 0, dest_format, sx, sy, sz * sw, 0, GL_RGBA, GL_FLOAT, pixels);
|
|
||||||
delete[] pixels;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,9 +3,10 @@
|
||||||
|
|
||||||
#include "opengl_global.h"
|
#include "opengl_global.h"
|
||||||
|
|
||||||
#include <QColor>
|
class QColor;
|
||||||
#include <QVector3D>
|
class QVector3D;
|
||||||
#include <QMatrix4x4>
|
class QMatrix4x4;
|
||||||
|
class QImage;
|
||||||
|
|
||||||
namespace paysages {
|
namespace paysages {
|
||||||
namespace opengl {
|
namespace opengl {
|
||||||
|
@ -28,10 +29,12 @@ class OpenGLVariable {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
OpenGLVariable(const std::string &name);
|
OpenGLVariable(const std::string &name);
|
||||||
|
~OpenGLVariable();
|
||||||
|
|
||||||
void apply(OpenGLShaderProgram *program, int &texture_unit);
|
void apply(OpenGLShaderProgram *program, int &texture_unit);
|
||||||
|
|
||||||
void set(const Texture2D *texture, bool repeat = false, bool color = true);
|
void set(const Texture2D *texture, bool repeat = false, bool color = true);
|
||||||
|
void set(const QImage &texture, bool repeat = false, bool color = true);
|
||||||
void set(const Texture3D *texture, bool repeat = false, bool color = true);
|
void set(const Texture3D *texture, bool repeat = false, bool color = true);
|
||||||
void set(const Texture4D *texture, bool repeat = false, bool color = true);
|
void set(const Texture4D *texture, bool repeat = false, bool color = true);
|
||||||
void set(float value);
|
void set(float value);
|
||||||
|
@ -49,13 +52,14 @@ class OpenGLVariable {
|
||||||
OpenGLVariableType type;
|
OpenGLVariableType type;
|
||||||
|
|
||||||
float value_float;
|
float value_float;
|
||||||
QColor value_color;
|
QColor *value_color;
|
||||||
QVector3D value_vector3;
|
QVector3D *value_vector3;
|
||||||
QMatrix4x4 value_matrix4;
|
QMatrix4x4 *value_matrix4;
|
||||||
const Texture2D *value_tex2d;
|
float *value_texture_data;
|
||||||
const Texture3D *value_tex3d;
|
|
||||||
const Texture4D *value_tex4d;
|
|
||||||
|
|
||||||
|
int texture_size_x;
|
||||||
|
int texture_size_y;
|
||||||
|
int texture_size_z;
|
||||||
bool texture_toupload;
|
bool texture_toupload;
|
||||||
bool texture_repeat;
|
bool texture_repeat;
|
||||||
bool texture_color;
|
bool texture_color;
|
||||||
|
|
121
src/render/opengl/OpenGLVertexArray.cpp
Normal file
121
src/render/opengl/OpenGLVertexArray.cpp
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
#include "OpenGLVertexArray.h"
|
||||||
|
|
||||||
|
#include "OpenGLFunctions.h"
|
||||||
|
#include "Logs.h"
|
||||||
|
#include "Vector3.h"
|
||||||
|
|
||||||
|
OpenGLVertexArray::OpenGLVertexArray(bool has_uv, bool strip) : has_uv(has_uv) {
|
||||||
|
if (strip) {
|
||||||
|
draw_mode = GL_TRIANGLE_STRIP;
|
||||||
|
} else {
|
||||||
|
draw_mode = GL_TRIANGLES;
|
||||||
|
}
|
||||||
|
|
||||||
|
vao = 0;
|
||||||
|
vbo_vertex = 0;
|
||||||
|
vbo_uv = 0;
|
||||||
|
|
||||||
|
changed = false;
|
||||||
|
vertexcount = 0;
|
||||||
|
array_vertex = (float *)malloc(sizeof(float));
|
||||||
|
array_uv = (float *)malloc(sizeof(float));
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenGLVertexArray::~OpenGLVertexArray() {
|
||||||
|
if (vao || vbo_vertex || vbo_uv) {
|
||||||
|
Logs::warning() << "[OpenGL] VertexArray not freed in OpenGL state before destructor called" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(array_vertex);
|
||||||
|
free(array_uv);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLVertexArray::destroy() {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLVertexArray::render(OpenGLFunctions *functions) {
|
||||||
|
if (changed) {
|
||||||
|
changed = false;
|
||||||
|
update(functions);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vertexcount and vao) {
|
||||||
|
functions->glBindVertexArray(vao);
|
||||||
|
functions->glDrawArrays(draw_mode, 0, vertexcount);
|
||||||
|
functions->glBindVertexArray(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLVertexArray::setVertexCount(int count) {
|
||||||
|
if (count != vertexcount) {
|
||||||
|
vertexcount = count;
|
||||||
|
if (count < 1) {
|
||||||
|
count = 1;
|
||||||
|
}
|
||||||
|
array_vertex = (float *)realloc(array_vertex, sizeof(float) * count * 3);
|
||||||
|
array_uv = (float *)realloc(array_uv, sizeof(float) * count * 2);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLVertexArray::set(int index, const Vector3 &location, double u, double v) {
|
||||||
|
if (index >= 0 and index < vertexcount) {
|
||||||
|
array_vertex[index * 3] = location.x;
|
||||||
|
array_vertex[index * 3 + 1] = location.y;
|
||||||
|
array_vertex[index * 3 + 2] = location.z;
|
||||||
|
array_uv[index * 2] = u;
|
||||||
|
array_uv[index * 2 + 1] = v;
|
||||||
|
changed = true;
|
||||||
|
} else {
|
||||||
|
Logs::error() << "[OpenGL] Setting vertex data outside of array bounds" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLVertexArray::get(int index, Vector3 *location, double *u, double *v) const
|
||||||
|
{
|
||||||
|
if (index >= 0 and index < vertexcount) {
|
||||||
|
location->x = array_vertex[index * 3];
|
||||||
|
location->y = array_vertex[index * 3 + 1];
|
||||||
|
location->z = array_vertex[index * 3 + 2];
|
||||||
|
*u = array_uv[index * 2];
|
||||||
|
*v = array_uv[index * 2 + 1];
|
||||||
|
} else {
|
||||||
|
Logs::error() << "[OpenGL] Getting vertex data outside of array bounds" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLVertexArray::copyTo(OpenGLVertexArray *destination) const
|
||||||
|
{
|
||||||
|
destination->setVertexCount(vertexcount);
|
||||||
|
if (vertexcount) {
|
||||||
|
memcpy(destination->array_vertex, array_vertex, sizeof(float) * vertexcount * 3);
|
||||||
|
memcpy(destination->array_uv, array_uv, sizeof(float) * vertexcount * 2);
|
||||||
|
}
|
||||||
|
destination->changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLVertexArray::update(OpenGLFunctions *functions) {
|
||||||
|
if (not vao) {
|
||||||
|
functions->glGenVertexArrays(1, &vao);
|
||||||
|
}
|
||||||
|
functions->glBindVertexArray(vao);
|
||||||
|
|
||||||
|
if (not vbo_vertex) {
|
||||||
|
functions->glGenBuffers(1, &vbo_vertex);
|
||||||
|
}
|
||||||
|
functions->glBindBuffer(GL_ARRAY_BUFFER, vbo_vertex);
|
||||||
|
functions->glBufferData(GL_ARRAY_BUFFER, sizeof(float) * vertexcount * 3, array_vertex, GL_STATIC_DRAW);
|
||||||
|
functions->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
|
||||||
|
functions->glEnableVertexAttribArray(0);
|
||||||
|
|
||||||
|
if (not vbo_uv) {
|
||||||
|
functions->glGenBuffers(1, &vbo_uv);
|
||||||
|
}
|
||||||
|
functions->glBindBuffer(GL_ARRAY_BUFFER, vbo_uv);
|
||||||
|
functions->glBufferData(GL_ARRAY_BUFFER, sizeof(float) * vertexcount * 2, array_uv, GL_STATIC_DRAW);
|
||||||
|
functions->glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);
|
||||||
|
functions->glEnableVertexAttribArray(1);
|
||||||
|
|
||||||
|
functions->glBindVertexArray(0);
|
||||||
|
}
|
94
src/render/opengl/OpenGLVertexArray.h
Normal file
94
src/render/opengl/OpenGLVertexArray.h
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
#ifndef OPENGLVERTEXARRAY_H
|
||||||
|
#define OPENGLVERTEXARRAY_H
|
||||||
|
|
||||||
|
#include "opengl_global.h"
|
||||||
|
|
||||||
|
namespace paysages {
|
||||||
|
namespace opengl {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vertex arrays storage and binding, to render triangles.
|
||||||
|
*
|
||||||
|
* This will handle VAOs and VBOs automatically.
|
||||||
|
*/
|
||||||
|
class OpenGLVertexArray {
|
||||||
|
public:
|
||||||
|
OpenGLVertexArray(bool has_uv, bool strip = false);
|
||||||
|
~OpenGLVertexArray();
|
||||||
|
|
||||||
|
inline int getVertexCount() const {
|
||||||
|
return vertexcount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Release any allocated resource in the opengl context.
|
||||||
|
*
|
||||||
|
* Must be called in the opengl rendering thread, and before the destructor is called.
|
||||||
|
*/
|
||||||
|
void destroy();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render this array in current opengl context.
|
||||||
|
*
|
||||||
|
* Must be called in the opengl rendering thread.
|
||||||
|
*
|
||||||
|
* A shader program must be bound (and uniforms defined) when calling this.
|
||||||
|
*/
|
||||||
|
void render(OpenGLFunctions *functions);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the vertex total count.
|
||||||
|
*/
|
||||||
|
void setVertexCount(int count);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set vertex data in the array.
|
||||||
|
*
|
||||||
|
* setVertexCount must have been called before to make room for this vertex.
|
||||||
|
*/
|
||||||
|
void set(int index, const Vector3 &location, double u = 0.0, double v = 0.0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve vertex data in the array.
|
||||||
|
*
|
||||||
|
* This is not optimized, only use for testing.
|
||||||
|
*/
|
||||||
|
void get(int index, Vector3 *location, double *u, double *v) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy this vertex array to another.
|
||||||
|
*
|
||||||
|
* This does not check it the arrays have the same config, but they certainly should.
|
||||||
|
*/
|
||||||
|
void copyTo(OpenGLVertexArray *destination) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* Update the opengl state.
|
||||||
|
*
|
||||||
|
* Should only be called when the data changed.
|
||||||
|
*
|
||||||
|
* Must be called in the opengl rendering thread.
|
||||||
|
*/
|
||||||
|
void update(OpenGLFunctions *functions);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Config
|
||||||
|
bool has_uv;
|
||||||
|
int draw_mode;
|
||||||
|
|
||||||
|
// OpenGL IDs
|
||||||
|
unsigned int vao;
|
||||||
|
unsigned int vbo_vertex;
|
||||||
|
unsigned int vbo_uv;
|
||||||
|
|
||||||
|
// Data
|
||||||
|
bool changed;
|
||||||
|
int vertexcount;
|
||||||
|
float *array_vertex;
|
||||||
|
float *array_uv;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // OPENGLVERTEXARRAY_H
|
|
@ -3,6 +3,7 @@
|
||||||
#include "OpenGLRenderer.h"
|
#include "OpenGLRenderer.h"
|
||||||
#include "OpenGLShaderProgram.h"
|
#include "OpenGLShaderProgram.h"
|
||||||
#include "OpenGLSharedState.h"
|
#include "OpenGLSharedState.h"
|
||||||
|
#include "OpenGLVertexArray.h"
|
||||||
#include "WaterRenderer.h"
|
#include "WaterRenderer.h"
|
||||||
#include "Scenery.h"
|
#include "Scenery.h"
|
||||||
#include "WaterDefinition.h"
|
#include "WaterDefinition.h"
|
||||||
|
@ -13,15 +14,8 @@
|
||||||
#include "IntNode.h"
|
#include "IntNode.h"
|
||||||
|
|
||||||
OpenGLWater::OpenGLWater(OpenGLRenderer *renderer) : OpenGLPart(renderer) {
|
OpenGLWater::OpenGLWater(OpenGLRenderer *renderer) : OpenGLPart(renderer) {
|
||||||
vertices = new float[4 * 3];
|
|
||||||
enabled = true;
|
enabled = true;
|
||||||
}
|
|
||||||
|
|
||||||
OpenGLWater::~OpenGLWater() {
|
|
||||||
delete[] vertices;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLWater::initialize() {
|
|
||||||
program = createShader("water");
|
program = createShader("water");
|
||||||
program->addVertexSource("water");
|
program->addVertexSource("water");
|
||||||
program->addFragmentSource("atmosphere");
|
program->addFragmentSource("atmosphere");
|
||||||
|
@ -31,11 +25,18 @@ void OpenGLWater::initialize() {
|
||||||
program->addFragmentSource("noise");
|
program->addFragmentSource("noise");
|
||||||
program->addFragmentSource("water");
|
program->addFragmentSource("water");
|
||||||
|
|
||||||
setVertex(0, -1.0f, 0.0f, -1.0f);
|
vertices = createVertexArray(false, true);
|
||||||
setVertex(1, -1.0f, 0.0f, 1.0f);
|
vertices->setVertexCount(4);
|
||||||
setVertex(2, 1.0f, 0.0f, -1.0f);
|
vertices->set(0, Vector3(-1.0f, 0.0f, -1.0f));
|
||||||
setVertex(3, 1.0f, 0.0f, 1.0f);
|
vertices->set(1, Vector3(-1.0f, 0.0f, 1.0f));
|
||||||
|
vertices->set(2, Vector3(1.0f, 0.0f, -1.0f));
|
||||||
|
vertices->set(3, Vector3(1.0f, 0.0f, 1.0f));
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenGLWater::~OpenGLWater() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLWater::initialize() {
|
||||||
// Watch for definition changes
|
// Watch for definition changes
|
||||||
renderer->getScenery()->getTerrain()->propWaterHeight()->addWatcher(this, true);
|
renderer->getScenery()->getTerrain()->propWaterHeight()->addWatcher(this, true);
|
||||||
renderer->getScenery()->getWater()->propReflection()->addWatcher(this, true);
|
renderer->getScenery()->getWater()->propReflection()->addWatcher(this, true);
|
||||||
|
@ -54,16 +55,10 @@ void OpenGLWater::update() {
|
||||||
|
|
||||||
void OpenGLWater::render() {
|
void OpenGLWater::render() {
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
program->drawTriangleStrip(vertices, 4);
|
program->draw(vertices);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLWater::setVertex(int i, float x, float y, float z) {
|
|
||||||
vertices[i * 3] = x;
|
|
||||||
vertices[i * 3 + 1] = y;
|
|
||||||
vertices[i * 3 + 2] = z;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLWater::nodeChanged(const DefinitionNode *node, const DefinitionDiff *) {
|
void OpenGLWater::nodeChanged(const DefinitionNode *node, const DefinitionDiff *) {
|
||||||
if (node->getPath() == "/terrain/water_height") {
|
if (node->getPath() == "/terrain/water_height") {
|
||||||
renderer->getSharedState()->set("waterOffset", renderer->getScenery()->getTerrain()->getWaterOffset());
|
renderer->getSharedState()->set("waterOffset", renderer->getScenery()->getTerrain()->getWaterOffset());
|
||||||
|
|
|
@ -26,11 +26,9 @@ class OPENGLSHARED_EXPORT OpenGLWater : public OpenGLPart, public DefinitionWatc
|
||||||
void setEnabled(bool enabled);
|
void setEnabled(bool enabled);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setVertex(int i, float x, float y, float z);
|
|
||||||
|
|
||||||
bool enabled;
|
bool enabled;
|
||||||
OpenGLShaderProgram *program;
|
OpenGLShaderProgram *program;
|
||||||
float *vertices;
|
OpenGLVertexArray *vertices;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,147 +0,0 @@
|
||||||
#ifndef VERTEXARRAY_H
|
|
||||||
#define VERTEXARRAY_H
|
|
||||||
|
|
||||||
#include "opengl_global.h"
|
|
||||||
|
|
||||||
#include <cassert>
|
|
||||||
#include <QOpenGLShaderProgram>
|
|
||||||
#include "OpenGLFunctions.h"
|
|
||||||
|
|
||||||
namespace paysages {
|
|
||||||
namespace opengl {
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* Wrapper for OpenGL vertex arrays.
|
|
||||||
*/
|
|
||||||
template <typename Vertex> class VertexArray {
|
|
||||||
public:
|
|
||||||
VertexArray() {
|
|
||||||
ready = false;
|
|
||||||
changed = false;
|
|
||||||
vertex_count = 1;
|
|
||||||
vertices = new Vertex[1];
|
|
||||||
index_count = 1;
|
|
||||||
indices = new unsigned short[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
~VertexArray() {
|
|
||||||
delete[] vertices;
|
|
||||||
delete[] indices;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int getVertexCount() {
|
|
||||||
return vertex_count;
|
|
||||||
}
|
|
||||||
inline int getIndexCount() {
|
|
||||||
return index_count;
|
|
||||||
}
|
|
||||||
inline bool isReady() {
|
|
||||||
return ready;
|
|
||||||
}
|
|
||||||
inline bool isChanged() {
|
|
||||||
return changed;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setVertexCount(int count) {
|
|
||||||
assert(count > 0 and count <= 16384);
|
|
||||||
|
|
||||||
delete[] vertices;
|
|
||||||
vertices = new Vertex[count];
|
|
||||||
|
|
||||||
vertex_count = count;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setGridSize(int edge_vertex_count) {
|
|
||||||
assert(edge_vertex_count >= 2);
|
|
||||||
|
|
||||||
setVertexCount(edge_vertex_count * edge_vertex_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setVertex(int position, const Vertex &vertex) {
|
|
||||||
assert(position >= 0 and position < vertex_count);
|
|
||||||
|
|
||||||
vertices[position] = vertex;
|
|
||||||
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setGridVertex(int edge_vertex_count, int x, int y, const Vertex &vertex) {
|
|
||||||
setVertex(y * edge_vertex_count + x, vertex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setAutoGridIndices(int edge_vertex_count, int stride = 1) {
|
|
||||||
assert(stride >= 1);
|
|
||||||
|
|
||||||
delete[] indices;
|
|
||||||
int cell_count = edge_vertex_count - 1;
|
|
||||||
|
|
||||||
index_count = (cell_count / stride) * (cell_count / stride) * 6;
|
|
||||||
indices = new unsigned short[index_count];
|
|
||||||
|
|
||||||
int idx = 0;
|
|
||||||
for (int y = 0; y < cell_count; y += stride) {
|
|
||||||
for (int x = 0; x < cell_count; x += stride) {
|
|
||||||
int base = y * edge_vertex_count + x;
|
|
||||||
indices[idx++] = base;
|
|
||||||
indices[idx++] = base + edge_vertex_count * stride;
|
|
||||||
indices[idx++] = base + stride;
|
|
||||||
indices[idx++] = base + stride;
|
|
||||||
indices[idx++] = base + edge_vertex_count * stride;
|
|
||||||
indices[idx++] = base + edge_vertex_count * stride + stride;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Vertex getVertex(int position) {
|
|
||||||
assert(position >= 0 and position < vertex_count);
|
|
||||||
|
|
||||||
return vertices[position];
|
|
||||||
}
|
|
||||||
|
|
||||||
Vertex getVertexByIndex(unsigned short index) {
|
|
||||||
assert(index >= 0 and index < index_count);
|
|
||||||
|
|
||||||
return getVertex(indices[index]);
|
|
||||||
}
|
|
||||||
|
|
||||||
Vertex getGridVertex(int edge_vertex_count, int x, int y) {
|
|
||||||
return getVertex(y * edge_vertex_count + x);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned short getIndex(int position) {
|
|
||||||
assert(position >= 0 and position < index_count);
|
|
||||||
|
|
||||||
return indices[position];
|
|
||||||
}
|
|
||||||
|
|
||||||
void render(QOpenGLShaderProgram *program, OpenGLFunctions *functions) {
|
|
||||||
size_t ptr = (size_t)vertices;
|
|
||||||
|
|
||||||
GLuint vertex = program->attributeLocation("vertex");
|
|
||||||
program->setAttributeArray(vertex, GL_FLOAT, (void *)(ptr + offsetof(Vertex, location)), 3, sizeof(Vertex));
|
|
||||||
program->enableAttributeArray(vertex);
|
|
||||||
|
|
||||||
GLuint uv = program->attributeLocation("uv");
|
|
||||||
program->setAttributeArray(uv, GL_FLOAT, (void *)(ptr + offsetof(Vertex, uv)), 2, sizeof(Vertex));
|
|
||||||
program->enableAttributeArray(uv);
|
|
||||||
|
|
||||||
functions->glDrawRangeElements(GL_TRIANGLES, 0, vertex_count - 1, index_count, GL_UNSIGNED_SHORT, indices);
|
|
||||||
|
|
||||||
program->disableAttributeArray(vertex);
|
|
||||||
program->disableAttributeArray(uv);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool ready;
|
|
||||||
bool changed;
|
|
||||||
|
|
||||||
int vertex_count;
|
|
||||||
Vertex *vertices;
|
|
||||||
|
|
||||||
int index_count;
|
|
||||||
unsigned short *indices;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // VERTEXARRAY_H
|
|
|
@ -16,17 +16,20 @@ class OpenGLRenderer;
|
||||||
class OpenGLShaderProgram;
|
class OpenGLShaderProgram;
|
||||||
class OpenGLSharedState;
|
class OpenGLSharedState;
|
||||||
class OpenGLVariable;
|
class OpenGLVariable;
|
||||||
|
class OpenGLVertexArray;
|
||||||
class OpenGLSkybox;
|
class OpenGLSkybox;
|
||||||
class OpenGLWater;
|
class OpenGLWater;
|
||||||
class OpenGLTerrain;
|
class OpenGLTerrain;
|
||||||
class ExplorerChunkTerrain;
|
class OpenGLTerrainChunk;
|
||||||
template <typename Vertex> class VertexArray;
|
template <typename Vertex> class VertexArray;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
using namespace paysages::opengl;
|
using namespace paysages::opengl;
|
||||||
|
|
||||||
#define OpenGLFunctions QOpenGLFunctions_3_0
|
#define OpenGLFunctions QOpenGLFunctions_3_3_Core
|
||||||
//#define OpenGLFunctions QOpenGLFunctions_3_3_Core
|
#define OPENGL_GLSL_VERSION "330 core"
|
||||||
|
#define OPENGL_MAJOR_VERSION 3
|
||||||
|
#define OPENGL_MINOR_VERSION 3
|
||||||
class OpenGLFunctions;
|
class OpenGLFunctions;
|
||||||
|
|
||||||
#endif // OPENGL_GLOBAL_H
|
#endif // OPENGL_GLOBAL_H
|
||||||
|
|
|
@ -29,7 +29,7 @@ uniform vec4 sunColor;
|
||||||
uniform float dayTime;
|
uniform float dayTime;
|
||||||
uniform float sunRadius;
|
uniform float sunRadius;
|
||||||
|
|
||||||
varying vec3 unprojected;
|
in vec3 unprojected;
|
||||||
|
|
||||||
uniform sampler2D transmittanceTexture;
|
uniform sampler2D transmittanceTexture;
|
||||||
uniform sampler3D inscatterTexture;
|
uniform sampler3D inscatterTexture;
|
||||||
|
@ -48,8 +48,8 @@ vec4 texture4D(sampler3D tex, float r, float mu, float muS, float nu)
|
||||||
|
|
||||||
float sr = 1.0 / float(RES_R);
|
float sr = 1.0 / float(RES_R);
|
||||||
int br = int(floor(uR / sr));
|
int br = int(floor(uR / sr));
|
||||||
vec4 r1 = texture3D(tex, vec3(uMu, uMuS, float(br) * sr + nu * sr));
|
vec4 r1 = texture(tex, vec3(uMu, uMuS, float(br) * sr + nu * sr));
|
||||||
vec4 r2 = texture3D(tex, vec3(uMu, uMuS, float(br + 1) * sr + nu * sr));
|
vec4 r2 = texture(tex, vec3(uMu, uMuS, float(br + 1) * sr + nu * sr));
|
||||||
return mix(r1, r2, (uR - float(br) * sr) / sr);
|
return mix(r1, r2, (uR - float(br) * sr) / sr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@ vec2 _getTransmittanceUV(float r, float mu)
|
||||||
vec4 _transmittance(float r, float mu)
|
vec4 _transmittance(float r, float mu)
|
||||||
{
|
{
|
||||||
vec2 uv = _getTransmittanceUV(r, mu);
|
vec2 uv = _getTransmittanceUV(r, mu);
|
||||||
return texture2D(transmittanceTexture, uv);
|
return texture(transmittanceTexture, uv);
|
||||||
}
|
}
|
||||||
|
|
||||||
vec4 _transmittanceWithShadow(float r, float mu)
|
vec4 _transmittanceWithShadow(float r, float mu)
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
|
out vec4 final_color;
|
||||||
|
|
||||||
void main(void)
|
void main(void)
|
||||||
{
|
{
|
||||||
gl_FragColor = getSkyColor(cameraLocation, unprojected - cameraLocation);
|
final_color = getSkyColor(cameraLocation, unprojected - cameraLocation);
|
||||||
gl_FragColor = applyToneMapping(gl_FragColor);
|
final_color = applyToneMapping(final_color);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
attribute highp vec4 vertex;
|
in highp vec4 vertex;
|
||||||
uniform highp mat4 viewMatrix;
|
uniform highp mat4 viewMatrix;
|
||||||
uniform vec3 cameraLocation;
|
uniform vec3 cameraLocation;
|
||||||
varying vec3 unprojected;
|
out vec3 unprojected;
|
||||||
|
|
||||||
void main(void)
|
void main(void)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
uniform sampler2D groundTexture;
|
uniform sampler2D groundTexture;
|
||||||
varying vec2 texcoord;
|
in vec2 texcoord;
|
||||||
|
out vec4 final_color;
|
||||||
|
|
||||||
void main(void)
|
void main(void)
|
||||||
{
|
{
|
||||||
gl_FragColor = texture2D(groundTexture, texcoord);
|
final_color = texture(groundTexture, texcoord);
|
||||||
|
|
||||||
gl_FragColor = applyAerialPerspective(gl_FragColor);
|
final_color = applyAerialPerspective(final_color);
|
||||||
|
|
||||||
gl_FragColor = applyToneMapping(gl_FragColor);
|
final_color = applyToneMapping(final_color);
|
||||||
|
|
||||||
gl_FragColor = applyMouseTracking(unprojected, gl_FragColor);
|
final_color = applyMouseTracking(unprojected, final_color);
|
||||||
|
|
||||||
gl_FragColor.a = distanceFadeout();
|
final_color.a = distanceFadeout();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
attribute highp vec4 vertex;
|
in highp vec4 vertex;
|
||||||
attribute highp vec2 uv;
|
in highp vec2 uv;
|
||||||
uniform highp mat4 viewMatrix;
|
uniform highp mat4 viewMatrix;
|
||||||
varying vec3 unprojected;
|
out vec3 unprojected;
|
||||||
varying vec2 texcoord;
|
out vec2 texcoord;
|
||||||
uniform float waterOffset;
|
uniform float waterOffset;
|
||||||
|
|
||||||
void main(void)
|
void main(void)
|
||||||
|
|
|
@ -3,22 +3,23 @@ uniform float waterMaterialReflection;
|
||||||
uniform float waterMaterialShininess;
|
uniform float waterMaterialShininess;
|
||||||
uniform float waterMaterialHardness;
|
uniform float waterMaterialHardness;
|
||||||
uniform float waterReflection;
|
uniform float waterReflection;
|
||||||
|
out vec4 final_color;
|
||||||
|
|
||||||
void main(void)
|
void main(void)
|
||||||
{
|
{
|
||||||
vec3 normal = noiseNormal2d(unprojected.xz, 0.001);
|
vec3 normal = noiseNormal2d(unprojected.xz, 0.001);
|
||||||
|
|
||||||
gl_FragColor = applyLighting(unprojected, normal, waterMaterialColor, waterMaterialReflection, waterMaterialShininess, waterMaterialHardness);
|
final_color = applyLighting(unprojected, normal, waterMaterialColor, waterMaterialReflection, waterMaterialShininess, waterMaterialHardness);
|
||||||
|
|
||||||
vec3 reflected = reflect(unprojected - cameraLocation, normal);
|
vec3 reflected = reflect(unprojected - cameraLocation, normal);
|
||||||
reflected.y = max(reflected.y, 0.0);
|
reflected.y = max(reflected.y, 0.0);
|
||||||
gl_FragColor += getSkyColor(unprojected, reflected) * waterReflection;
|
final_color += getSkyColor(unprojected, reflected) * waterReflection;
|
||||||
|
|
||||||
gl_FragColor = applyAerialPerspective(gl_FragColor);
|
final_color = applyAerialPerspective(final_color);
|
||||||
|
|
||||||
gl_FragColor = applyToneMapping(gl_FragColor);
|
final_color = applyToneMapping(final_color);
|
||||||
|
|
||||||
gl_FragColor = applyMouseTracking(unprojected, gl_FragColor);
|
final_color = applyMouseTracking(unprojected, final_color);
|
||||||
|
|
||||||
gl_FragColor.a = distanceFadeout();
|
final_color.a = distanceFadeout();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
attribute highp vec4 vertex;
|
in highp vec4 vertex;
|
||||||
uniform highp mat4 viewMatrix;
|
uniform highp mat4 viewMatrix;
|
||||||
uniform float waterHeight;
|
uniform float waterHeight;
|
||||||
uniform vec3 cameraLocation;
|
uniform vec3 cameraLocation;
|
||||||
varying vec3 unprojected;
|
out vec3 unprojected;
|
||||||
|
|
||||||
void main(void)
|
void main(void)
|
||||||
{
|
{
|
||||||
|
|
68
src/tests/OpenGLTerrainChunk_Test.cpp
Normal file
68
src/tests/OpenGLTerrainChunk_Test.cpp
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
#include "BaseTestCase.h"
|
||||||
|
#include "OpenGLTerrainChunk.h"
|
||||||
|
|
||||||
|
#include "Scenery.h"
|
||||||
|
#include "OpenGLRenderer.h"
|
||||||
|
#include "OpenGLVertexArray.h"
|
||||||
|
#include "Vector3.h"
|
||||||
|
|
||||||
|
static void checkVertex(const OpenGLVertexArray *array, int index, const Vector3 &expected_location, double expected_u, double expected_v) {
|
||||||
|
Vector3 location;
|
||||||
|
double u, v;
|
||||||
|
|
||||||
|
array->get(index, &location, &u, &v);
|
||||||
|
|
||||||
|
EXPECT_VECTOR3_COORDS(location, expected_location.x, expected_location.y, expected_location.z);
|
||||||
|
EXPECT_DOUBLE_EQ(expected_u, u);
|
||||||
|
EXPECT_DOUBLE_EQ(expected_v, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(OpenGLTerrainChunk, setFirstStepVertices) {
|
||||||
|
Scenery scenery;
|
||||||
|
OpenGLRenderer renderer(&scenery);
|
||||||
|
OpenGLTerrainChunk chunk(&renderer, 0.0, 0.0, 1.0, 1);
|
||||||
|
|
||||||
|
ASSERT_EQ(0, chunk.getVerticesLevel());
|
||||||
|
|
||||||
|
chunk.setFirstStepVertices();
|
||||||
|
|
||||||
|
EXPECT_EQ(1, chunk.getVerticesLevel());
|
||||||
|
ASSERT_EQ(6, chunk.getVertices()->getVertexCount());
|
||||||
|
const OpenGLVertexArray *array = chunk.getVertices();
|
||||||
|
checkVertex(array, 0, Vector3(0.0, 0.0, 0.0), 0.0, 0.0);
|
||||||
|
checkVertex(array, 1, Vector3(0.0, 0.0, 1.0), 0.0, 1.0);
|
||||||
|
checkVertex(array, 2, Vector3(1.0, 0.0, 0.0), 1.0, 0.0);
|
||||||
|
checkVertex(array, 3, Vector3(1.0, 0.0, 1.0), 1.0, 1.0);
|
||||||
|
checkVertex(array, 4, Vector3(1.0, 0.0, 0.0), 1.0, 0.0);
|
||||||
|
checkVertex(array, 5, Vector3(0.0, 0.0, 1.0), 0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(OpenGLTerrainChunk, augmentVertices) {
|
||||||
|
Scenery scenery;
|
||||||
|
OpenGLRenderer renderer(&scenery);
|
||||||
|
OpenGLTerrainChunk chunk(&renderer, 0.0, 0.0, 1.0, 1);
|
||||||
|
|
||||||
|
ASSERT_EQ(0, chunk.getVerticesLevel());
|
||||||
|
|
||||||
|
chunk.setFirstStepVertices();
|
||||||
|
|
||||||
|
ASSERT_EQ(1, chunk.getVerticesLevel());
|
||||||
|
|
||||||
|
chunk.augmentVertices();
|
||||||
|
|
||||||
|
ASSERT_EQ(2, chunk.getVerticesLevel());
|
||||||
|
EXPECT_EQ(24, chunk.getVertices()->getVertexCount());
|
||||||
|
const OpenGLVertexArray *array = chunk.getVertices();
|
||||||
|
checkVertex(array, 0, Vector3(0.0, 0.0, 0.0), 0.0, 0.0);
|
||||||
|
checkVertex(array, 1, Vector3(0.0, 0.0, 0.5), 0.0, 0.5);
|
||||||
|
checkVertex(array, 2, Vector3(0.5, 0.0, 0.0), 0.5, 0.0);
|
||||||
|
checkVertex(array, 3, Vector3(0.5, 0.0, 0.5), 0.5, 0.5);
|
||||||
|
checkVertex(array, 4, Vector3(0.5, 0.0, 0.0), 0.5, 0.0);
|
||||||
|
checkVertex(array, 5, Vector3(0.0, 0.0, 0.5), 0.0, 0.5);
|
||||||
|
checkVertex(array, 6, Vector3(0.5, 0.0, 0.0), 0.5, 0.0);
|
||||||
|
checkVertex(array, 7, Vector3(0.5, 0.0, 0.5), 0.5, 0.5);
|
||||||
|
checkVertex(array, 8, Vector3(1.0, 0.0, 0.0), 1.0, 0.0);
|
||||||
|
checkVertex(array, 9, Vector3(1.0, 0.0, 0.5), 1.0, 0.5);
|
||||||
|
checkVertex(array, 10, Vector3(1.0, 0.0, 0.0), 1.0, 0.0);
|
||||||
|
checkVertex(array, 11, Vector3(0.5, 0.0, 0.5), 0.5, 0.5);
|
||||||
|
}
|
|
@ -1,92 +0,0 @@
|
||||||
#include "BaseTestCase.h"
|
|
||||||
|
|
||||||
#include "VertexArray.h"
|
|
||||||
|
|
||||||
class TestVertex {
|
|
||||||
public:
|
|
||||||
float uv[2];
|
|
||||||
int loc[3];
|
|
||||||
|
|
||||||
bool operator==(const TestVertex &other) const {
|
|
||||||
return other.uv[0] == uv[0] and other.uv[1] == uv[1] and other.loc[0] == loc[0] and other.loc[1] == loc[1] and
|
|
||||||
other.loc[2] == loc[2];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST(VertexArray, grid) {
|
|
||||||
VertexArray<TestVertex> array;
|
|
||||||
|
|
||||||
array.setGridSize(3);
|
|
||||||
|
|
||||||
ASSERT_EQ(9, array.getVertexCount());
|
|
||||||
|
|
||||||
TestVertex v1 = {{0.1, 0.2}, {1, 2, 3}};
|
|
||||||
TestVertex vgot;
|
|
||||||
|
|
||||||
array.setGridVertex(3, 1, 2, v1);
|
|
||||||
vgot = array.getGridVertex(3, 1, 2);
|
|
||||||
EXPECT_EQ(v1, vgot);
|
|
||||||
vgot = array.getVertex(7);
|
|
||||||
EXPECT_EQ(v1, vgot);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(VertexArray, gridIndices) {
|
|
||||||
VertexArray<TestVertex> array;
|
|
||||||
|
|
||||||
array.setGridSize(3);
|
|
||||||
|
|
||||||
array.setAutoGridIndices(3);
|
|
||||||
ASSERT_EQ(24, array.getIndexCount());
|
|
||||||
|
|
||||||
EXPECT_EQ(0, array.getIndex(0));
|
|
||||||
EXPECT_EQ(3, array.getIndex(1));
|
|
||||||
EXPECT_EQ(1, array.getIndex(2));
|
|
||||||
|
|
||||||
EXPECT_EQ(1, array.getIndex(3));
|
|
||||||
EXPECT_EQ(3, array.getIndex(4));
|
|
||||||
EXPECT_EQ(4, array.getIndex(5));
|
|
||||||
|
|
||||||
EXPECT_EQ(1, array.getIndex(6));
|
|
||||||
EXPECT_EQ(4, array.getIndex(7));
|
|
||||||
EXPECT_EQ(2, array.getIndex(8));
|
|
||||||
|
|
||||||
EXPECT_EQ(2, array.getIndex(9));
|
|
||||||
EXPECT_EQ(4, array.getIndex(10));
|
|
||||||
EXPECT_EQ(5, array.getIndex(11));
|
|
||||||
|
|
||||||
EXPECT_EQ(3, array.getIndex(12));
|
|
||||||
EXPECT_EQ(6, array.getIndex(13));
|
|
||||||
EXPECT_EQ(4, array.getIndex(14));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(VertexArray, gridIndicesStride) {
|
|
||||||
VertexArray<TestVertex> array;
|
|
||||||
|
|
||||||
array.setGridSize(5);
|
|
||||||
|
|
||||||
array.setAutoGridIndices(5, 1);
|
|
||||||
ASSERT_EQ(96, array.getIndexCount());
|
|
||||||
|
|
||||||
array.setAutoGridIndices(5, 2);
|
|
||||||
ASSERT_EQ(24, array.getIndexCount());
|
|
||||||
|
|
||||||
EXPECT_EQ(0, array.getIndex(0));
|
|
||||||
EXPECT_EQ(10, array.getIndex(1));
|
|
||||||
EXPECT_EQ(2, array.getIndex(2));
|
|
||||||
|
|
||||||
EXPECT_EQ(2, array.getIndex(3));
|
|
||||||
EXPECT_EQ(10, array.getIndex(4));
|
|
||||||
EXPECT_EQ(12, array.getIndex(5));
|
|
||||||
|
|
||||||
EXPECT_EQ(2, array.getIndex(6));
|
|
||||||
EXPECT_EQ(12, array.getIndex(7));
|
|
||||||
EXPECT_EQ(4, array.getIndex(8));
|
|
||||||
|
|
||||||
EXPECT_EQ(4, array.getIndex(9));
|
|
||||||
EXPECT_EQ(12, array.getIndex(10));
|
|
||||||
EXPECT_EQ(14, array.getIndex(11));
|
|
||||||
|
|
||||||
EXPECT_EQ(10, array.getIndex(12));
|
|
||||||
EXPECT_EQ(20, array.getIndex(13));
|
|
||||||
EXPECT_EQ(12, array.getIndex(14));
|
|
||||||
}
|
|
Loading…
Reference in a new issue