Browse Source

Fix issue #292: Can't send arrays to pixeleffects.

Arrays of numbers, vectors and matrices are supported.
vrld 14 years ago
parent
commit
eec0250545

+ 15 - 16
src/modules/graphics/opengl/PixelEffect.cpp

@@ -2,7 +2,6 @@
 #include "GLee.h"
 #include <limits>
 #include <sstream>
-#include <iostream>
 
 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

+ 2 - 2
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);
 

+ 103 - 21
src/modules/graphics/opengl/wrap_PixelEffect.cpp

@@ -2,6 +2,8 @@
 #include "wrap_Image.h"
 #include "wrap_Canvas.h"
 #include <string>
+#include <iostream>
+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);
+		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);
+		}
 
-		if (count < 1 || count > 4)
-			return luaL_error(L, "Invalid variable count (expected 1-4, got %d).", count);
+		try {
+			effect->sendFloat(name, 1, values, count);
+		} catch(love::Exception& e) {
+			delete[] values;
+			return luaL_error(L, e.what());
+		}
 
-		float values[4] = {0,0,0,0};
-		for (unsigned int i = 0; i < count; ++i)
-			values[i] = (float) luaL_checknumber(L, i+1 + 2);
+		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, count, values);
+			effect->sendFloat(name, dimension, values, count);
 		} catch(love::Exception& e) {
-			luaL_error(L, e.what());
+			delete[] values;
+			return luaL_error(L, e.what());
 		}
 
+		delete[] values;
 		return 0;
 	}
 
-	int w_PixelEffect_sendMatrix(lua_State * L)
+	int w_PixelEffect_sendFloat(lua_State * L)
 	{
-		size_t count = lua_gettop(L) - 3;
 		PixelEffect * effect = luax_checkpixeleffect(L, 1);
 		const char* name = luaL_checkstring(L, 2);
-		int size = luaL_checkinteger(L, 3);
+		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");
+	}
 
-		if (size < 2 || size > 4)
-			return luaL_error(L, "Invalid matrix size: %dx%d (only 2x2, 3x3 and 4x4 matrices are supported).", count, count);
+	int w_PixelEffect_sendMatrix(lua_State * L)
+	{
+		int count = lua_gettop(L) - 2;
+		PixelEffect * effect = luax_checkpixeleffect(L, 1);
+		const char* name = luaL_checkstring(L, 2);
 
-		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);
+		if (!lua_istable(L, 3))
+			return luaL_typerror(L, 3, "matrix table");
+
+		lua_getfield(L, 3, "dimension");
+		int dimension = lua_tointeger(L, -1);
+		lua_pop(L, 1);
+
+		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->sendFloat(name, size, values);
+			effect->sendMatrix(name, dimension, values, count);
 		} catch(love::Exception& e) {
-			luaL_error(L, e.what());
+			delete[] values;
+			return luaL_error(L, e.what());
 		}
 
+		delete[] values;
 		return 0;
 	}
 

+ 20 - 9
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

+ 31 - 17
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,