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);
}
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);

View file

@ -3,16 +3,14 @@
#include "basics_global.h"
#ifdef QT_GUI_LIB
#include <QMatrix4x4>
#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;

View file

@ -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;

View file

@ -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 *) {

View file

@ -1,5 +1,6 @@
#include "OpenGLRenderer.h"
#include <QMatrix4x4>
#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());

View file

@ -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();
}

View file

@ -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;

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) {
pair.second->apply(program, texture_unit);
}

View file

@ -6,8 +6,6 @@
#include <map>
#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);
}

View file

@ -2,9 +2,6 @@
#include <cassert>
#include <QOpenGLShaderProgram>
#include <QColor>
#include <QVector3D>
#include <QMatrix4x4>
#include <QImage>
#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<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() {
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<int>(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<int>(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<float[]>(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<float[]>(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<float[]>(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<float[]>(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<Vector3>(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<float[]>(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>(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());
}
}

View file

@ -3,9 +3,8 @@
#include "opengl_global.h"
class QColor;
class QVector3D;
class QMatrix4x4;
#include <memory>
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<pimpl> impl;
};
}
}

View file

@ -40,6 +40,7 @@ using namespace std;
// Some useful casts
#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 round_to_int(_x_) (static_cast<int>(round(_x_)))
#define floor_to_int(_x_) (static_cast<int>(floor(_x_)))

View file

@ -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));