diff --git a/src/modules/graphics/opengl/PixelEffect.cpp b/src/modules/graphics/opengl/PixelEffect.cpp index 1c9dc684f..d155ee653 100644 --- a/src/modules/graphics/opengl/PixelEffect.cpp +++ b/src/modules/graphics/opengl/PixelEffect.cpp @@ -2,7 +2,6 @@ #include "GLee.h" #include #include -#include namespace { @@ -148,28 +147,28 @@ namespace opengl glUseProgram(0); } - void PixelEffect::sendFloat(const std::string& name, int count, const GLfloat* vec) + void PixelEffect::sendFloat(const std::string& name, int size, const GLfloat* vec, int count) { TemporaryAttacher attacher(this); GLint location = getUniformLocation(name); - if (count < 1 || count > 4) { - throw love::Exception("Invalid variable count: %d (expected 1-4).", count); + if (size < 1 || size > 4) { + throw love::Exception("Invalid variable size: %d (expected 1-4).", size); } - switch (count) { + switch (size) { case 4: - glUniform4fv(location, 1, vec); + glUniform4fv(location, count, vec); break; case 3: - glUniform3fv(location, 1, vec); + glUniform3fv(location, count, vec); break; case 2: - glUniform2fv(location, 1, vec); + glUniform2fv(location, count, vec); break; case 1: default: - glUniform1fv(location, 1, vec); + glUniform1fv(location, count, vec); break; } @@ -177,7 +176,7 @@ namespace opengl checkSetUniformError(); } - void PixelEffect::sendMatrix(const std::string& name, int size, const GLfloat* m) + void PixelEffect::sendMatrix(const std::string& name, int size, const GLfloat* m, int count) { TemporaryAttacher attacher(this); GLint location = getUniformLocation(name); @@ -189,14 +188,14 @@ namespace opengl switch (size) { case 4: - glUniformMatrix4fv(location, 1, GL_FALSE, m); + glUniformMatrix4fv(location, count, GL_FALSE, m); break; case 3: - glUniformMatrix3fv(location, 1, GL_FALSE, m); + glUniformMatrix3fv(location, count, GL_FALSE, m); break; case 2: default: - glUniformMatrix2fv(location, 1, GL_FALSE, m); + glUniformMatrix2fv(location, count, GL_FALSE, m); break; } @@ -257,9 +256,9 @@ namespace opengl if (GL_INVALID_OPERATION == error_code) { throw love::Exception( "Invalid operation:\n" - "Trying to send more than one value to a float variable, or" - "Size of shader variable does not match indicated size, or" - "Invalid variable name."); + "- Trying to send the wrong value type to shader variable, or\n" + "- Trying to send array values with wrong dimension, or\n" + "- Invalid variable name."); } } } // opengl diff --git a/src/modules/graphics/opengl/PixelEffect.h b/src/modules/graphics/opengl/PixelEffect.h index db439db4c..47927b627 100644 --- a/src/modules/graphics/opengl/PixelEffect.h +++ b/src/modules/graphics/opengl/PixelEffect.h @@ -28,8 +28,8 @@ namespace opengl static void detach(); static bool isSupported(); - void sendFloat(const std::string& name, int count, const GLfloat* vec); - void sendMatrix(const std::string& name, int size, const GLfloat* m); + void sendFloat(const std::string& name, int size, const GLfloat* vec, int count); + void sendMatrix(const std::string& name, int size, const GLfloat* m, int count); void sendImage(const std::string& name, const Image& image); void sendCanvas(const std::string& name, const Canvas& canvas); diff --git a/src/modules/graphics/opengl/wrap_PixelEffect.cpp b/src/modules/graphics/opengl/wrap_PixelEffect.cpp index 9e7e9d909..fa02aa6bf 100644 --- a/src/modules/graphics/opengl/wrap_PixelEffect.cpp +++ b/src/modules/graphics/opengl/wrap_PixelEffect.cpp @@ -2,6 +2,8 @@ #include "wrap_Image.h" #include "wrap_Canvas.h" #include +#include +using namespace std; namespace love { @@ -21,48 +23,128 @@ namespace opengl return 1; } - int w_PixelEffect_sendFloat(lua_State * L) + static int _sendScalars(lua_State * L, PixelEffect * effect, const char * name, int count) { - size_t count = lua_gettop(L) - 2; - PixelEffect * effect = luax_checkpixeleffect(L, 1); - const char* name = luaL_checkstring(L, 2); - - if (count < 1 || count > 4) - return luaL_error(L, "Invalid variable count (expected 1-4, got %d).", count); - - float values[4] = {0,0,0,0}; - for (unsigned int i = 0; i < count; ++i) - values[i] = (float) luaL_checknumber(L, i+1 + 2); - - try { - effect->sendFloat(name, count, values); - } catch(love::Exception& e) { - luaL_error(L, e.what()); + float * values = new float[count]; + for (int i = 0; i < count; ++i) { + if (!lua_isnumber(L, 3 + i)) { + delete[] values; + return luaL_typerror(L, 3 + i, "number"); + } + values[i] = (float)lua_tonumber(L, 3 + i); } + try { + effect->sendFloat(name, 1, values, count); + } catch(love::Exception& e) { + delete[] values; + return luaL_error(L, e.what()); + } + + delete[] values; return 0; } + static int _sendVectors(lua_State * L, PixelEffect * effect, const char * name, int count) + { + int dimension = lua_objlen(L, 3); + float * values = new float[count * dimension]; + + for (int i = 0; i < count; ++i) { + if (!lua_istable(L, 3 + i)) { + delete[] values; + return luaL_typerror(L, 3 + i, "table"); + } + if (lua_objlen(L, 3 + i) != dimension) { + delete[] values; + return luaL_error(L, "Error in argument %d: Expected table size %d, got %d.", + 3+i, dimension, lua_objlen(L, 3+i)); + } + + for (int k = 1; k <= dimension; ++k) { + lua_rawgeti(L, 3 + i, k); + values[i * dimension + k - 1] = (float)lua_tonumber(L, -1); + } + lua_pop(L, dimension); + } + + try { + effect->sendFloat(name, dimension, values, count); + } catch(love::Exception& e) { + delete[] values; + return luaL_error(L, e.what()); + } + + delete[] values; + return 0; + } + + int w_PixelEffect_sendFloat(lua_State * L) + { + PixelEffect * effect = luax_checkpixeleffect(L, 1); + const char* name = luaL_checkstring(L, 2); + int count = lua_gettop(L) - 2; + + if (count < 1) + return luaL_error(L, "No variable to send."); + + if (lua_isnumber(L, 3)) + return _sendScalars(L, effect, name, count); + else if (lua_istable(L, 3)) + return _sendVectors(L, effect, name, count); + + return luaL_typerror(L, 3, "number or table"); + } + int w_PixelEffect_sendMatrix(lua_State * L) { - size_t count = lua_gettop(L) - 3; + int count = lua_gettop(L) - 2; PixelEffect * effect = luax_checkpixeleffect(L, 1); const char* name = luaL_checkstring(L, 2); - int size = luaL_checkinteger(L, 3); - if (size < 2 || size > 4) - return luaL_error(L, "Invalid matrix size: %dx%d (only 2x2, 3x3 and 4x4 matrices are supported).", count, count); + if (!lua_istable(L, 3)) + return luaL_typerror(L, 3, "matrix table"); - float values[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; - for (unsigned int i = 0; i < count; ++i) - values[i] = (float) luaL_checknumber(L, i+1 + 3); + lua_getfield(L, 3, "dimension"); + int dimension = lua_tointeger(L, -1); + lua_pop(L, 1); - try { - effect->sendFloat(name, size, values); - } catch(love::Exception& e) { - luaL_error(L, e.what()); + if (dimension < 2 || dimension > 4) + return luaL_error(L, "Invalid matrix size: %dx%d (only 2x2, 3x3 and 4x4 matrices are supported).", + count, count); + + float * values = new float[dimension * dimension * count]; + for (int i = 0; i < count; ++i) { + lua_getfield(L, 3+i, "dimension"); + if (lua_tointeger(L, -1) != dimension) { + // You unlock this door with the key of imagination. Beyond it is + // another dimension: a dimension of sound, a dimension of sight, + // a dimension of mind. You're moving into a land of both shadow + // and substance, of things and ideas. You've just crossed over + // into... the Twilight Zone. + int other_dimension = lua_tointeger(L, -1); + delete[] values; + return luaL_error(L, "Invalid matrix size at argument %d: Expected size %dx%d, got %dx%d.", + 3+i, dimension, dimension, other_dimension, other_dimension); + } + + for (int k = 1; k <= dimension*dimension; ++k) { + lua_rawgeti(L, 3+i, k); + values[i * dimension * dimension + k - 1] = (float)lua_tonumber(L, -1); + cout << i << "." << k << " = " << (float)lua_tonumber(L, -1) << endl; + } + + lua_pop(L, 1 + dimension); } + try { + effect->sendMatrix(name, dimension, values, count); + } catch(love::Exception& e) { + delete[] values; + return luaL_error(L, e.what()); + } + + delete[] values; return 0; } diff --git a/src/scripts/graphics.lua b/src/scripts/graphics.lua index ad2c07f5a..bfb051873 100644 --- a/src/scripts/graphics.lua +++ b/src/scripts/graphics.lua @@ -1318,9 +1318,26 @@ do return table.concat(lines, "\n") end + -- helper to transform a matrix from {{a,b,c}, {d,e,f}, ...} to + -- {a, b, c, d, e, f, ...} + local function flattenMatrices(mat, ...) + if not mat then return end + + local ret,l = {}, 1 + ret.dimension = #mat + + for i = 1,#mat do + for k = 1,#mat[i] do + ret[l], l = tonumber(mat[i][k]), l+1 + end + end + + return ret, flattenMatrices(...) + end + -- automagic uniform setter local function pixeleffect_dispatch_send(self, name, value, ...) - if type(value) == "number" then -- scalar or vector + if type(value) == "number" then -- scalar self:sendFloat(name, value, ...) elseif type(value) == "userdata" and value:typeOf("Image") then self:sendImage(name, value) @@ -1328,15 +1345,9 @@ do self:sendCanvas(name, value) elseif type(value) == "table" then -- vector or matrix if type(value[1]) == "number" then - self:sendFloat(name, unpack(value)) + self:sendFloat(name, value, ...) elseif type(value[1]) == "table" then - local m,l = {}, 0 - for i = 1,#value do - for k = 1,#value[i] do - m[l], l = tonumber(value[i][k]), l+1 - end - end - self:sendMatrix(name, #value, unpack(m)) + self:sendMatrix(name, flattenMatrices(value, ...)) else error("Cannot send value (unsupported type: {"..type(value[1]).."}).") end diff --git a/src/scripts/graphics.lua.h b/src/scripts/graphics.lua.h index 929f0f09c..37087fdb9 100644 --- a/src/scripts/graphics.lua.h +++ b/src/scripts/graphics.lua.h @@ -6359,6 +6359,33 @@ const unsigned char graphics_lua[] = 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6e, 0x63, 0x61, 0x74, 0x28, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x2c, 0x20, 0x22, 0x5c, 0x6e, 0x22, 0x29, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a,0x0a, + 0x09, 0x2d, 0x2d, 0x20, 0x68, 0x65, 0x6c, 0x70, 0x65, 0x72, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x72, 0x61, 0x6e, + 0x73, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x61, 0x20, 0x6d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x20, 0x66, 0x72, 0x6f, + 0x6d, 0x20, 0x7b, 0x7b, 0x61, 0x2c, 0x62, 0x2c, 0x63, 0x7d, 0x2c, 0x20, 0x7b, 0x64, 0x2c, 0x65, 0x2c, 0x66, + 0x7d, 0x2c, 0x20, 0x2e, 0x2e, 0x2e, 0x7d, 0x20, 0x74, 0x6f, 0x0a, + 0x09, 0x2d, 0x2d, 0x20, 0x7b, 0x61, 0x2c, 0x20, 0x62, 0x2c, 0x20, 0x63, 0x2c, 0x20, 0x64, 0x2c, 0x20, 0x65, + 0x2c, 0x20, 0x66, 0x2c, 0x20, 0x2e, 0x2e, 0x2e, 0x7d, 0x0a, + 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x66, 0x6c, + 0x61, 0x74, 0x74, 0x65, 0x6e, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x63, 0x65, 0x73, 0x28, 0x6d, 0x61, 0x74, 0x2c, + 0x20, 0x2e, 0x2e, 0x2e, 0x29, 0x0a, + 0x09, 0x09, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6d, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, + 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x65, 0x6e, 0x64, 0x0a,0x0a, + 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x74, 0x2c, 0x6c, 0x20, 0x3d, 0x20, 0x7b, 0x7d, + 0x2c, 0x20, 0x31, 0x0a, + 0x09, 0x09, 0x72, 0x65, 0x74, 0x2e, 0x64, 0x69, 0x6d, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x3d, 0x20, + 0x23, 0x6d, 0x61, 0x74, 0x0a,0x0a, + 0x09, 0x09, 0x66, 0x6f, 0x72, 0x20, 0x69, 0x20, 0x3d, 0x20, 0x31, 0x2c, 0x23, 0x6d, 0x61, 0x74, 0x20, 0x64, + 0x6f, 0x0a, + 0x09, 0x09, 0x09, 0x66, 0x6f, 0x72, 0x20, 0x6b, 0x20, 0x3d, 0x20, 0x31, 0x2c, 0x23, 0x6d, 0x61, 0x74, 0x5b, + 0x69, 0x5d, 0x20, 0x64, 0x6f, 0x0a, + 0x09, 0x09, 0x09, 0x09, 0x72, 0x65, 0x74, 0x5b, 0x6c, 0x5d, 0x2c, 0x20, 0x6c, 0x20, 0x3d, 0x20, 0x74, 0x6f, + 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x28, 0x6d, 0x61, 0x74, 0x5b, 0x69, 0x5d, 0x5b, 0x6b, 0x5d, 0x29, 0x2c, + 0x20, 0x6c, 0x2b, 0x31, 0x0a, + 0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, + 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a,0x0a, + 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x2c, 0x20, 0x66, 0x6c, 0x61, 0x74, + 0x74, 0x65, 0x6e, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x63, 0x65, 0x73, 0x28, 0x2e, 0x2e, 0x2e, 0x29, 0x0a, + 0x09, 0x65, 0x6e, 0x64, 0x0a,0x0a, 0x09, 0x2d, 0x2d, 0x20, 0x61, 0x75, 0x74, 0x6f, 0x6d, 0x61, 0x67, 0x69, 0x63, 0x20, 0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x73, 0x65, 0x74, 0x74, 0x65, 0x72, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x70, 0x69, @@ -6367,8 +6394,7 @@ const unsigned char graphics_lua[] = 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2c, 0x20, 0x2e, 0x2e, 0x2e, 0x29, 0x0a, 0x09, 0x09, 0x69, 0x66, 0x20, 0x74, 0x79, 0x70, 0x65, 0x28, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x29, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x2d, 0x20, 0x73, 0x63, 0x61, 0x6c, 0x61, 0x72, 0x20, 0x6f, 0x72, - 0x20, 0x76, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x2d, 0x20, 0x73, 0x63, 0x61, 0x6c, 0x61, 0x72, 0x0a, 0x09, 0x09, 0x09, 0x73, 0x65, 0x6c, 0x66, 0x3a, 0x73, 0x65, 0x6e, 0x64, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2c, 0x20, 0x2e, 0x2e, 0x2e, 0x29, 0x0a, 0x09, 0x09, 0x65, 0x6c, 0x73, 0x65, 0x69, 0x66, 0x20, 0x74, 0x79, 0x70, 0x65, 0x28, 0x76, 0x61, 0x6c, 0x75, @@ -6391,25 +6417,13 @@ const unsigned char graphics_lua[] = 0x5d, 0x29, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x73, 0x65, 0x6c, 0x66, 0x3a, 0x73, 0x65, 0x6e, 0x64, 0x46, 0x6c, 0x6f, 0x61, 0x74, - 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x75, 0x6e, 0x70, 0x61, 0x63, 0x6b, 0x28, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x29, 0x29, 0x0a, + 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2c, 0x20, 0x2e, 0x2e, 0x2e, 0x29, 0x0a, 0x09, 0x09, 0x09, 0x65, 0x6c, 0x73, 0x65, 0x69, 0x66, 0x20, 0x74, 0x79, 0x70, 0x65, 0x28, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5b, 0x31, 0x5d, 0x29, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x22, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6d, 0x2c, 0x6c, 0x20, 0x3d, 0x20, 0x7b, 0x7d, - 0x2c, 0x20, 0x30, 0x0a, - 0x09, 0x09, 0x09, 0x09, 0x66, 0x6f, 0x72, 0x20, 0x69, 0x20, 0x3d, 0x20, 0x31, 0x2c, 0x23, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x20, 0x64, 0x6f, 0x0a, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x66, 0x6f, 0x72, 0x20, 0x6b, 0x20, 0x3d, 0x20, 0x31, 0x2c, 0x23, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x5b, 0x69, 0x5d, 0x20, 0x64, 0x6f, 0x0a, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x6d, 0x5b, 0x6c, 0x5d, 0x2c, 0x20, 0x6c, 0x20, 0x3d, 0x20, 0x74, 0x6f, - 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x28, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5b, 0x69, 0x5d, 0x5b, 0x6b, 0x5d, - 0x29, 0x2c, 0x20, 0x6c, 0x2b, 0x31, 0x0a, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x73, 0x65, 0x6c, 0x66, 0x3a, 0x73, 0x65, 0x6e, 0x64, 0x4d, 0x61, 0x74, 0x72, 0x69, - 0x78, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x23, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2c, 0x20, 0x75, 0x6e, - 0x70, 0x61, 0x63, 0x6b, 0x28, 0x6d, 0x29, 0x29, 0x0a, + 0x78, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x66, 0x6c, 0x61, 0x74, 0x74, 0x65, 0x6e, 0x4d, 0x61, 0x74, + 0x72, 0x69, 0x63, 0x65, 0x73, 0x28, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2c, 0x20, 0x2e, 0x2e, 0x2e, 0x29, 0x29, 0x0a, 0x09, 0x09, 0x09, 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x22, 0x43, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x28, 0x75, 0x6e, 0x73, 0x75, 0x70, 0x70,