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
|
||||
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
|
||||
|
||||
package:build
|
||||
|
|
3
TODO
3
TODO
|
@ -5,7 +5,8 @@ Technlology Preview 2 :
|
|||
- Add clouds to OpenGL with 3d textures.
|
||||
- Refactor medium traversal to unify clouds, atmosphere and god rays.
|
||||
- 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 :
|
||||
- Alter aerial perspective using estimation of the amount of light left after cloud layers traversal.
|
||||
|
|
|
@ -16,10 +16,10 @@
|
|||
#include <QGuiApplication>
|
||||
|
||||
MainModelerWindow::MainModelerWindow() {
|
||||
/*QSurfaceFormat new_format = format();
|
||||
new_format.setVersion(3, 3);
|
||||
QSurfaceFormat new_format = format();
|
||||
new_format.setVersion(OPENGL_MAJOR_VERSION, OPENGL_MINOR_VERSION);
|
||||
new_format.setProfile(QSurfaceFormat::CoreProfile);
|
||||
setFormat(new_format);*/
|
||||
setFormat(new_format);
|
||||
|
||||
scenery = new Scenery();
|
||||
scenery->autoPreset();
|
||||
|
|
|
@ -52,8 +52,8 @@ void OpenGLView::paint() {
|
|||
resized = false;
|
||||
}
|
||||
|
||||
renderer->prepareOpenGLState();
|
||||
renderer->paint();
|
||||
renderer->prepareOpenGLState(false);
|
||||
renderer->paint(false);
|
||||
|
||||
if (window) {
|
||||
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 <QDir>
|
||||
#include <cmath>
|
||||
#include "OpenGLRenderer.h"
|
||||
#include "OpenGLShaderProgram.h"
|
||||
#include "CameraDefinition.h"
|
||||
#include "AtmosphereDefinition.h"
|
||||
#include "AtmosphereRenderer.h"
|
||||
#include "Scenery.h"
|
||||
#include "OpenGLVertexArray.h"
|
||||
|
||||
OpenGLPart::OpenGLPart(OpenGLRenderer *renderer) : renderer(renderer) {
|
||||
}
|
||||
|
||||
OpenGLPart::~OpenGLPart() {
|
||||
QMapIterator<QString, OpenGLShaderProgram *> i(shaders);
|
||||
while (i.hasNext()) {
|
||||
i.next();
|
||||
delete i.value();
|
||||
for (auto &pair: shaders) {
|
||||
delete pair.second;
|
||||
}
|
||||
for (auto &array: arrays) {
|
||||
delete array;
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLPart::interrupt() {
|
||||
}
|
||||
|
||||
OpenGLShaderProgram *OpenGLPart::createShader(QString name) {
|
||||
OpenGLShaderProgram *program = new OpenGLShaderProgram(name.toStdString(), renderer);
|
||||
OpenGLShaderProgram *OpenGLPart::createShader(const std::string &name) {
|
||||
OpenGLShaderProgram *program = new OpenGLShaderProgram(name, renderer);
|
||||
|
||||
if (!shaders.contains(name)) {
|
||||
if (shaders.find(name) == shaders.end()) {
|
||||
shaders[name] = program;
|
||||
return program;
|
||||
} 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) {
|
||||
// Let subclass do its own collecting
|
||||
if (not onlyCommon) {
|
||||
|
|
|
@ -3,14 +3,15 @@
|
|||
|
||||
#include "opengl_global.h"
|
||||
|
||||
#include <QMap>
|
||||
#include <QString>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
namespace paysages {
|
||||
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 {
|
||||
public:
|
||||
OpenGLPart(OpenGLRenderer *renderer);
|
||||
|
@ -31,14 +32,26 @@ class OPENGLSHARED_EXPORT OpenGLPart {
|
|||
void updateScenery(bool onlyCommon = false);
|
||||
|
||||
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
|
||||
OpenGLRenderer *renderer;
|
||||
|
||||
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) {
|
||||
functions->glDisable(GL_LIGHTING);
|
||||
|
||||
functions->glFrontFace(GL_CCW);
|
||||
functions->glCullFace(GL_BACK);
|
||||
functions->glEnable(GL_CULL_FACE);
|
||||
|
@ -110,16 +108,16 @@ void OpenGLRenderer::prepareOpenGLState() {
|
|||
functions->glEnable(GL_DEPTH_TEST);
|
||||
|
||||
functions->glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
functions->glEnable(GL_LINE_SMOOTH);
|
||||
functions->glLineWidth(1.0);
|
||||
|
||||
functions->glDisable(GL_FOG);
|
||||
/*functions->glEnable(GL_LINE_SMOOTH);
|
||||
functions->glLineWidth(1.0);*/
|
||||
|
||||
functions->glEnable(GL_BLEND);
|
||||
functions->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -146,10 +144,12 @@ void OpenGLRenderer::resize(int width, int height) {
|
|||
}
|
||||
}
|
||||
|
||||
void OpenGLRenderer::paint() {
|
||||
void OpenGLRenderer::paint(bool clear) {
|
||||
if (ready and not paused) {
|
||||
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();
|
||||
checkForErrors("skybox");
|
||||
|
|
|
@ -39,9 +39,9 @@ class OPENGLSHARED_EXPORT OpenGLRenderer : public SoftwareRenderer {
|
|||
void checkForErrors(const std::string &domain);
|
||||
|
||||
void initialize();
|
||||
void prepareOpenGLState();
|
||||
void prepareOpenGLState(bool clear=true);
|
||||
void resize(int width, int height);
|
||||
void paint();
|
||||
void paint(bool clear=true);
|
||||
|
||||
/**
|
||||
* Reset the whole state (when the scenery has been massively updated).
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "OpenGLFunctions.h"
|
||||
#include "OpenGLRenderer.h"
|
||||
#include "OpenGLSharedState.h"
|
||||
#include "OpenGLVertexArray.h"
|
||||
#include "Texture2D.h"
|
||||
#include "Texture3D.h"
|
||||
#include "Texture4D.h"
|
||||
|
@ -22,8 +23,8 @@ OpenGLShaderProgram::~OpenGLShaderProgram() {
|
|||
delete program;
|
||||
}
|
||||
|
||||
void OpenGLShaderProgram::addVertexSource(QString path) {
|
||||
QFile file(QString(":/shaders/%1.vert").arg(path));
|
||||
void OpenGLShaderProgram::addVertexSource(const std::string &path) {
|
||||
QFile file(QString(":/shaders/%1.vert").arg(QString::fromStdString(path)));
|
||||
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
source_vertex += QString(file.readAll()).toStdString();
|
||||
} else {
|
||||
|
@ -31,8 +32,8 @@ void OpenGLShaderProgram::addVertexSource(QString path) {
|
|||
}
|
||||
}
|
||||
|
||||
void OpenGLShaderProgram::addFragmentSource(QString path) {
|
||||
QFile file(QString(":/shaders/%1.frag").arg(path));
|
||||
void OpenGLShaderProgram::addFragmentSource(const std::string &path) {
|
||||
QFile file(QString(":/shaders/%1.frag").arg(QString::fromStdString(path)));
|
||||
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
source_fragment += QString(file.readAll()).toStdString();
|
||||
} else {
|
||||
|
@ -41,8 +42,13 @@ void OpenGLShaderProgram::addFragmentSource(QString path) {
|
|||
}
|
||||
|
||||
void OpenGLShaderProgram::compile() {
|
||||
program->addShaderFromSourceCode(QOpenGLShader::Vertex, QString::fromStdString(source_vertex));
|
||||
program->addShaderFromSourceCode(QOpenGLShader::Fragment, QString::fromStdString(source_fragment));
|
||||
std::string prefix = std::string("#version ") + OPENGL_GLSL_VERSION + "\n\n";
|
||||
|
||||
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()) {
|
||||
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) {
|
||||
compile();
|
||||
compiled = true;
|
||||
|
@ -64,6 +70,9 @@ bool OpenGLShaderProgram::bind() {
|
|||
if (program->bind()) {
|
||||
int texture_unit = 0;
|
||||
renderer->getSharedState()->apply(this, texture_unit);
|
||||
if (state) {
|
||||
state->apply(this, texture_unit);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
|
@ -74,29 +83,9 @@ void OpenGLShaderProgram::release() {
|
|||
program->release();
|
||||
}
|
||||
|
||||
void OpenGLShaderProgram::drawTriangles(float *vertices, int triangle_count) {
|
||||
if (bind()) {
|
||||
GLuint vertex = program->attributeLocation("vertex");
|
||||
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);
|
||||
void OpenGLShaderProgram::draw(OpenGLVertexArray *vertices, OpenGLSharedState *state) {
|
||||
if (bind(state)) {
|
||||
vertices->render(functions);
|
||||
|
||||
release();
|
||||
}
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
|
||||
#include "opengl_global.h"
|
||||
|
||||
#include <QString>
|
||||
|
||||
class QOpenGLShaderProgram;
|
||||
|
||||
namespace paysages {
|
||||
|
@ -15,18 +13,25 @@ class OPENGLSHARED_EXPORT OpenGLShaderProgram {
|
|||
OpenGLShaderProgram(const std::string &name, OpenGLRenderer *renderer);
|
||||
~OpenGLShaderProgram();
|
||||
|
||||
void addVertexSource(QString path);
|
||||
void addFragmentSource(QString path);
|
||||
void addVertexSource(const std::string &path);
|
||||
void addFragmentSource(const std::string &path);
|
||||
|
||||
void drawTriangles(float *vertices, int triangle_count);
|
||||
void drawTriangleStrip(float *vertices, int vertex_count);
|
||||
|
||||
bool bind();
|
||||
void release();
|
||||
/**
|
||||
* Draw a VertexArray object.
|
||||
*
|
||||
* This will bind the program (compile it if needed), set the uniform variables, and
|
||||
* 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 {
|
||||
return program;
|
||||
}
|
||||
inline OpenGLFunctions *getFunctions() const {
|
||||
return functions;
|
||||
}
|
||||
inline OpenGLRenderer *getRenderer() const {
|
||||
return renderer;
|
||||
}
|
||||
|
@ -35,6 +40,8 @@ class OPENGLSHARED_EXPORT OpenGLShaderProgram {
|
|||
friend class OpenGLVariable;
|
||||
|
||||
private:
|
||||
bool bind(OpenGLSharedState *state = NULL);
|
||||
void release();
|
||||
void compile();
|
||||
|
||||
bool compiled;
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
#include <map>
|
||||
#include "OpenGLVariable.h"
|
||||
|
||||
class QImage;
|
||||
|
||||
namespace paysages {
|
||||
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) {
|
||||
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) {
|
||||
get(name)->set(texture, repeat, color);
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "OpenGLRenderer.h"
|
||||
#include "OpenGLShaderProgram.h"
|
||||
#include "OpenGLSharedState.h"
|
||||
#include "OpenGLVertexArray.h"
|
||||
#include "Scenery.h"
|
||||
#include "AtmosphereDefinition.h"
|
||||
#include "AtmosphereRenderer.h"
|
||||
|
@ -11,42 +12,43 @@
|
|||
#include "FloatNode.h"
|
||||
|
||||
OpenGLSkybox::OpenGLSkybox(OpenGLRenderer *renderer) : OpenGLPart(renderer) {
|
||||
vertices = new float[14 * 3];
|
||||
}
|
||||
|
||||
OpenGLSkybox::~OpenGLSkybox() {
|
||||
delete[] vertices;
|
||||
}
|
||||
|
||||
void OpenGLSkybox::initialize() {
|
||||
program = createShader("skybox");
|
||||
program->addVertexSource("skybox");
|
||||
program->addFragmentSource("atmosphere");
|
||||
program->addFragmentSource("tonemapping");
|
||||
program->addFragmentSource("skybox");
|
||||
|
||||
setVertex(0, 1.0f, 1.0f, 1.0f);
|
||||
setVertex(12, 1.0f, 1.0f, 1.0f);
|
||||
vertices = createVertexArray(false, true);
|
||||
|
||||
setVertex(1, 1.0f, -1.0f, 1.0f);
|
||||
setVertex(5, 1.0f, -1.0f, 1.0f);
|
||||
setVertex(13, 1.0f, -1.0f, 1.0f);
|
||||
vertices->setVertexCount(14);
|
||||
|
||||
setVertex(2, -1.0f, 1.0f, 1.0f);
|
||||
setVertex(10, -1.0f, 1.0f, 1.0f);
|
||||
vertices->set(0, Vector3(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);
|
||||
setVertex(8, -1.0f, -1.0f, -1.0f);
|
||||
vertices->set(2, Vector3(-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);
|
||||
setVertex(11, 1.0f, 1.0f, -1.0f);
|
||||
vertices->set(4, Vector3(-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
|
||||
renderer->getScenery()->getAtmosphere()->propDayTime()->addWatcher(this, true);
|
||||
renderer->getScenery()->getAtmosphere()->propHumidity()->addWatcher(this, true);
|
||||
|
@ -61,7 +63,7 @@ void OpenGLSkybox::update() {
|
|||
}
|
||||
|
||||
void OpenGLSkybox::render() {
|
||||
program->drawTriangleStrip(vertices, 14);
|
||||
program->draw(vertices);
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
private:
|
||||
void setVertex(int i, float x, float y, float z);
|
||||
|
||||
OpenGLShaderProgram *program;
|
||||
float *vertices;
|
||||
OpenGLVertexArray *vertices;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include "OpenGLShaderProgram.h"
|
||||
#include "ParallelPool.h"
|
||||
#include "Thread.h"
|
||||
#include "ExplorerChunkTerrain.h"
|
||||
#include "OpenGLTerrainChunk.h"
|
||||
#include "WaterRenderer.h"
|
||||
#include "CameraDefinition.h"
|
||||
#include "AtmosphereDefinition.h"
|
||||
|
@ -35,6 +35,14 @@ class ChunkMaintenanceThreads : public ParallelPool {
|
|||
OpenGLTerrain::OpenGLTerrain(OpenGLRenderer *renderer) : OpenGLPart(renderer) {
|
||||
work = new ChunkMaintenanceThreads(this);
|
||||
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() {
|
||||
|
@ -46,15 +54,6 @@ OpenGLTerrain::~OpenGLTerrain() {
|
|||
}
|
||||
|
||||
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
|
||||
int chunks = 12;
|
||||
double size = 800.0;
|
||||
|
@ -62,7 +61,7 @@ void OpenGLTerrain::initialize() {
|
|||
double start = -size / 2.0;
|
||||
for (int i = 0; i < chunks; i++) {
|
||||
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);
|
||||
_chunks.append(chunk);
|
||||
_updateQueue.append(chunk);
|
||||
|
@ -84,13 +83,9 @@ void OpenGLTerrain::update() {
|
|||
}
|
||||
|
||||
void OpenGLTerrain::render() {
|
||||
program->bind();
|
||||
|
||||
for (int i = 0; i < _chunks.count(); i++) {
|
||||
_chunks[i]->render(program->getProgram(), renderer->getOpenGlFunctions());
|
||||
_chunks[i]->render(program);
|
||||
}
|
||||
|
||||
program->release();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void OpenGLTerrain::performChunksMaintenance() {
|
||||
CameraDefinition *camera = renderer->getScenery()->getCamera();
|
||||
ExplorerChunkTerrain *chunk;
|
||||
OpenGLTerrainChunk *chunk;
|
||||
|
||||
_lock_chunks.lock();
|
||||
if (_updateQueue.count() > 0) {
|
||||
|
|
|
@ -44,8 +44,8 @@ class OPENGLSHARED_EXPORT OpenGLTerrain : public OpenGLPart, public DefinitionWa
|
|||
ParallelPool *work;
|
||||
bool paused;
|
||||
|
||||
QVector<ExplorerChunkTerrain *> _chunks;
|
||||
QList<ExplorerChunkTerrain *> _updateQueue;
|
||||
QVector<OpenGLTerrainChunk *> _chunks;
|
||||
QList<OpenGLTerrainChunk *> _updateQueue;
|
||||
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 <QOpenGLShaderProgram>
|
||||
#include <cassert>
|
||||
#include <QOpenGLShaderProgram>
|
||||
#include <QColor>
|
||||
#include <QVector3D>
|
||||
#include <QMatrix4x4>
|
||||
#include <QImage>
|
||||
#include "Logs.h"
|
||||
#include "OpenGLFunctions.h"
|
||||
#include "OpenGLRenderer.h"
|
||||
#include "OpenGLShaderProgram.h"
|
||||
|
@ -16,6 +21,22 @@ OpenGLVariable::OpenGLVariable(const std::string &name) : name(name) {
|
|||
type = TYPE_NONE;
|
||||
texture_toupload = false;
|
||||
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) {
|
||||
|
@ -32,13 +53,13 @@ void OpenGLVariable::apply(OpenGLShaderProgram *program, int &texture_unit) {
|
|||
pr->setUniformValue(name.c_str(), value_float);
|
||||
break;
|
||||
case TYPE_COLOR:
|
||||
pr->setUniformValue(name.c_str(), value_color);
|
||||
pr->setUniformValue(name.c_str(), *value_color);
|
||||
break;
|
||||
case TYPE_VECTOR3:
|
||||
pr->setUniformValue(name.c_str(), value_vector3);
|
||||
pr->setUniformValue(name.c_str(), *value_vector3);
|
||||
break;
|
||||
case TYPE_MATRIX4:
|
||||
pr->setUniformValue(name.c_str(), value_matrix4);
|
||||
pr->setUniformValue(name.c_str(), *value_matrix4);
|
||||
break;
|
||||
case TYPE_TEXTURE_2D:
|
||||
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);
|
||||
|
||||
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_repeat = repeat;
|
||||
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) {
|
||||
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;
|
||||
value_tex3d = texture;
|
||||
texture_toupload = true;
|
||||
texture_repeat = repeat;
|
||||
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) {
|
||||
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;
|
||||
value_tex4d = texture;
|
||||
texture_toupload = true;
|
||||
texture_repeat = repeat;
|
||||
texture_color = color;
|
||||
|
@ -103,7 +226,7 @@ void OpenGLVariable::set(const QVector3D &vector) {
|
|||
assert(type == TYPE_NONE or type == TYPE_VECTOR3);
|
||||
|
||||
type = TYPE_VECTOR3;
|
||||
value_vector3 = vector;
|
||||
*value_vector3 = vector;
|
||||
}
|
||||
|
||||
void OpenGLVariable::set(const Matrix4 &matrix) {
|
||||
|
@ -114,14 +237,14 @@ void OpenGLVariable::set(const QMatrix4x4 &matrix) {
|
|||
assert(type == TYPE_NONE or type == TYPE_MATRIX4);
|
||||
|
||||
type = TYPE_MATRIX4;
|
||||
value_matrix4 = matrix;
|
||||
*value_matrix4 = matrix;
|
||||
}
|
||||
|
||||
void OpenGLVariable::set(const Color &color) {
|
||||
assert(type == TYPE_NONE or 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) {
|
||||
|
@ -149,61 +272,8 @@ void OpenGLVariable::uploadTexture(OpenGLRenderer *renderer) {
|
|||
int dest_format = texture_color ? GL_RGBA : GL_RED;
|
||||
|
||||
if (type == TYPE_TEXTURE_2D) {
|
||||
int sx, sy;
|
||||
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;
|
||||
functions->glTexImage2D(GL_TEXTURE_2D, 0, dest_format, texture_size_x, texture_size_y, 0, GL_RGBA, GL_FLOAT, value_texture_data);
|
||||
} else {
|
||||
int sx, sy, sz, sw;
|
||||
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;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,9 +3,10 @@
|
|||
|
||||
#include "opengl_global.h"
|
||||
|
||||
#include <QColor>
|
||||
#include <QVector3D>
|
||||
#include <QMatrix4x4>
|
||||
class QColor;
|
||||
class QVector3D;
|
||||
class QMatrix4x4;
|
||||
class QImage;
|
||||
|
||||
namespace paysages {
|
||||
namespace opengl {
|
||||
|
@ -28,10 +29,12 @@ class OpenGLVariable {
|
|||
|
||||
public:
|
||||
OpenGLVariable(const std::string &name);
|
||||
~OpenGLVariable();
|
||||
|
||||
void apply(OpenGLShaderProgram *program, int &texture_unit);
|
||||
|
||||
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 Texture4D *texture, bool repeat = false, bool color = true);
|
||||
void set(float value);
|
||||
|
@ -49,13 +52,14 @@ class OpenGLVariable {
|
|||
OpenGLVariableType type;
|
||||
|
||||
float value_float;
|
||||
QColor value_color;
|
||||
QVector3D value_vector3;
|
||||
QMatrix4x4 value_matrix4;
|
||||
const Texture2D *value_tex2d;
|
||||
const Texture3D *value_tex3d;
|
||||
const Texture4D *value_tex4d;
|
||||
QColor *value_color;
|
||||
QVector3D *value_vector3;
|
||||
QMatrix4x4 *value_matrix4;
|
||||
float *value_texture_data;
|
||||
|
||||
int texture_size_x;
|
||||
int texture_size_y;
|
||||
int texture_size_z;
|
||||
bool texture_toupload;
|
||||
bool texture_repeat;
|
||||
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 "OpenGLShaderProgram.h"
|
||||
#include "OpenGLSharedState.h"
|
||||
#include "OpenGLVertexArray.h"
|
||||
#include "WaterRenderer.h"
|
||||
#include "Scenery.h"
|
||||
#include "WaterDefinition.h"
|
||||
|
@ -13,15 +14,8 @@
|
|||
#include "IntNode.h"
|
||||
|
||||
OpenGLWater::OpenGLWater(OpenGLRenderer *renderer) : OpenGLPart(renderer) {
|
||||
vertices = new float[4 * 3];
|
||||
enabled = true;
|
||||
}
|
||||
|
||||
OpenGLWater::~OpenGLWater() {
|
||||
delete[] vertices;
|
||||
}
|
||||
|
||||
void OpenGLWater::initialize() {
|
||||
program = createShader("water");
|
||||
program->addVertexSource("water");
|
||||
program->addFragmentSource("atmosphere");
|
||||
|
@ -31,11 +25,18 @@ void OpenGLWater::initialize() {
|
|||
program->addFragmentSource("noise");
|
||||
program->addFragmentSource("water");
|
||||
|
||||
setVertex(0, -1.0f, 0.0f, -1.0f);
|
||||
setVertex(1, -1.0f, 0.0f, 1.0f);
|
||||
setVertex(2, 1.0f, 0.0f, -1.0f);
|
||||
setVertex(3, 1.0f, 0.0f, 1.0f);
|
||||
vertices = createVertexArray(false, true);
|
||||
vertices->setVertexCount(4);
|
||||
vertices->set(0, Vector3(-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
|
||||
renderer->getScenery()->getTerrain()->propWaterHeight()->addWatcher(this, true);
|
||||
renderer->getScenery()->getWater()->propReflection()->addWatcher(this, true);
|
||||
|
@ -54,16 +55,10 @@ void OpenGLWater::update() {
|
|||
|
||||
void OpenGLWater::render() {
|
||||
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 *) {
|
||||
if (node->getPath() == "/terrain/water_height") {
|
||||
renderer->getSharedState()->set("waterOffset", renderer->getScenery()->getTerrain()->getWaterOffset());
|
||||
|
|
|
@ -26,11 +26,9 @@ class OPENGLSHARED_EXPORT OpenGLWater : public OpenGLPart, public DefinitionWatc
|
|||
void setEnabled(bool enabled);
|
||||
|
||||
private:
|
||||
void setVertex(int i, float x, float y, float z);
|
||||
|
||||
bool enabled;
|
||||
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 OpenGLSharedState;
|
||||
class OpenGLVariable;
|
||||
class OpenGLVertexArray;
|
||||
class OpenGLSkybox;
|
||||
class OpenGLWater;
|
||||
class OpenGLTerrain;
|
||||
class ExplorerChunkTerrain;
|
||||
class OpenGLTerrainChunk;
|
||||
template <typename Vertex> class VertexArray;
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
||||
#endif // OPENGL_GLOBAL_H
|
||||
|
|
|
@ -29,7 +29,7 @@ uniform vec4 sunColor;
|
|||
uniform float dayTime;
|
||||
uniform float sunRadius;
|
||||
|
||||
varying vec3 unprojected;
|
||||
in vec3 unprojected;
|
||||
|
||||
uniform sampler2D transmittanceTexture;
|
||||
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);
|
||||
int br = int(floor(uR / sr));
|
||||
vec4 r1 = texture3D(tex, vec3(uMu, uMuS, float(br) * sr + nu * sr));
|
||||
vec4 r2 = texture3D(tex, vec3(uMu, uMuS, float(br + 1) * sr + nu * sr));
|
||||
vec4 r1 = texture(tex, vec3(uMu, uMuS, float(br) * 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);
|
||||
}
|
||||
|
||||
|
@ -77,7 +77,7 @@ vec2 _getTransmittanceUV(float r, float mu)
|
|||
vec4 _transmittance(float r, float mu)
|
||||
{
|
||||
vec2 uv = _getTransmittanceUV(r, mu);
|
||||
return texture2D(transmittanceTexture, uv);
|
||||
return texture(transmittanceTexture, uv);
|
||||
}
|
||||
|
||||
vec4 _transmittanceWithShadow(float r, float mu)
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
out vec4 final_color;
|
||||
|
||||
void main(void)
|
||||
{
|
||||
gl_FragColor = getSkyColor(cameraLocation, unprojected - cameraLocation);
|
||||
gl_FragColor = applyToneMapping(gl_FragColor);
|
||||
final_color = getSkyColor(cameraLocation, unprojected - cameraLocation);
|
||||
final_color = applyToneMapping(final_color);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
attribute highp vec4 vertex;
|
||||
in highp vec4 vertex;
|
||||
uniform highp mat4 viewMatrix;
|
||||
uniform vec3 cameraLocation;
|
||||
varying vec3 unprojected;
|
||||
out vec3 unprojected;
|
||||
|
||||
void main(void)
|
||||
{
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
uniform sampler2D groundTexture;
|
||||
varying vec2 texcoord;
|
||||
in vec2 texcoord;
|
||||
out vec4 final_color;
|
||||
|
||||
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;
|
||||
attribute highp vec2 uv;
|
||||
in highp vec4 vertex;
|
||||
in highp vec2 uv;
|
||||
uniform highp mat4 viewMatrix;
|
||||
varying vec3 unprojected;
|
||||
varying vec2 texcoord;
|
||||
out vec3 unprojected;
|
||||
out vec2 texcoord;
|
||||
uniform float waterOffset;
|
||||
|
||||
void main(void)
|
||||
|
|
|
@ -3,22 +3,23 @@ uniform float waterMaterialReflection;
|
|||
uniform float waterMaterialShininess;
|
||||
uniform float waterMaterialHardness;
|
||||
uniform float waterReflection;
|
||||
out vec4 final_color;
|
||||
|
||||
void main(void)
|
||||
{
|
||||
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);
|
||||
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 float waterHeight;
|
||||
uniform vec3 cameraLocation;
|
||||
varying vec3 unprojected;
|
||||
out vec3 unprojected;
|
||||
|
||||
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