Refactored OpenGLVariable with pimpl and smart pointers

This commit is contained in:
Michaël Lemaire 2015-12-23 23:40:19 +01:00
parent 3934077552
commit d88cb29f4c
13 changed files with 306 additions and 233 deletions

View file

@ -10,6 +10,11 @@ Matrix4::Matrix4(bool identity) {
a = f = k = p = (identity ? 1.0 : 0.0); 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 { void Matrix4::save(PackStream *stream) const {
stream->write(&a); stream->write(&a);
stream->write(&b); 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 Matrix4::newPerspective(double fov_y, double aspect, double near, double far) {
Matrix4 result; Matrix4 result;
double fo = 1 / tan(fov_y / 2.0); double fo = 1.0 / tan(fov_y / 2.0);
result.a = fo / aspect; result.a = fo / aspect;
result.f = fo; result.f = fo;
result.k = (far + near) / (near - far); result.k = (far + near) / (near - far);

View file

@ -3,16 +3,14 @@
#include "basics_global.h" #include "basics_global.h"
#ifdef QT_GUI_LIB
#include <QMatrix4x4>
#endif
namespace paysages { namespace paysages {
namespace basics { namespace basics {
class BASICSSHARED_EXPORT Matrix4 { class BASICSSHARED_EXPORT Matrix4 {
public: public:
Matrix4(bool identity = true); 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 save(PackStream *stream) const;
void load(PackStream *stream); void load(PackStream *stream);
@ -36,11 +34,54 @@ class BASICSSHARED_EXPORT Matrix4 {
double getDeterminant() const; double getDeterminant() const;
#ifdef QT_GUI_LIB inline double getA() const {
inline QMatrix4x4 toQMatrix() const { return a;
return QMatrix4x4(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p); }
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: private:
double a; double a;

View file

@ -249,6 +249,7 @@ bool CameraDefinition::transitionToAnother(const CameraDefinition *wanted, doubl
dy = wanted->location.y - location.y; dy = wanted->location.y - location.y;
dz = wanted->location.z - location.z; dz = wanted->location.z - location.z;
dr = wanted->direction.r - direction.r; dr = wanted->direction.r - direction.r;
// TODO pi-modulo nearest
dphi = wanted->direction.phi - direction.phi; dphi = wanted->direction.phi - direction.phi;
dtheta = wanted->direction.theta - direction.theta; dtheta = wanted->direction.theta - direction.theta;
droll = wanted->roll - roll; droll = wanted->roll - roll;

View file

@ -73,9 +73,10 @@ void ModelerCameras::endTool() {
} }
void ModelerCameras::timerEvent(QTimerEvent *) { void ModelerCameras::timerEvent(QTimerEvent *) {
current->transitionToAnother(active, 0.5); if (current->transitionToAnother(active, 0.5)) {
parent->getScenery()->keepCameraAboveGround(current); parent->getScenery()->keepCameraAboveGround(current);
parent->getRenderer()->setCamera(current); parent->getRenderer()->setCamera(current);
}
} }
void ModelerCameras::nodeChanged(const DefinitionNode *node, const DefinitionDiff *) { void ModelerCameras::nodeChanged(const DefinitionNode *node, const DefinitionDiff *) {

View file

@ -1,5 +1,6 @@
#include "OpenGLRenderer.h" #include "OpenGLRenderer.h"
#include <QMatrix4x4>
#include "OpenGLFunctions.h" #include "OpenGLFunctions.h"
#include "CameraDefinition.h" #include "CameraDefinition.h"
#include "OpenGLSharedState.h" #include "OpenGLSharedState.h"
@ -38,7 +39,7 @@ OpenGLRenderer::OpenGLRenderer(Scenery *scenery) : SoftwareRenderer(scenery) {
shared_state = new OpenGLSharedState(); shared_state = new OpenGLSharedState();
shared_state->set("viewDistance", 300.0); 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(skybox = new OpenGLSkybox(this));
parts.push_back(water = new OpenGLWater(this)); parts.push_back(water = new OpenGLWater(this));
@ -72,7 +73,7 @@ void OpenGLRenderer::prepare() {
} }
void OpenGLRenderer::checkForErrors(const string &domain) { void OpenGLRenderer::checkForErrors(const string &domain) {
int error_code; unsigned int error_code;
while ((error_code = functions->glGetError()) != GL_NO_ERROR) { while ((error_code = functions->glGetError()) != GL_NO_ERROR) {
Logs::warning("OpenGL") << "Error in " << domain << " : " << error_code << endl; Logs::warning("OpenGL") << "Error in " << domain << " : " << error_code << endl;
} }
@ -236,6 +237,7 @@ void OpenGLRenderer::cameraChangeEvent(CameraDefinition *camera) {
CameraPerspective perspective = camera->getPerspective(); CameraPerspective perspective = camera->getPerspective();
// Compute matrix // Compute matrix
// TODO Switch to CameraDefinition raw transformation matrix (currently produces strange results)
QMatrix4x4 transform; QMatrix4x4 transform;
transform.setToIdentity(); transform.setToIdentity();
transform.lookAt(QVector3D(location.x, location.y, location.z), QVector3D(target.x, target.y, target.z), 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 // Set in shaders
shared_state->set("cameraLocation", location); 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 // Broadcast to parts
vegetation->cameraChanged(camera); vegetation->cameraChanged(camera);
@ -267,7 +270,7 @@ void OpenGLRenderer::updateMouseProjection() {
GLfloat z; GLfloat z;
functions->glReadPixels(mouse_x, mouse_y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &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)); 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(), *mouse_projected = Vector3(unprojected.x() / unprojected.w(), unprojected.y() / unprojected.w(),
unprojected.z() / unprojected.w()); unprojected.z() / unprojected.w());

View file

@ -18,6 +18,7 @@ OpenGLShaderProgram::OpenGLShaderProgram(const string &name, OpenGLRenderer *ren
functions = renderer->getOpenGlFunctions(); functions = renderer->getOpenGlFunctions();
state = new OpenGLSharedState(); state = new OpenGLSharedState();
compiled = false; compiled = false;
bound = false;
} }
OpenGLShaderProgram::~OpenGLShaderProgram() { OpenGLShaderProgram::~OpenGLShaderProgram() {
@ -28,7 +29,7 @@ OpenGLShaderProgram::~OpenGLShaderProgram() {
void OpenGLShaderProgram::addVertexSource(const string &path) { void OpenGLShaderProgram::addVertexSource(const string &path) {
QFile file(QString(":/shaders/%1.vert").arg(QString::fromStdString(path))); QFile file(QString(":/shaders/%1.vert").arg(QString::fromStdString(path)));
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
source_vertex += QString(file.readAll()).toStdString(); source_vertex += QString(file.readAll()).toStdString() + "\n";
} else { } else {
Logs::error("OpenGL") << "Can't open vertex file " << file.fileName().toStdString() << endl; 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) { void OpenGLShaderProgram::addFragmentSource(const string &path) {
QFile file(QString(":/shaders/%1.frag").arg(QString::fromStdString(path))); QFile file(QString(":/shaders/%1.frag").arg(QString::fromStdString(path)));
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
source_fragment += QString(file.readAll()).toStdString(); source_fragment += QString(file.readAll()).toStdString() + "\n";
} else { } else {
Logs::error("OpenGL") << "Can't open fragment file " << file.fileName().toStdString() << endl; Logs::error("OpenGL") << "Can't open fragment file " << file.fileName().toStdString() << endl;
} }
@ -74,11 +75,14 @@ bool OpenGLShaderProgram::bind(OpenGLSharedState *state) {
} }
if (program->bind()) { if (program->bind()) {
int texture_unit = 0; bound = true;
unsigned int texture_unit = 0;
renderer->getSharedState()->apply(this, texture_unit); renderer->getSharedState()->apply(this, texture_unit);
if (state) { if (state) {
state->apply(this, texture_unit); state->apply(this, texture_unit);
} }
return true; return true;
} else { } else {
return false; return false;
@ -86,6 +90,7 @@ bool OpenGLShaderProgram::bind(OpenGLSharedState *state) {
} }
void OpenGLShaderProgram::release() { void OpenGLShaderProgram::release() {
bound = false;
program->release(); program->release();
} }
@ -96,3 +101,7 @@ void OpenGLShaderProgram::draw(OpenGLVertexArray *vertices, OpenGLSharedState *s
release(); release();
} }
} }
unsigned int OpenGLShaderProgram::getId() const {
return program->programId();
}

View file

@ -33,6 +33,20 @@ class OPENGLSHARED_EXPORT OpenGLShaderProgram {
*/ */
void draw(OpenGLVertexArray *vertices, OpenGLSharedState *state = NULL, int start = 0, int count = -1); 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 { inline QOpenGLShaderProgram *getProgram() const {
return program; return program;
} }
@ -55,6 +69,7 @@ class OPENGLSHARED_EXPORT OpenGLShaderProgram {
void compile(); void compile();
bool compiled; bool compiled;
bool bound;
OpenGLRenderer *renderer; OpenGLRenderer *renderer;

View file

@ -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) { for (const auto &pair : variables) {
pair.second->apply(program, texture_unit); pair.second->apply(program, texture_unit);
} }

View file

@ -6,8 +6,6 @@
#include <map> #include <map>
#include "OpenGLVariable.h" #include "OpenGLVariable.h"
class QImage;
namespace paysages { namespace paysages {
namespace opengl { namespace opengl {
@ -22,7 +20,7 @@ class OPENGLSHARED_EXPORT OpenGLSharedState {
/** /**
* Apply the stored variables to the bound program. * 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. * 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) { inline void set(const string &name, const Vector3 &vector) {
get(name)->set(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) { inline void set(const string &name, const Matrix4 &matrix) {
get(name)->set(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) { inline void set(const string &name, const Color &color) {
get(name)->set(color); get(name)->set(color);
} }

View file

@ -2,9 +2,6 @@
#include <cassert> #include <cassert>
#include <QOpenGLShaderProgram> #include <QOpenGLShaderProgram>
#include <QColor>
#include <QVector3D>
#include <QMatrix4x4>
#include <QImage> #include <QImage>
#include "Logs.h" #include "Logs.h"
#include "OpenGLFunctions.h" #include "OpenGLFunctions.h"
@ -17,281 +14,303 @@
#include "Texture3D.h" #include "Texture3D.h"
#include "Texture4D.h" #include "Texture4D.h"
OpenGLVariable::OpenGLVariable(const string &name) : name(name) { typedef enum {
type = TYPE_NONE; TYPE_NONE,
texture_toupload = false; TYPE_TEXTURE_2D,
texture_id = 0; TYPE_TEXTURE_3D,
TYPE_TEXTURE_4D,
TYPE_INTEGER,
TYPE_FLOAT,
TYPE_VECTOR3,
TYPE_MATRIX4,
TYPE_COLOR
} OpenGLVariableType;
value_color = new QColor; class OpenGLVariable::pimpl {
value_matrix4 = new QMatrix4x4; public:
value_vector3 = new QVector3D; pimpl(const string &name) : name(name) {
value_texture_data = new float[1]; type = TYPE_NONE;
texture_toupload = false;
texture_id = 0;
}
string name;
OpenGLVariableType type;
int value_int;
float value_float;
unique_ptr<Color> value_color;
unique_ptr<Vector3> value_vector3;
unique_ptr<float[]> 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() { OpenGLVariable::~OpenGLVariable() {
delete value_color; if (impl->texture_id) {
delete value_matrix4; Logs::warning("OpenGL") << "Texture ID " << impl->texture_id << " not freed in variable " << impl->name << endl;
delete value_vector3;
delete[] value_texture_data;
if (texture_id) {
Logs::warning("OpenGL") << "Texture ID not freed " << texture_id << endl;
} }
} }
void OpenGLVariable::apply(OpenGLShaderProgram *program, int &texture_unit) { void OpenGLVariable::apply(OpenGLShaderProgram *program, unsigned int &texture_unit) {
QOpenGLShaderProgram *pr = program->getProgram(); assert(program->isBound());
OpenGLFunctions *functions = program->getRenderer()->getOpenGlFunctions(); OpenGLFunctions *functions = program->getRenderer()->getOpenGlFunctions();
if (texture_toupload) { if (impl->texture_toupload) {
uploadTexture(program->getRenderer()); uploadTexture(functions);
texture_toupload = false; impl->texture_toupload = false;
} }
switch (type) { int loc = functions->glGetUniformLocation(program->getId(), impl->name.c_str());
case TYPE_INTEGER: if (loc >= 0) {
pr->setUniformValue(name.c_str(), value_int); switch (impl->type) {
break; case TYPE_INTEGER:
case TYPE_FLOAT: functions->glUniform1i(loc, impl->value_int);
pr->setUniformValue(name.c_str(), value_float); break;
break; case TYPE_FLOAT:
case TYPE_COLOR: functions->glUniform1f(loc, impl->value_float);
pr->setUniformValue(name.c_str(), *value_color); break;
break; case TYPE_COLOR:
case TYPE_VECTOR3: functions->glUniform4f(loc, to_float(impl->value_color->r), to_float(impl->value_color->g),
pr->setUniformValue(name.c_str(), *value_vector3); to_float(impl->value_color->b), to_float(impl->value_color->a));
break; break;
case TYPE_MATRIX4: case TYPE_VECTOR3:
pr->setUniformValue(name.c_str(), *value_matrix4); functions->glUniform3f(loc, to_float(impl->value_vector3->x), to_float(impl->value_vector3->y),
break; to_float(impl->value_vector3->z));
case TYPE_TEXTURE_2D: break;
functions->glActiveTexture(GL_TEXTURE0 + texture_unit); case TYPE_MATRIX4:
functions->glBindTexture(GL_TEXTURE_2D, texture_id); functions->glUniformMatrix4fv(loc, 1, true, impl->value_array_float.get());
pr->setUniformValue(name.c_str(), texture_unit); break;
texture_unit++; case TYPE_TEXTURE_2D:
break; functions->glActiveTexture(GL_TEXTURE0 + texture_unit);
case TYPE_TEXTURE_3D: functions->glBindTexture(GL_TEXTURE_2D, impl->texture_id);
case TYPE_TEXTURE_4D: functions->glUniform1i(loc, static_cast<int>(texture_unit));
functions->glActiveTexture(GL_TEXTURE0 + texture_unit); texture_unit++;
functions->glBindTexture(GL_TEXTURE_3D, texture_id); break;
pr->setUniformValue(name.c_str(), texture_unit); case TYPE_TEXTURE_3D:
texture_unit++; case TYPE_TEXTURE_4D:
break; functions->glActiveTexture(GL_TEXTURE0 + texture_unit);
case TYPE_NONE: functions->glBindTexture(GL_TEXTURE_3D, impl->texture_id);
break; functions->glUniform1i(loc, static_cast<int>(texture_unit));
texture_unit++;
break;
case TYPE_NONE:
break;
}
} }
} }
void OpenGLVariable::destroy(OpenGLFunctions *functions) { void OpenGLVariable::destroy(OpenGLFunctions *functions) {
if (texture_id) { if (impl->texture_id) {
functions->glDeleteTextures(1, &texture_id); functions->glDeleteTextures(1, &(impl->texture_id));
texture_id = 0; impl->texture_id = 0;
} }
} }
void OpenGLVariable::set(const Texture2D *texture, bool repeat, bool color) { void OpenGLVariable::set(const Texture2D *texture, bool repeat, bool color) {
assert(type == TYPE_NONE or type == TYPE_TEXTURE_2D); impl->type = TYPE_TEXTURE_2D;
type = TYPE_TEXTURE_2D;
int sx, sy; int sx, sy;
texture->getSize(&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 x = 0; x < sx; x++) {
for (int y = 0; y < sy; y++) { for (int y = 0; y < sy; y++) {
float *pixel = pixels + (y * sx + x) * 4; float *pixel = pixels + (y * sx + x) * 4;
Color col = texture->getPixel(x, y); Color col = texture->getPixel(x, y);
pixel[0] = (float)col.r; pixel[0] = to_float(col.r);
pixel[1] = (float)col.g; pixel[1] = to_float(col.g);
pixel[2] = (float)col.b; pixel[2] = to_float(col.b);
pixel[3] = (float)col.a; pixel[3] = to_float(col.a);
} }
} }
float *old_pixels = value_texture_data; impl->value_array_float = unique_ptr<float[]>(pixels);
value_texture_data = pixels;
delete[] old_pixels;
texture_size_x = sx; impl->texture_size_x = sx;
texture_size_y = sy; impl->texture_size_y = sy;
texture_size_z = 0; impl->texture_size_z = 0;
texture_toupload = true; impl->texture_toupload = true;
texture_repeat = repeat; impl->texture_repeat = repeat;
texture_color = color; impl->texture_color = color;
} }
void OpenGLVariable::set(const QImage &texture, bool repeat, bool color) { void OpenGLVariable::set(const QImage &texture, bool repeat, bool color) {
assert(type == TYPE_NONE or type == TYPE_TEXTURE_2D); impl->type = TYPE_TEXTURE_2D;
type = TYPE_TEXTURE_2D;
int sx = texture.width(), sy = texture.height(); 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 x = 0; x < sx; x++) {
for (int y = 0; y < sy; y++) { for (int y = 0; y < sy; y++) {
float *pixel = pixels + (y * sx + x) * 4; float *pixel = pixels + (y * sx + x) * 4;
Color col = Color::from32BitRGBA(texture.pixel(x, y)); Color col = Color::from32BitRGBA(texture.pixel(x, y));
pixel[0] = (float)col.r; pixel[0] = to_float(col.r);
pixel[1] = (float)col.g; pixel[1] = to_float(col.g);
pixel[2] = (float)col.b; pixel[2] = to_float(col.b);
pixel[3] = (float)col.a; pixel[3] = to_float(col.a);
} }
} }
float *old_pixels = value_texture_data; impl->value_array_float = unique_ptr<float[]>(pixels);
value_texture_data = pixels;
delete[] old_pixels;
texture_size_x = sx; impl->texture_size_x = sx;
texture_size_y = sy; impl->texture_size_y = sy;
texture_size_z = 0; impl->texture_size_z = 0;
texture_toupload = true; impl->texture_toupload = true;
texture_repeat = repeat; impl->texture_repeat = repeat;
texture_color = color; impl->texture_color = color;
} }
void OpenGLVariable::set(const Texture3D *texture, bool repeat, bool color) { void OpenGLVariable::set(const Texture3D *texture, bool repeat, bool color) {
assert(type == TYPE_NONE or type == TYPE_TEXTURE_3D);
int sx, sy, sz; int sx, sy, sz;
texture->getSize(&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 x = 0; x < sx; x++) {
for (int y = 0; y < sy; y++) { for (int y = 0; y < sy; y++) {
for (int z = 0; z < sz; z++) { for (int z = 0; z < sz; z++) {
float *pixel = pixels + (z * (sx * sy) + y * sx + x) * 4; float *pixel = pixels + (z * (sx * sy) + y * sx + x) * 4;
Color col = texture->getPixel(x, y, z); Color col = texture->getPixel(x, y, z);
pixel[0] = (float)col.r; pixel[0] = to_float(col.r);
pixel[1] = (float)col.g; pixel[1] = to_float(col.g);
pixel[2] = (float)col.b; pixel[2] = to_float(col.b);
pixel[3] = (float)col.a; pixel[3] = to_float(col.a);
} }
} }
} }
float *old_pixels = value_texture_data; impl->value_array_float = unique_ptr<float[]>(pixels);
value_texture_data = pixels;
delete[] old_pixels;
texture_size_x = sx; impl->texture_size_x = sx;
texture_size_y = sy; impl->texture_size_y = sy;
texture_size_z = sz; impl->texture_size_z = sz;
type = TYPE_TEXTURE_3D; impl->type = TYPE_TEXTURE_3D;
texture_toupload = true; impl->texture_toupload = true;
texture_repeat = repeat; impl->texture_repeat = repeat;
texture_color = color; impl->texture_color = color;
} }
void OpenGLVariable::set(const Texture4D *texture, bool repeat, bool color) { void OpenGLVariable::set(const Texture4D *texture, bool repeat, bool color) {
assert(type == TYPE_NONE or type == TYPE_TEXTURE_4D);
int sx, sy, sz, sw; int sx, sy, sz, sw;
texture->getSize(&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 x = 0; x < sx; x++) {
for (int y = 0; y < sy; y++) { for (int y = 0; y < sy; y++) {
for (int z = 0; z < sz; z++) { for (int z = 0; z < sz; z++) {
for (int w = 0; w < sw; w++) { for (int w = 0; w < sw; w++) {
float *pixel = pixels + (w * (sx * sy * sz) + z * (sx * sy) + y * sx + x) * 4; float *pixel = pixels + (w * (sx * sy * sz) + z * (sx * sy) + y * sx + x) * 4;
Color col = texture->getPixel(x, y, z, w); Color col = texture->getPixel(x, y, z, w);
pixel[0] = (float)col.r; pixel[0] = to_float(col.r);
pixel[1] = (float)col.g; pixel[1] = to_float(col.g);
pixel[2] = (float)col.b; pixel[2] = to_float(col.b);
pixel[3] = (float)col.a; pixel[3] = to_float(col.a);
} }
} }
} }
} }
float *old_pixels = value_texture_data; impl->value_array_float = unique_ptr<float[]>(pixels);
value_texture_data = pixels;
delete[] old_pixels;
texture_size_x = sx; impl->texture_size_x = sx;
texture_size_y = sy; impl->texture_size_y = sy;
texture_size_z = sz * sw; impl->texture_size_z = sz * sw;
type = TYPE_TEXTURE_4D; impl->type = TYPE_TEXTURE_4D;
texture_toupload = true; impl->texture_toupload = true;
texture_repeat = repeat; impl->texture_repeat = repeat;
texture_color = color; impl->texture_color = color;
} }
void OpenGLVariable::set(int value) { void OpenGLVariable::set(int value) {
assert(type == TYPE_NONE or type == TYPE_INTEGER); impl->type = TYPE_INTEGER;
impl->value_int = value;
type = TYPE_INTEGER;
value_int = value;
} }
void OpenGLVariable::set(float value) { void OpenGLVariable::set(float value) {
assert(type == TYPE_NONE or type == TYPE_FLOAT); impl->type = TYPE_FLOAT;
impl->value_float = value;
type = TYPE_FLOAT;
value_float = value;
} }
void OpenGLVariable::set(const Vector3 &vector) { void OpenGLVariable::set(const Vector3 &vector) {
set(QVector3D(vector.x, vector.y, vector.z)); impl->type = TYPE_VECTOR3;
} impl->value_vector3 = make_unique<Vector3>(vector);
void OpenGLVariable::set(const QVector3D &vector) {
assert(type == TYPE_NONE or type == TYPE_VECTOR3);
type = TYPE_VECTOR3;
*value_vector3 = vector;
} }
void OpenGLVariable::set(const Matrix4 &matrix) { void OpenGLVariable::set(const Matrix4 &matrix) {
set(matrix.toQMatrix()); impl->type = TYPE_MATRIX4;
}
void OpenGLVariable::set(const QMatrix4x4 &matrix) { float *data = new float[16];
assert(type == TYPE_NONE or type == TYPE_MATRIX4); 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; impl->value_array_float = unique_ptr<float[]>(data);
*value_matrix4 = matrix;
} }
void OpenGLVariable::set(const Color &color) { void OpenGLVariable::set(const Color &color) {
assert(type == TYPE_NONE or type == TYPE_COLOR); impl->type = TYPE_COLOR;
impl->value_color = make_unique<Color>(color);
type = TYPE_COLOR;
*value_color = QColor::fromRgbF(color.r, color.g, color.b);
} }
void OpenGLVariable::uploadTexture(OpenGLRenderer *renderer) { int OpenGLVariable::getIntValue() const {
OpenGLFunctions *functions = renderer->getOpenGlFunctions(); 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; GLuint texid;
functions->glGenTextures(1, &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_MIN_FILTER, GL_LINEAR);
functions->glTexParameteri(textype, GL_TEXTURE_MAG_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_S, impl->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_T, impl->texture_repeat ? GL_REPEAT : GL_CLAMP_TO_EDGE);
if (textype == GL_TEXTURE_3D) { 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) { if (impl->type == TYPE_TEXTURE_2D) {
functions->glTexImage2D(GL_TEXTURE_2D, 0, dest_format, texture_size_x, texture_size_y, 0, GL_RGBA, GL_FLOAT, functions->glTexImage2D(GL_TEXTURE_2D, 0, dest_format, impl->texture_size_x, impl->texture_size_y, 0, GL_RGBA,
value_texture_data); GL_FLOAT, impl->value_array_float.get());
} else { } else {
functions->glTexImage3D(GL_TEXTURE_3D, 0, dest_format, texture_size_x, texture_size_y, texture_size_z, 0, functions->glTexImage3D(GL_TEXTURE_3D, 0, dest_format, impl->texture_size_x, impl->texture_size_y,
GL_RGBA, GL_FLOAT, value_texture_data); impl->texture_size_z, 0, GL_RGBA, GL_FLOAT, impl->value_array_float.get());
} }
} }

View file

@ -3,9 +3,8 @@
#include "opengl_global.h" #include "opengl_global.h"
class QColor; #include <memory>
class QVector3D;
class QMatrix4x4;
class QImage; class QImage;
namespace paysages { namespace paysages {
@ -14,7 +13,7 @@ namespace opengl {
/*! /*!
* \brief OpenGL variable that can be bound to a uniform for shaders. * \brief OpenGL variable that can be bound to a uniform for shaders.
*/ */
class OpenGLVariable { class OpenGLVariable final {
public: public:
typedef enum { typedef enum {
TYPE_NONE, TYPE_NONE,
@ -32,7 +31,14 @@ class OpenGLVariable {
OpenGLVariable(const string &name); OpenGLVariable(const string &name);
~OpenGLVariable(); ~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. * Release any allocated resource in the opengl context.
@ -48,39 +54,18 @@ class OpenGLVariable {
void set(int value); void set(int value);
void set(float value); void set(float value);
void set(const Vector3 &vector); void set(const Vector3 &vector);
void set(const QVector3D &vector);
void set(const Matrix4 &matrix); void set(const Matrix4 &matrix);
void set(const QMatrix4x4 &matrix);
void set(const Color &color); void set(const Color &color);
inline int getIntValue() const { int getIntValue() const;
return value_int; float getFloatValue() const;
}
inline float getFloatValue() const {
return value_float;
}
protected: protected:
void uploadTexture(OpenGLRenderer *renderer); void uploadTexture(OpenGLFunctions *renderer);
private: private:
string name; class pimpl;
OpenGLVariableType type; unique_ptr<pimpl> impl;
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;
}; };
} }
} }

View file

@ -40,6 +40,7 @@ using namespace std;
// Some useful casts // Some useful casts
#define to_double(_x_) (static_cast<double>(_x_)) #define to_double(_x_) (static_cast<double>(_x_))
#define to_float(_x_) (static_cast<float>(_x_))
#define trunc_to_int(_x_) (static_cast<int>(_x_)) #define trunc_to_int(_x_) (static_cast<int>(_x_))
#define round_to_int(_x_) (static_cast<int>(round(_x_))) #define round_to_int(_x_) (static_cast<int>(round(_x_)))
#define floor_to_int(_x_) (static_cast<int>(floor(_x_))) #define floor_to_int(_x_) (static_cast<int>(floor(_x_)))

View file

@ -2,7 +2,7 @@
#include "CameraDefinition.h" #include "CameraDefinition.h"
TEST(Camera, Definition) { TEST(CameraDefinition, constructor) {
CameraDefinition cam; CameraDefinition cam;
cam.setLocationCoords(0.0, 1.0, 1.0); 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); EXPECT_VECTOR3_COORDS(cam.getTarget(), 0.0, 0.0, 0.0);
} }
TEST(Camera, Projection) { TEST(CameraDefinition, unproject) {
CameraDefinition cam; CameraDefinition cam;
Vector3 point;
cam.setLocationCoords(0.0, 1.0, 1.0); cam.setLocationCoords(0.0, 1.0, 1.0);
cam.setTargetCoords(0.0, 0.0, 0.0); cam.setTargetCoords(0.0, 0.0, 0.0);
/* Test the reversibility of projection */ // Test the reversibility of projection
Vector3 point = cam.project(Vector3(12.0, 5.2, -6.3)); point = cam.project(Vector3(12.0, 5.2, -6.3));
point = cam.unproject(point); point = cam.unproject(point);
EXPECT_VECTOR3_COORDS(point, 12.0, 5.2, -6.3); EXPECT_VECTOR3_COORDS(point, 12.0, 5.2, -6.3);
point = cam.project(Vector3(-25.1, 8.3, 1.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); EXPECT_VECTOR3_COORDS(point, -25.1, 8.3, 1.3);
} }
TEST(Camera, Depth) { TEST(CameraDefinition, getRealDepth) {
CameraDefinition cam; CameraDefinition cam;
cam.setLocationCoords(0.0, 0.0, 0.0); cam.setLocationCoords(0.0, 0.0, 0.0);
cam.setTargetCoords(1.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)); Vector3 point = cam.project(Vector3(12.5, 0.0, 0.0));
ASSERT_DOUBLE_EQ(cam.getRealDepth(point), 12.5); ASSERT_DOUBLE_EQ(cam.getRealDepth(point), 12.5);
point = cam.project(Vector3(12.5, 8.0, -3.0)); point = cam.project(Vector3(12.5, 8.0, -3.0));