From f30a0d72f0844ecf7d2f4e441a152b9d49f3451e Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Fri, 25 Apr 2014 20:32:42 -0300 Subject: [PATCH] Added Shader:getExternVariable(name). Returns the base type name ('float', 'image', etc.), the number of components (2 for a vec2), and number of array elements (1 for a non-array variable) for the extern variable with the specified name in the shader. Returns nil if the variable either doesn't exist or was optimized out by the driver's shader compiler. --- src/modules/graphics/opengl/Shader.cpp | 50 +++++++++++++++++--- src/modules/graphics/opengl/Shader.h | 52 ++++++++++++++------- src/modules/graphics/opengl/wrap_Shader.cpp | 33 +++++++++++++ src/modules/graphics/opengl/wrap_Shader.h | 1 + 4 files changed, 114 insertions(+), 22 deletions(-) diff --git a/src/modules/graphics/opengl/Shader.cpp b/src/modules/graphics/opengl/Shader.cpp index 2240b55f5..b95a0d10b 100644 --- a/src/modules/graphics/opengl/Shader.cpp +++ b/src/modules/graphics/opengl/Shader.cpp @@ -255,7 +255,7 @@ void Shader::mapActiveUniforms() } // If this is a built-in (LOVE-created) uniform, store the location. - BuiltinExtern builtin; + BuiltinUniform builtin; if (builtinNames.find(u.name.c_str(), builtin)) builtinUniforms[int(builtin)] = u.location; @@ -660,19 +660,36 @@ int Shader::getTextureUnit(const std::string &name) return texunit; } +Shader::UniformType Shader::getExternVariable(const std::string &name, int &components, int &count) +{ + auto it = uniforms.find(name); + + if (it == uniforms.end()) + { + components = 0; + count = 0; + return UNIFORM_UNKNOWN; + } + + components = getUniformTypeSize(it->second.type); + count = (int) it->second.count; + + return it->second.baseType; +} + bool Shader::hasVertexAttrib(OpenGL::VertexAttrib attrib) const { return vertexAttributes[int(attrib)] != -1; } -bool Shader::hasBuiltinExtern(BuiltinExtern builtin) const +bool Shader::hasBuiltinUniform(BuiltinUniform builtin) const { return builtinUniforms[int(builtin)] != -1; } -bool Shader::sendBuiltinFloat(BuiltinExtern builtin, int size, const GLfloat *vec, int count) +bool Shader::sendBuiltinFloat(BuiltinUniform builtin, int size, const GLfloat *vec, int count) { - if (!hasBuiltinExtern(builtin)) + if (!hasBuiltinUniform(builtin)) return false; GLint location = builtinUniforms[int(builtin)]; @@ -766,6 +783,16 @@ bool Shader::isSupported() return GLEE_VERSION_2_0 && getGLSLVersion() >= "1.2"; } +bool Shader::getConstant(const char *in, UniformType &out) +{ + return uniformTypes.find(in, out); +} + +bool Shader::getConstant(UniformType in, const char *&out) +{ + return uniformTypes.find(in, out); +} + StringMap::Entry Shader::typeNameEntries[] = { {"vertex", Shader::TYPE_VERTEX}, @@ -774,6 +801,17 @@ StringMap::Entry Shader::typeNameEntr StringMap Shader::typeNames(Shader::typeNameEntries, sizeof(Shader::typeNameEntries)); +StringMap::Entry Shader::uniformTypeEntries[] = +{ + {"float", Shader::UNIFORM_FLOAT}, + {"int", Shader::UNIFORM_INT}, + {"bool", Shader::UNIFORM_BOOL}, + {"image", Shader::UNIFORM_SAMPLER}, + {"unknown", Shader::UNIFORM_UNKNOWN}, +}; + +StringMap Shader::uniformTypes(Shader::uniformTypeEntries, sizeof(Shader::uniformTypeEntries)); + StringMap::Entry Shader::attribNameEntries[] = { {"love_PseudoInstanceID", OpenGL::ATTRIB_PSEUDO_INSTANCE_ID}, @@ -781,12 +819,12 @@ StringMap::Entry Shader::attribNa StringMap Shader::attribNames(Shader::attribNameEntries, sizeof(Shader::attribNameEntries)); -StringMap::Entry Shader::builtinNameEntries[] = +StringMap::Entry Shader::builtinNameEntries[] = { {"love_ScreenSize", Shader::BUILTIN_SCREEN_SIZE}, }; -StringMap Shader::builtinNames(Shader::builtinNameEntries, sizeof(Shader::builtinNameEntries)); +StringMap Shader::builtinNames(Shader::builtinNameEntries, sizeof(Shader::builtinNameEntries)); } // opengl } // graphics diff --git a/src/modules/graphics/opengl/Shader.h b/src/modules/graphics/opengl/Shader.h index db116cc47..38c70a137 100644 --- a/src/modules/graphics/opengl/Shader.h +++ b/src/modules/graphics/opengl/Shader.h @@ -56,13 +56,24 @@ public: TYPE_MAX_ENUM }; - // Built-in extern (uniform) variables. - enum BuiltinExtern + // Built-in uniform (extern) variables. + enum BuiltinUniform { BUILTIN_SCREEN_SIZE, BUILTIN_MAX_ENUM }; + // Types of potential uniform (extern) variables used in love's shaders. + enum UniformType + { + UNIFORM_FLOAT, + UNIFORM_INT, + UNIFORM_BOOL, + UNIFORM_SAMPLER, + UNIFORM_UNKNOWN, + UNIFORM_MAX_ENUM + }; + // Type for a list of shader source codes in the form of sources[shadertype] = code typedef std::map ShaderSources; @@ -135,12 +146,25 @@ public: **/ void sendTexture(const std::string &name, Texture *texture); + /** + * Gets the type, number of components, and number of array elements of + * an active 'extern' (uniform) variable in the shader. If a uniform + * variable with the specified name doesn't exist, returns UNIFORM_UNKNOWN + * and sets the 'components' and 'count' values to 0. + * + * @param name The name of the uniform variable in the source code. + * @param[out] components Number of components of the variable (2 for vec2.) + * @param[out] count Number of array elements, if the variable is an array. + * @return The base type of the uniform variable. + **/ + UniformType getExternVariable(const std::string &name, int &components, int &count); + /** * Internal use only. **/ bool hasVertexAttrib(OpenGL::VertexAttrib attrib) const; - bool hasBuiltinExtern(BuiltinExtern builtin) const; - bool sendBuiltinFloat(BuiltinExtern builtin, int size, const GLfloat *m, int count); + bool hasBuiltinUniform(BuiltinUniform builtin) const; + bool sendBuiltinFloat(BuiltinUniform builtin, int size, const GLfloat *m, int count); void checkSetScreenParams(); const std::map &getBoundRetainables() const; @@ -148,17 +172,10 @@ public: static std::string getGLSLVersion(); static bool isSupported(); -private: + static bool getConstant(const char *in, UniformType &out); + static bool getConstant(UniformType in, const char *&out); - // Types of potential uniform variables used in love's shaders. - enum UniformType - { - UNIFORM_FLOAT, - UNIFORM_INT, - UNIFORM_BOOL, - UNIFORM_SAMPLER, - UNIFORM_UNKNOWN - }; +private: // Represents a single uniform/extern shader variable. struct Uniform @@ -227,13 +244,16 @@ private: static StringMap::Entry typeNameEntries[]; static StringMap typeNames; + static StringMap::Entry uniformTypeEntries[]; + static StringMap uniformTypes; + // Names for the generic vertex attributes used by love. static StringMap::Entry attribNameEntries[]; static StringMap attribNames; // Names for the built-in uniform variables. - static StringMap::Entry builtinNameEntries[]; - static StringMap builtinNames; + static StringMap::Entry builtinNameEntries[]; + static StringMap builtinNames; }; } // opengl diff --git a/src/modules/graphics/opengl/wrap_Shader.cpp b/src/modules/graphics/opengl/wrap_Shader.cpp index dde23fde5..ed3ee1ed5 100644 --- a/src/modules/graphics/opengl/wrap_Shader.cpp +++ b/src/modules/graphics/opengl/wrap_Shader.cpp @@ -346,6 +346,38 @@ int w_Shader_send(lua_State *L) return luaL_argerror(L, 3, "number, boolean, table, image, or canvas expected"); } +int w_Shader_getExternVariable(lua_State *L) +{ + Shader *shader = luax_checkshader(L, 1); + const char *name = luaL_checkstring(L, 2); + + int components = 0; + int arrayelements = 0; + Shader::UniformType type = Shader::UNIFORM_UNKNOWN; + + type = shader->getExternVariable(name, components, arrayelements); + + // Check if the variable exists (function will set components to 0 if not.) + if (components > 0) + { + const char *tname = nullptr; + if (!Shader::getConstant(type, tname)) + return luaL_error(L, "Unknown extern variable type name."); + + lua_pushstring(L, tname); + lua_pushinteger(L, components); + lua_pushinteger(L, arrayelements); + } + else + { + lua_pushnil(L); + lua_pushnil(L); + lua_pushnil(L); + } + + return 3; +} + static const luaL_Reg functions[] = { { "getWarnings", w_Shader_getWarnings }, @@ -355,6 +387,7 @@ static const luaL_Reg functions[] = { "sendMatrix", w_Shader_sendMatrix }, { "sendTexture", w_Shader_sendTexture }, { "send", w_Shader_send }, + { "getExternVariable", w_Shader_getExternVariable }, // Deprecated since 0.9.1. { "sendImage", w_Shader_sendTexture }, diff --git a/src/modules/graphics/opengl/wrap_Shader.h b/src/modules/graphics/opengl/wrap_Shader.h index be7b81db4..f89295399 100644 --- a/src/modules/graphics/opengl/wrap_Shader.h +++ b/src/modules/graphics/opengl/wrap_Shader.h @@ -38,6 +38,7 @@ int w_Shader_sendFloat(lua_State *L); int w_Shader_sendMatrix(lua_State *L); int w_Shader_sendTexture(lua_State *L); int w_Shader_send(lua_State *L); +int w_Shader_getExternVariable(lua_State *L); extern "C" int luaopen_shader(lua_State *L); } // opengl