From f36a3c866eb36e16b2b1365b400996e78d352370 Mon Sep 17 00:00:00 2001 From: skyjake Date: Fri, 19 Apr 2013 13:58:24 +0300 Subject: [PATCH] libdeng2: Implemented logical state of GLUniform Tracking the current value, notifying audiences of changes. --- doomsday/libgui/include/de/gui/gluniform.h | 82 +++++- doomsday/libgui/src/gluniform.cpp | 310 ++++++++++++++++++++- 2 files changed, 387 insertions(+), 5 deletions(-) diff --git a/doomsday/libgui/include/de/gui/gluniform.h b/doomsday/libgui/include/de/gui/gluniform.h index e0051dd4b9..0d2b78a825 100644 --- a/doomsday/libgui/include/de/gui/gluniform.h +++ b/doomsday/libgui/include/de/gui/gluniform.h @@ -20,20 +20,98 @@ #define LIBGUI_GLUNIFORM_H #include +#include +#include +#include #include "libgui.h" +#include + namespace de { /** - * GL uniform. + * Constant variable or a sampler in a shader. + * + * GLUniform's public interface allows the uniform value to be manipulated like + * any other native variable (assignment, arithmetic, etc.). + * + * The value of the uniform is stored locally in the GLUniform instance. When + * the uniform has been bound to programs and its value changes, the programs + * are notified and they mark the uniform as changed. When the program is then + * later taken into use, the updated value of the changed uniforms is sent to + * GL. * * @ingroup gl */ class LIBGUI_PUBLIC GLUniform { public: - GLUniform(); + enum Type + { + Int, + UInt, + Float, + Vector2, + Vector3, + Vector4, + Matrix3x3, + Matrix4x4, + Texture2D + }; + + /** + * Notified when the value of the uniform changes. + */ + DENG2_DEFINE_AUDIENCE(ValueChange, void uniformValueChanged(GLUniform &)) + + /** + * Notified when the uniform instance is deleted. + */ + DENG2_DEFINE_AUDIENCE(Deletion, void uniformDeleted(GLUniform &)) + +public: + GLUniform(QLatin1String const &nameInShader, Type uniformType); + + virtual ~GLUniform(); + + void setName(QLatin1String const &nameInShader); + + /** + * Returns the name of the uniform as it appears in shaders. + */ + QLatin1String name() const; + + /** + * Returns the value type of the shader. + */ + Type type() const; + + GLUniform &operator = (dint value); + GLUniform &operator = (duint value); + GLUniform &operator = (dfloat value); + GLUniform &operator = (Vector2f const &vec); + GLUniform &operator = (Vector3f const &vec); + GLUniform &operator = (Vector4f const &vec); + GLUniform &operator = (Matrix3f const &vec); + GLUniform &operator = (Matrix4f const &vec); + + operator dint() const { return toInt(); } + operator duint() const { return toUInt(); } + operator dfloat() const { return toFloat(); } + operator ddouble() const { return ddouble(toFloat()); } + operator Vector2f() const { return toVector2f(); } + operator Vector3f() const { return toVector3f(); } + operator Vector4f() const { return toVector4f(); } + + dint toInt() const; + duint toUInt() const; + dfloat toFloat() const; + Vector2f const &toVector2f() const; + Vector3f const &toVector3f() const; + Vector4f const &toVector4f() const; + Matrix3f const &toMatrix3f() const; + Matrix4f const &toMatrix4f() const; private: DENG2_PRIVATE(d) diff --git a/doomsday/libgui/src/gluniform.cpp b/doomsday/libgui/src/gluniform.cpp index edd4f65140..9eb07b319a 100644 --- a/doomsday/libgui/src/gluniform.cpp +++ b/doomsday/libgui/src/gluniform.cpp @@ -17,16 +17,320 @@ */ #include "de/GLUniform" +#include "de/GLTexture" +#include +#include namespace de { DENG2_PIMPL(GLUniform) { - Instance(Public *i) : Base(i) - {} + Block name; + Type type; + union Value { + dint int32; + duint uint32; + dfloat float32; + Vector4f *vector; + Matrix3f *mat3; + Matrix4f *mat4; + GLTexture *tex; + } value; + + Instance(Public *i, QLatin1String const &n, Type t) + : Base(i), name(n.latin1()), type(t) + { + name.append('\0'); + + // Allocate the value type. + zap(value); + switch(type) + { + case Vector2: + case Vector3: + case Vector4: + value.vector = new Vector4f; + break; + + case Matrix3x3: + value.mat3 = new Matrix3f; + break; + + case Matrix4x4: + value.mat4 = new Matrix4f; + break; + + default: + break; + } + } + + ~Instance() + { + switch(type) + { + case Vector2: + case Vector3: + case Vector4: + delete value.vector; + break; + + case Matrix3x3: + delete value.mat3; + break; + + case Matrix4x4: + delete value.mat4; + break; + + default: + break; + } + } + + /** + * @return Returns @c true if the value changed. + */ + template + bool set(Type numValue) + { + DENG2_ASSERT(type == Int || type == UInt || type == Float); + + switch(type) + { + case Int: + if(value.int32 != dint(numValue)) + { + value.int32 = dint(numValue); + return true; + } + break; + + case UInt: + if(value.uint32 != duint(numValue)) + { + value.uint32 = duint(numValue); + return true; + } + break; + + case Float: + if(!fequal(value.float32, dfloat(numValue))) + { + value.float32 = dfloat(numValue); + return true; + } + break; + + default: + break; + } + + return false; + } + + void markAsChanged() + { + DENG2_FOR_PUBLIC_AUDIENCE(ValueChange, i) i->uniformValueChanged(self); + } }; -GLUniform::GLUniform() : d(new Instance(this)) +GLUniform::GLUniform(QLatin1String const &nameInShader, Type uniformType) + : d(new Instance(this, nameInShader, uniformType)) {} +GLUniform::~GLUniform() +{ + DENG2_FOR_AUDIENCE(Deletion, i) i->uniformDeleted(*this); +} + +void GLUniform::setName(QLatin1String const &nameInShader) +{ + d->name = Block(nameInShader.latin1()); + d->name.append('\0'); +} + +QLatin1String GLUniform::name() const +{ + return QLatin1String(d->name); +} + +GLUniform::Type GLUniform::type() const +{ + return d->type; +} + +GLUniform &GLUniform::operator = (dint value) +{ + if(d->set(value)) + { + d->markAsChanged(); + } + return *this; +} + +GLUniform &GLUniform::operator = (duint value) +{ + if(d->set(value)) + { + d->markAsChanged(); + } + return *this; +} + +GLUniform &GLUniform::operator = (dfloat value) +{ + if(d->set(value)) + { + d->markAsChanged(); + } + return *this; +} + +GLUniform &GLUniform::operator = (Vector2f const &vec) +{ + DENG2_ASSERT(d->type == Vector2); + + if(Vector2f(*d->value.vector) != vec) + { + *d->value.vector = Vector4f(vec); + d->markAsChanged(); + } + return *this; +} + +GLUniform &GLUniform::operator = (Vector3f const &vec) +{ + DENG2_ASSERT(d->type == Vector3); + + if(Vector3f(*d->value.vector) != vec) + { + *d->value.vector = vec; + d->markAsChanged(); + } + return *this; +} + +GLUniform &GLUniform::operator = (Vector4f const &vec) +{ + DENG2_ASSERT(d->type == Vector4); + + if(*d->value.vector != vec) + { + *d->value.vector = vec; + d->markAsChanged(); + } + return *this; +} + +GLUniform &GLUniform::operator = (Matrix3f const &mat) +{ + DENG2_ASSERT(d->type == Matrix3x3); + + *d->value.mat3 = mat; + d->markAsChanged(); + + return *this; +} + +GLUniform &GLUniform::operator = (Matrix4f const &mat) +{ + DENG2_ASSERT(d->type == Matrix4x4); + + *d->value.mat4 = mat; + d->markAsChanged(); + + return *this; +} + +dint GLUniform::toInt() const +{ + DENG2_ASSERT(d->type == Int || d->type == UInt || d->type == Float); + + switch(d->type) + { + case Int: + return d->value.int32; + + case UInt: + return dint(d->value.uint32); + + case Float: + return dint(d->value.float32); + + default: + return 0; + } +} + +duint de::GLUniform::toUInt() const +{ + DENG2_ASSERT(d->type == Int || d->type == UInt || d->type == Float); + + switch(d->type) + { + case Int: + return duint(d->value.int32); + + case UInt: + return d->value.uint32; + + case Float: + return duint(d->value.float32); + + default: + return 0; + } +} + +dfloat GLUniform::toFloat() const +{ + DENG2_ASSERT(d->type == Int || d->type == UInt || d->type == Float); + + switch(d->type) + { + case Int: + return dfloat(d->value.int32); + + case UInt: + return dfloat(d->value.uint32); + + case Float: + return d->value.float32; + + default: + return 0; + } +} + +Vector2f const &GLUniform::toVector2f() const +{ + DENG2_ASSERT(d->type == Vector2 || d->type == Vector3 || d->type == Vector4); + return *d->value.vector; +} + +Vector3f const &GLUniform::toVector3f() const +{ + DENG2_ASSERT(d->type == Vector2 || d->type == Vector3 || d->type == Vector4); + return *d->value.vector; +} + +Vector4f const &GLUniform::toVector4f() const +{ + DENG2_ASSERT(d->type == Vector2 || d->type == Vector3 || d->type == Vector4); + return *d->value.vector; +} + +Matrix3f const &GLUniform::toMatrix3f() const +{ + DENG2_ASSERT(d->type == Matrix3x3); + return *d->value.mat3; +} + +Matrix4f const &GLUniform::toMatrix4f() const +{ + DENG2_ASSERT(d->type == Matrix4x4); + return *d->value.mat4; +} + } // namespace de