From d88cb29f4c272149e766b1afd7d426e4a0f64e66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Lemaire?= Date: Wed, 23 Dec 2015 23:40:19 +0100 Subject: [PATCH] Refactored OpenGLVariable with pimpl and smart pointers --- src/basics/Matrix4.cpp | 7 +- src/basics/Matrix4.h | 57 ++- src/definition/CameraDefinition.cpp | 1 + src/interface/modeler/ModelerCameras.cpp | 7 +- src/render/opengl/OpenGLRenderer.cpp | 11 +- src/render/opengl/OpenGLShaderProgram.cpp | 15 +- src/render/opengl/OpenGLShaderProgram.h | 15 + src/render/opengl/OpenGLSharedState.cpp | 2 +- src/render/opengl/OpenGLSharedState.h | 10 +- src/render/opengl/OpenGLVariable.cpp | 353 +++++++++--------- src/render/opengl/OpenGLVariable.h | 47 +-- src/system/system_global.h | 1 + ...era_Test.cpp => CameraDefinition_Test.cpp} | 13 +- 13 files changed, 306 insertions(+), 233 deletions(-) rename src/tests/{Camera_Test.cpp => CameraDefinition_Test.cpp} (80%) diff --git a/src/basics/Matrix4.cpp b/src/basics/Matrix4.cpp index 69265cf..57c94df 100644 --- a/src/basics/Matrix4.cpp +++ b/src/basics/Matrix4.cpp @@ -10,6 +10,11 @@ Matrix4::Matrix4(bool identity) { a = f = k = p = (identity ? 1.0 : 0.0); } +Matrix4::Matrix4(double a, double b, double c, double d, double e, double f, double g, double h, double i, double j, + double k, double l, double m, double n, double o, double p) + : a(a), b(b), c(c), d(d), e(e), f(f), g(g), h(h), i(i), j(j), k(k), l(l), m(m), n(n), o(o), p(p) { +} + void Matrix4::save(PackStream *stream) const { stream->write(&a); stream->write(&b); @@ -221,7 +226,7 @@ Matrix4 Matrix4::newLookAt(const Vector3 &eye, const Vector3 &at, const Vector3 Matrix4 Matrix4::newPerspective(double fov_y, double aspect, double near, double far) { Matrix4 result; - double fo = 1 / tan(fov_y / 2.0); + double fo = 1.0 / tan(fov_y / 2.0); result.a = fo / aspect; result.f = fo; result.k = (far + near) / (near - far); diff --git a/src/basics/Matrix4.h b/src/basics/Matrix4.h index 5f185d1..db99193 100644 --- a/src/basics/Matrix4.h +++ b/src/basics/Matrix4.h @@ -3,16 +3,14 @@ #include "basics_global.h" -#ifdef QT_GUI_LIB -#include -#endif - namespace paysages { namespace basics { class BASICSSHARED_EXPORT Matrix4 { public: Matrix4(bool identity = true); + Matrix4(double a, double b, double c, double d, double e, double f, double g, double h, double i, double j, + double k, double l, double m, double n, double o, double p); void save(PackStream *stream) const; void load(PackStream *stream); @@ -36,11 +34,54 @@ class BASICSSHARED_EXPORT Matrix4 { double getDeterminant() const; -#ifdef QT_GUI_LIB - inline QMatrix4x4 toQMatrix() const { - return QMatrix4x4(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p); + inline double getA() const { + return a; + } + inline double getB() const { + return b; + } + inline double getC() const { + return c; + } + inline double getD() const { + return d; + } + inline double getE() const { + return e; + } + inline double getF() const { + return f; + } + inline double getG() const { + return g; + } + inline double getH() const { + return h; + } + inline double getI() const { + return i; + } + inline double getJ() const { + return j; + } + inline double getK() const { + return k; + } + inline double getL() const { + return l; + } + inline double getM() const { + return m; + } + inline double getN() const { + return n; + } + inline double getO() const { + return o; + } + inline double getP() const { + return p; } -#endif private: double a; diff --git a/src/definition/CameraDefinition.cpp b/src/definition/CameraDefinition.cpp index 33a35c4..7bb1bd2 100644 --- a/src/definition/CameraDefinition.cpp +++ b/src/definition/CameraDefinition.cpp @@ -249,6 +249,7 @@ bool CameraDefinition::transitionToAnother(const CameraDefinition *wanted, doubl dy = wanted->location.y - location.y; dz = wanted->location.z - location.z; dr = wanted->direction.r - direction.r; + // TODO pi-modulo nearest dphi = wanted->direction.phi - direction.phi; dtheta = wanted->direction.theta - direction.theta; droll = wanted->roll - roll; diff --git a/src/interface/modeler/ModelerCameras.cpp b/src/interface/modeler/ModelerCameras.cpp index 1b292d0..b8ffab5 100644 --- a/src/interface/modeler/ModelerCameras.cpp +++ b/src/interface/modeler/ModelerCameras.cpp @@ -73,9 +73,10 @@ void ModelerCameras::endTool() { } void ModelerCameras::timerEvent(QTimerEvent *) { - current->transitionToAnother(active, 0.5); - parent->getScenery()->keepCameraAboveGround(current); - parent->getRenderer()->setCamera(current); + if (current->transitionToAnother(active, 0.5)) { + parent->getScenery()->keepCameraAboveGround(current); + parent->getRenderer()->setCamera(current); + } } void ModelerCameras::nodeChanged(const DefinitionNode *node, const DefinitionDiff *) { diff --git a/src/render/opengl/OpenGLRenderer.cpp b/src/render/opengl/OpenGLRenderer.cpp index f1f5602..1962c69 100644 --- a/src/render/opengl/OpenGLRenderer.cpp +++ b/src/render/opengl/OpenGLRenderer.cpp @@ -1,5 +1,6 @@ #include "OpenGLRenderer.h" +#include #include "OpenGLFunctions.h" #include "CameraDefinition.h" #include "OpenGLSharedState.h" @@ -38,7 +39,7 @@ OpenGLRenderer::OpenGLRenderer(Scenery *scenery) : SoftwareRenderer(scenery) { shared_state = new OpenGLSharedState(); shared_state->set("viewDistance", 300.0); - shared_state->set("exposure", 1.2); + shared_state->set("exposure", to_float(1.2)); parts.push_back(skybox = new OpenGLSkybox(this)); parts.push_back(water = new OpenGLWater(this)); @@ -72,7 +73,7 @@ void OpenGLRenderer::prepare() { } void OpenGLRenderer::checkForErrors(const string &domain) { - int error_code; + unsigned int error_code; while ((error_code = functions->glGetError()) != GL_NO_ERROR) { Logs::warning("OpenGL") << "Error in " << domain << " : " << error_code << endl; } @@ -236,6 +237,7 @@ void OpenGLRenderer::cameraChangeEvent(CameraDefinition *camera) { CameraPerspective perspective = camera->getPerspective(); // Compute matrix + // TODO Switch to CameraDefinition raw transformation matrix (currently produces strange results) QMatrix4x4 transform; transform.setToIdentity(); transform.lookAt(QVector3D(location.x, location.y, location.z), QVector3D(target.x, target.y, target.z), @@ -249,7 +251,8 @@ void OpenGLRenderer::cameraChangeEvent(CameraDefinition *camera) { // Set in shaders shared_state->set("cameraLocation", location); - shared_state->set("viewMatrix", *view_matrix); + float *matdata = view_matrix->transposed().data(); + shared_state->set("viewMatrix", Matrix4(matdata[0], matdata[1], matdata[2], matdata[3], matdata[4], matdata[5], matdata[6], matdata[7], matdata[8], matdata[9], matdata[10], matdata[11], matdata[12], matdata[13], matdata[14], matdata[15])); // Broadcast to parts vegetation->cameraChanged(camera); @@ -267,7 +270,7 @@ void OpenGLRenderer::updateMouseProjection() { GLfloat z; functions->glReadPixels(mouse_x, mouse_y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &z); - QVector4D located(mouse_x / render_camera->getWidth(), mouse_y / render_camera->getHeight(), z, 1.0); + QVector4D located(to_float(mouse_x / render_camera->getWidth()), to_float(mouse_y / render_camera->getHeight()), z, 1.0); QVector4D unprojected = view_matrix->inverted() * 2.0 * (located - QVector4D(0.5, 0.5, 0.5, 0.5)); *mouse_projected = Vector3(unprojected.x() / unprojected.w(), unprojected.y() / unprojected.w(), unprojected.z() / unprojected.w()); diff --git a/src/render/opengl/OpenGLShaderProgram.cpp b/src/render/opengl/OpenGLShaderProgram.cpp index d6bc61f..541c9cc 100644 --- a/src/render/opengl/OpenGLShaderProgram.cpp +++ b/src/render/opengl/OpenGLShaderProgram.cpp @@ -18,6 +18,7 @@ OpenGLShaderProgram::OpenGLShaderProgram(const string &name, OpenGLRenderer *ren functions = renderer->getOpenGlFunctions(); state = new OpenGLSharedState(); compiled = false; + bound = false; } OpenGLShaderProgram::~OpenGLShaderProgram() { @@ -28,7 +29,7 @@ OpenGLShaderProgram::~OpenGLShaderProgram() { void OpenGLShaderProgram::addVertexSource(const 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(); + source_vertex += QString(file.readAll()).toStdString() + "\n"; } else { Logs::error("OpenGL") << "Can't open vertex file " << file.fileName().toStdString() << endl; } @@ -37,7 +38,7 @@ void OpenGLShaderProgram::addVertexSource(const string &path) { void OpenGLShaderProgram::addFragmentSource(const 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(); + source_fragment += QString(file.readAll()).toStdString() + "\n"; } else { Logs::error("OpenGL") << "Can't open fragment file " << file.fileName().toStdString() << endl; } @@ -74,11 +75,14 @@ bool OpenGLShaderProgram::bind(OpenGLSharedState *state) { } if (program->bind()) { - int texture_unit = 0; + bound = true; + + unsigned int texture_unit = 0; renderer->getSharedState()->apply(this, texture_unit); if (state) { state->apply(this, texture_unit); } + return true; } else { return false; @@ -86,6 +90,7 @@ bool OpenGLShaderProgram::bind(OpenGLSharedState *state) { } void OpenGLShaderProgram::release() { + bound = false; program->release(); } @@ -96,3 +101,7 @@ void OpenGLShaderProgram::draw(OpenGLVertexArray *vertices, OpenGLSharedState *s release(); } } + +unsigned int OpenGLShaderProgram::getId() const { + return program->programId(); +} diff --git a/src/render/opengl/OpenGLShaderProgram.h b/src/render/opengl/OpenGLShaderProgram.h index 35a0448..692ff09 100644 --- a/src/render/opengl/OpenGLShaderProgram.h +++ b/src/render/opengl/OpenGLShaderProgram.h @@ -33,6 +33,20 @@ class OPENGLSHARED_EXPORT OpenGLShaderProgram { */ void draw(OpenGLVertexArray *vertices, OpenGLSharedState *state = NULL, int start = 0, int count = -1); + /** + * Check if the program is currently bound to OpenGL context. + * + * This does not really check the OpenGL context, just check we are between bind() and release() calls. + */ + inline bool isBound() const { + return bound; + } + + /** + * Get the OpenGL ID for this program. + */ + unsigned int getId() const; + inline QOpenGLShaderProgram *getProgram() const { return program; } @@ -55,6 +69,7 @@ class OPENGLSHARED_EXPORT OpenGLShaderProgram { void compile(); bool compiled; + bool bound; OpenGLRenderer *renderer; diff --git a/src/render/opengl/OpenGLSharedState.cpp b/src/render/opengl/OpenGLSharedState.cpp index 22459fe..cfb3603 100644 --- a/src/render/opengl/OpenGLSharedState.cpp +++ b/src/render/opengl/OpenGLSharedState.cpp @@ -9,7 +9,7 @@ OpenGLSharedState::~OpenGLSharedState() { } } -void OpenGLSharedState::apply(OpenGLShaderProgram *program, int &texture_unit) { +void OpenGLSharedState::apply(OpenGLShaderProgram *program, unsigned int &texture_unit) { for (const auto &pair : variables) { pair.second->apply(program, texture_unit); } diff --git a/src/render/opengl/OpenGLSharedState.h b/src/render/opengl/OpenGLSharedState.h index 2b4e781..06e04b8 100644 --- a/src/render/opengl/OpenGLSharedState.h +++ b/src/render/opengl/OpenGLSharedState.h @@ -6,8 +6,6 @@ #include #include "OpenGLVariable.h" -class QImage; - namespace paysages { namespace opengl { @@ -22,7 +20,7 @@ class OPENGLSHARED_EXPORT OpenGLSharedState { /** * Apply the stored variables to the bound program. */ - void apply(OpenGLShaderProgram *program, int &texture_unit); + void apply(OpenGLShaderProgram *program, unsigned int &texture_unit); /** * Release any allocated resource in the opengl context. @@ -58,15 +56,9 @@ class OPENGLSHARED_EXPORT OpenGLSharedState { inline void set(const string &name, const Vector3 &vector) { get(name)->set(vector); } - inline void set(const string &name, const QVector3D &vector) { - get(name)->set(vector); - } inline void set(const string &name, const Matrix4 &matrix) { get(name)->set(matrix); } - inline void set(const string &name, const QMatrix4x4 &matrix) { - get(name)->set(matrix); - } inline void set(const string &name, const Color &color) { get(name)->set(color); } diff --git a/src/render/opengl/OpenGLVariable.cpp b/src/render/opengl/OpenGLVariable.cpp index bf3ef31..8ea0484 100644 --- a/src/render/opengl/OpenGLVariable.cpp +++ b/src/render/opengl/OpenGLVariable.cpp @@ -2,9 +2,6 @@ #include #include -#include -#include -#include #include #include "Logs.h" #include "OpenGLFunctions.h" @@ -17,281 +14,303 @@ #include "Texture3D.h" #include "Texture4D.h" -OpenGLVariable::OpenGLVariable(const string &name) : name(name) { - type = TYPE_NONE; - texture_toupload = false; - texture_id = 0; +typedef enum { + TYPE_NONE, + TYPE_TEXTURE_2D, + TYPE_TEXTURE_3D, + TYPE_TEXTURE_4D, + TYPE_INTEGER, + TYPE_FLOAT, + TYPE_VECTOR3, + TYPE_MATRIX4, + TYPE_COLOR +} OpenGLVariableType; - value_color = new QColor; - value_matrix4 = new QMatrix4x4; - value_vector3 = new QVector3D; - value_texture_data = new float[1]; +class OpenGLVariable::pimpl { + public: + pimpl(const string &name) : name(name) { + type = TYPE_NONE; + texture_toupload = false; + texture_id = 0; + } + + string name; + OpenGLVariableType type; + + int value_int; + float value_float; + unique_ptr value_color; + unique_ptr value_vector3; + unique_ptr value_array_float; + + int texture_size_x; + int texture_size_y; + int texture_size_z; + bool texture_toupload; + bool texture_repeat; + bool texture_color; + unsigned int texture_id; +}; + +OpenGLVariable::OpenGLVariable(const string &name) : impl(new pimpl(name)) { } 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 << endl; + if (impl->texture_id) { + Logs::warning("OpenGL") << "Texture ID " << impl->texture_id << " not freed in variable " << impl->name << endl; } } -void OpenGLVariable::apply(OpenGLShaderProgram *program, int &texture_unit) { - QOpenGLShaderProgram *pr = program->getProgram(); +void OpenGLVariable::apply(OpenGLShaderProgram *program, unsigned int &texture_unit) { + assert(program->isBound()); + OpenGLFunctions *functions = program->getRenderer()->getOpenGlFunctions(); - if (texture_toupload) { - uploadTexture(program->getRenderer()); - texture_toupload = false; + if (impl->texture_toupload) { + uploadTexture(functions); + impl->texture_toupload = false; } - switch (type) { - case TYPE_INTEGER: - pr->setUniformValue(name.c_str(), value_int); - break; - case TYPE_FLOAT: - pr->setUniformValue(name.c_str(), value_float); - break; - case TYPE_COLOR: - pr->setUniformValue(name.c_str(), *value_color); - break; - case TYPE_VECTOR3: - pr->setUniformValue(name.c_str(), *value_vector3); - break; - case TYPE_MATRIX4: - pr->setUniformValue(name.c_str(), *value_matrix4); - break; - case TYPE_TEXTURE_2D: - functions->glActiveTexture(GL_TEXTURE0 + texture_unit); - functions->glBindTexture(GL_TEXTURE_2D, texture_id); - pr->setUniformValue(name.c_str(), texture_unit); - texture_unit++; - break; - case TYPE_TEXTURE_3D: - case TYPE_TEXTURE_4D: - functions->glActiveTexture(GL_TEXTURE0 + texture_unit); - functions->glBindTexture(GL_TEXTURE_3D, texture_id); - pr->setUniformValue(name.c_str(), texture_unit); - texture_unit++; - break; - case TYPE_NONE: - break; + int loc = functions->glGetUniformLocation(program->getId(), impl->name.c_str()); + if (loc >= 0) { + switch (impl->type) { + case TYPE_INTEGER: + functions->glUniform1i(loc, impl->value_int); + break; + case TYPE_FLOAT: + functions->glUniform1f(loc, impl->value_float); + break; + case TYPE_COLOR: + functions->glUniform4f(loc, to_float(impl->value_color->r), to_float(impl->value_color->g), + to_float(impl->value_color->b), to_float(impl->value_color->a)); + break; + case TYPE_VECTOR3: + functions->glUniform3f(loc, to_float(impl->value_vector3->x), to_float(impl->value_vector3->y), + to_float(impl->value_vector3->z)); + break; + case TYPE_MATRIX4: + functions->glUniformMatrix4fv(loc, 1, true, impl->value_array_float.get()); + break; + case TYPE_TEXTURE_2D: + functions->glActiveTexture(GL_TEXTURE0 + texture_unit); + functions->glBindTexture(GL_TEXTURE_2D, impl->texture_id); + functions->glUniform1i(loc, static_cast(texture_unit)); + texture_unit++; + break; + case TYPE_TEXTURE_3D: + case TYPE_TEXTURE_4D: + functions->glActiveTexture(GL_TEXTURE0 + texture_unit); + functions->glBindTexture(GL_TEXTURE_3D, impl->texture_id); + functions->glUniform1i(loc, static_cast(texture_unit)); + texture_unit++; + break; + case TYPE_NONE: + break; + } } } void OpenGLVariable::destroy(OpenGLFunctions *functions) { - if (texture_id) { - functions->glDeleteTextures(1, &texture_id); - texture_id = 0; + if (impl->texture_id) { + functions->glDeleteTextures(1, &(impl->texture_id)); + impl->texture_id = 0; } } void OpenGLVariable::set(const Texture2D *texture, bool repeat, bool color) { - assert(type == TYPE_NONE or type == TYPE_TEXTURE_2D); - - type = TYPE_TEXTURE_2D; + impl->type = TYPE_TEXTURE_2D; int sx, sy; texture->getSize(&sx, &sy); - float *pixels = new float[sx * sy * 4]; + float *pixels = new float[to_size(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; + pixel[0] = to_float(col.r); + pixel[1] = to_float(col.g); + pixel[2] = to_float(col.b); + pixel[3] = to_float(col.a); } } - float *old_pixels = value_texture_data; - value_texture_data = pixels; - delete[] old_pixels; + impl->value_array_float = unique_ptr(pixels); - texture_size_x = sx; - texture_size_y = sy; - texture_size_z = 0; + impl->texture_size_x = sx; + impl->texture_size_y = sy; + impl->texture_size_z = 0; - texture_toupload = true; - texture_repeat = repeat; - texture_color = color; + impl->texture_toupload = true; + impl->texture_repeat = repeat; + impl->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; + impl->type = TYPE_TEXTURE_2D; int sx = texture.width(), sy = texture.height(); - float *pixels = new float[sx * sy * 4]; + float *pixels = new float[to_size(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; + pixel[0] = to_float(col.r); + pixel[1] = to_float(col.g); + pixel[2] = to_float(col.b); + pixel[3] = to_float(col.a); } } - float *old_pixels = value_texture_data; - value_texture_data = pixels; - delete[] old_pixels; + impl->value_array_float = unique_ptr(pixels); - texture_size_x = sx; - texture_size_y = sy; - texture_size_z = 0; + impl->texture_size_x = sx; + impl->texture_size_y = sy; + impl->texture_size_z = 0; - texture_toupload = true; - texture_repeat = repeat; - texture_color = color; + impl->texture_toupload = true; + impl->texture_repeat = repeat; + impl->texture_color = 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]; + float *pixels = new float[to_size(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; + pixel[0] = to_float(col.r); + pixel[1] = to_float(col.g); + pixel[2] = to_float(col.b); + pixel[3] = to_float(col.a); } } } - float *old_pixels = value_texture_data; - value_texture_data = pixels; - delete[] old_pixels; + impl->value_array_float = unique_ptr(pixels); - texture_size_x = sx; - texture_size_y = sy; - texture_size_z = sz; + impl->texture_size_x = sx; + impl->texture_size_y = sy; + impl->texture_size_z = sz; - type = TYPE_TEXTURE_3D; - texture_toupload = true; - texture_repeat = repeat; - texture_color = color; + impl->type = TYPE_TEXTURE_3D; + impl->texture_toupload = true; + impl->texture_repeat = repeat; + impl->texture_color = 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]; + float *pixels = new float[to_size(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; + pixel[0] = to_float(col.r); + pixel[1] = to_float(col.g); + pixel[2] = to_float(col.b); + pixel[3] = to_float(col.a); } } } } - float *old_pixels = value_texture_data; - value_texture_data = pixels; - delete[] old_pixels; + impl->value_array_float = unique_ptr(pixels); - texture_size_x = sx; - texture_size_y = sy; - texture_size_z = sz * sw; + impl->texture_size_x = sx; + impl->texture_size_y = sy; + impl->texture_size_z = sz * sw; - type = TYPE_TEXTURE_4D; - texture_toupload = true; - texture_repeat = repeat; - texture_color = color; + impl->type = TYPE_TEXTURE_4D; + impl->texture_toupload = true; + impl->texture_repeat = repeat; + impl->texture_color = color; } void OpenGLVariable::set(int value) { - assert(type == TYPE_NONE or type == TYPE_INTEGER); - - type = TYPE_INTEGER; - value_int = value; + impl->type = TYPE_INTEGER; + impl->value_int = value; } void OpenGLVariable::set(float value) { - assert(type == TYPE_NONE or type == TYPE_FLOAT); - - type = TYPE_FLOAT; - value_float = value; + impl->type = TYPE_FLOAT; + impl->value_float = value; } void OpenGLVariable::set(const Vector3 &vector) { - set(QVector3D(vector.x, vector.y, vector.z)); -} - -void OpenGLVariable::set(const QVector3D &vector) { - assert(type == TYPE_NONE or type == TYPE_VECTOR3); - - type = TYPE_VECTOR3; - *value_vector3 = vector; + impl->type = TYPE_VECTOR3; + impl->value_vector3 = make_unique(vector); } void OpenGLVariable::set(const Matrix4 &matrix) { - set(matrix.toQMatrix()); -} + impl->type = TYPE_MATRIX4; -void OpenGLVariable::set(const QMatrix4x4 &matrix) { - assert(type == TYPE_NONE or type == TYPE_MATRIX4); + float *data = new float[16]; + data[0] = to_float(matrix.getA()); + data[1] = to_float(matrix.getB()); + data[2] = to_float(matrix.getC()); + data[3] = to_float(matrix.getD()); + data[4] = to_float(matrix.getE()); + data[5] = to_float(matrix.getF()); + data[6] = to_float(matrix.getG()); + data[7] = to_float(matrix.getH()); + data[8] = to_float(matrix.getI()); + data[9] = to_float(matrix.getJ()); + data[10] = to_float(matrix.getK()); + data[11] = to_float(matrix.getL()); + data[12] = to_float(matrix.getM()); + data[13] = to_float(matrix.getN()); + data[14] = to_float(matrix.getO()); + data[15] = to_float(matrix.getP()); - type = TYPE_MATRIX4; - *value_matrix4 = matrix; + impl->value_array_float = unique_ptr(data); } 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); + impl->type = TYPE_COLOR; + impl->value_color = make_unique(color); } -void OpenGLVariable::uploadTexture(OpenGLRenderer *renderer) { - OpenGLFunctions *functions = renderer->getOpenGlFunctions(); +int OpenGLVariable::getIntValue() const { + return impl->value_int; +} - assert(type == TYPE_TEXTURE_2D or type == TYPE_TEXTURE_3D or type == TYPE_TEXTURE_4D); +float OpenGLVariable::getFloatValue() const { + return impl->value_float; +} - if (texture_id == 0) { +void OpenGLVariable::uploadTexture(OpenGLFunctions *functions) { + assert(impl->type == TYPE_TEXTURE_2D or impl->type == TYPE_TEXTURE_3D or impl->type == TYPE_TEXTURE_4D); + + if (impl->texture_id == 0) { GLuint texid; functions->glGenTextures(1, &texid); - texture_id = texid; + impl->texture_id = texid; } - GLenum textype = (type == TYPE_TEXTURE_2D) ? GL_TEXTURE_2D : GL_TEXTURE_3D; + GLenum textype = (impl->type == TYPE_TEXTURE_2D) ? GL_TEXTURE_2D : GL_TEXTURE_3D; - functions->glBindTexture(textype, texture_id); + functions->glBindTexture(textype, impl->texture_id); functions->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER, GL_LINEAR); functions->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - functions->glTexParameteri(textype, GL_TEXTURE_WRAP_S, texture_repeat ? GL_REPEAT : GL_CLAMP_TO_EDGE); - functions->glTexParameteri(textype, GL_TEXTURE_WRAP_T, texture_repeat ? GL_REPEAT : GL_CLAMP_TO_EDGE); + functions->glTexParameteri(textype, GL_TEXTURE_WRAP_S, impl->texture_repeat ? GL_REPEAT : GL_CLAMP_TO_EDGE); + functions->glTexParameteri(textype, GL_TEXTURE_WRAP_T, impl->texture_repeat ? GL_REPEAT : GL_CLAMP_TO_EDGE); if (textype == GL_TEXTURE_3D) { - functions->glTexParameteri(textype, GL_TEXTURE_WRAP_R, texture_repeat ? GL_REPEAT : GL_CLAMP_TO_EDGE); + functions->glTexParameteri(textype, GL_TEXTURE_WRAP_R, impl->texture_repeat ? GL_REPEAT : GL_CLAMP_TO_EDGE); } - int dest_format = texture_color ? GL_RGBA : GL_RED; + int dest_format = impl->texture_color ? GL_RGBA : GL_RED; - if (type == TYPE_TEXTURE_2D) { - functions->glTexImage2D(GL_TEXTURE_2D, 0, dest_format, texture_size_x, texture_size_y, 0, GL_RGBA, GL_FLOAT, - value_texture_data); + if (impl->type == TYPE_TEXTURE_2D) { + functions->glTexImage2D(GL_TEXTURE_2D, 0, dest_format, impl->texture_size_x, impl->texture_size_y, 0, GL_RGBA, + GL_FLOAT, impl->value_array_float.get()); } else { - 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); + functions->glTexImage3D(GL_TEXTURE_3D, 0, dest_format, impl->texture_size_x, impl->texture_size_y, + impl->texture_size_z, 0, GL_RGBA, GL_FLOAT, impl->value_array_float.get()); } } diff --git a/src/render/opengl/OpenGLVariable.h b/src/render/opengl/OpenGLVariable.h index 135b0ef..8c786d5 100644 --- a/src/render/opengl/OpenGLVariable.h +++ b/src/render/opengl/OpenGLVariable.h @@ -3,9 +3,8 @@ #include "opengl_global.h" -class QColor; -class QVector3D; -class QMatrix4x4; +#include + class QImage; namespace paysages { @@ -14,7 +13,7 @@ namespace opengl { /*! * \brief OpenGL variable that can be bound to a uniform for shaders. */ -class OpenGLVariable { +class OpenGLVariable final { public: typedef enum { TYPE_NONE, @@ -32,7 +31,14 @@ class OpenGLVariable { OpenGLVariable(const string &name); ~OpenGLVariable(); - void apply(OpenGLShaderProgram *program, int &texture_unit); + /** + * Apply the variable to the bound shader program. + * + * *texture_unit* will be used and updated accordingly. + * + * This must be called from the rendering thread, with the shader program bound. + */ + void apply(OpenGLShaderProgram *program, unsigned int &texture_unit); /** * Release any allocated resource in the opengl context. @@ -48,39 +54,18 @@ class OpenGLVariable { void set(int value); void set(float value); void set(const Vector3 &vector); - void set(const QVector3D &vector); void set(const Matrix4 &matrix); - void set(const QMatrix4x4 &matrix); void set(const Color &color); - inline int getIntValue() const { - return value_int; - } - inline float getFloatValue() const { - return value_float; - } + int getIntValue() const; + float getFloatValue() const; protected: - void uploadTexture(OpenGLRenderer *renderer); + void uploadTexture(OpenGLFunctions *renderer); private: - string name; - OpenGLVariableType type; - - int value_int; - float value_float; - 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; - unsigned int texture_id; + class pimpl; + unique_ptr impl; }; } } diff --git a/src/system/system_global.h b/src/system/system_global.h index 1b8bcbc..6fe4e02 100644 --- a/src/system/system_global.h +++ b/src/system/system_global.h @@ -40,6 +40,7 @@ using namespace std; // Some useful casts #define to_double(_x_) (static_cast(_x_)) +#define to_float(_x_) (static_cast(_x_)) #define trunc_to_int(_x_) (static_cast(_x_)) #define round_to_int(_x_) (static_cast(round(_x_))) #define floor_to_int(_x_) (static_cast(floor(_x_))) diff --git a/src/tests/Camera_Test.cpp b/src/tests/CameraDefinition_Test.cpp similarity index 80% rename from src/tests/Camera_Test.cpp rename to src/tests/CameraDefinition_Test.cpp index 43fab26..03df1c9 100644 --- a/src/tests/Camera_Test.cpp +++ b/src/tests/CameraDefinition_Test.cpp @@ -2,7 +2,7 @@ #include "CameraDefinition.h" -TEST(Camera, Definition) { +TEST(CameraDefinition, constructor) { CameraDefinition cam; cam.setLocationCoords(0.0, 1.0, 1.0); @@ -12,14 +12,15 @@ TEST(Camera, Definition) { EXPECT_VECTOR3_COORDS(cam.getTarget(), 0.0, 0.0, 0.0); } -TEST(Camera, Projection) { +TEST(CameraDefinition, unproject) { CameraDefinition cam; + Vector3 point; cam.setLocationCoords(0.0, 1.0, 1.0); cam.setTargetCoords(0.0, 0.0, 0.0); - /* Test the reversibility of projection */ - Vector3 point = cam.project(Vector3(12.0, 5.2, -6.3)); + // Test the reversibility of projection + point = cam.project(Vector3(12.0, 5.2, -6.3)); point = cam.unproject(point); EXPECT_VECTOR3_COORDS(point, 12.0, 5.2, -6.3); point = cam.project(Vector3(-25.1, 8.3, 1.3)); @@ -27,13 +28,13 @@ TEST(Camera, Projection) { EXPECT_VECTOR3_COORDS(point, -25.1, 8.3, 1.3); } -TEST(Camera, Depth) { +TEST(CameraDefinition, getRealDepth) { CameraDefinition cam; cam.setLocationCoords(0.0, 0.0, 0.0); cam.setTargetCoords(1.0, 0.0, 0.0); - /* Test the real depth getter */ + // Test the real depth getter Vector3 point = cam.project(Vector3(12.5, 0.0, 0.0)); ASSERT_DOUBLE_EQ(cam.getRealDepth(point), 12.5); point = cam.project(Vector3(12.5, 8.0, -3.0));