123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383 |
- /**
- * Copyright (c) 2006-2013 LOVE Development Team
- *
- * This software is provided 'as-is', without any express or implied
- * warranty. In no event will the authors be held liable for any damages
- * arising from the use of this software.
- *
- * Permission is granted to anyone to use this software for any purpose,
- * including commercial applications, and to alter it and redistribute it
- * freely, subject to the following restrictions:
- *
- * 1. The origin of this software must not be misrepresented; you must not
- * claim that you wrote the original software. If you use this software
- * in a product, an acknowledgment in the product documentation would be
- * appreciated but is not required.
- * 2. Altered source versions must be plainly marked as such, and must not be
- * misrepresented as being the original software.
- * 3. This notice may not be removed or altered from any source distribution.
- **/
- #include "wrap_Shader.h"
- #include "wrap_Image.h"
- #include "wrap_Canvas.h"
- #include <string>
- #include <iostream>
- namespace love
- {
- namespace graphics
- {
- namespace opengl
- {
- Shader *luax_checkshader(lua_State *L, int idx)
- {
- return luax_checktype<Shader>(L, idx, "Shader", GRAPHICS_SHADER_T);
- }
- int w_Shader_getWarnings(lua_State *L)
- {
- Shader *shader = luax_checkshader(L, 1);
- lua_pushstring(L, shader->getWarnings().c_str());
- return 1;
- }
- template <typename T>
- static T *_getScalars(lua_State *L, int count, size_t &dimension)
- {
- dimension = 1;
- T *values = new T[count];
- for (int i = 0; i < count; ++i)
- {
- if (lua_isnumber(L, 3 + i))
- values[i] = static_cast<T>(lua_tonumber(L, 3 + i));
- else if (lua_isboolean(L, 3 + i))
- values[i] = static_cast<T>(lua_toboolean(L, 3 + i));
- else
- {
- delete[] values;
- luax_typerror(L, 3 + i, "number or boolean");
- return 0;
- }
- }
- return values;
- }
- template <typename T>
- static T *_getVectors(lua_State *L, int count, size_t &dimension)
- {
- dimension = lua_objlen(L, 3);
- T *values = new T[count * dimension];
- for (int i = 0; i < count; ++i)
- {
- if (!lua_istable(L, 3 + i))
- {
- delete[] values;
- luax_typerror(L, 3 + i, "table");
- return 0;
- }
- if (lua_objlen(L, 3 + i) != dimension)
- {
- delete[] values;
- luaL_error(L, "Error in argument %d: Expected table size %d, got %d.",
- 3+i, dimension, lua_objlen(L, 3+i));
- return 0;
- }
- for (size_t k = 1; k <= dimension; ++k)
- {
- lua_rawgeti(L, 3 + i, k);
- if (lua_isnumber(L, -1))
- values[i * dimension + k - 1] = static_cast<T>(lua_tonumber(L, -1));
- else if (lua_isboolean(L, -1))
- values[i * dimension + k - 1] = static_cast<T>(lua_toboolean(L, -1));
- else
- {
- delete[] values;
- luax_typerror(L, -1, "number or boolean");
- return 0;
- }
- }
- lua_pop(L, int(dimension));
- }
- return values;
- }
- int w_Shader_sendInt(lua_State *L)
- {
- Shader *shader = luax_checkshader(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.");
- int *values = 0;
- size_t dimension = 1;
- if (lua_isnumber(L, 3) || lua_isboolean(L, 3))
- values = _getScalars<int>(L, count, dimension);
- else if (lua_istable(L, 3))
- values = _getVectors<int>(L, count, dimension);
- else
- return luax_typerror(L, 3, "number, boolean, or table");
- if (!values)
- return luaL_error(L, "Error in arguments.");
- bool should_error = false;
- try
- {
- shader->sendInt(name, dimension, values, count);
- }
- catch (love::Exception &e)
- {
- should_error = true;
- lua_pushstring(L, e.what());
- }
- delete[] values;
- if (should_error)
- return lua_error(L);
- return 0;
- }
- int w_Shader_sendFloat(lua_State *L)
- {
- Shader *shader = luax_checkshader(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.");
- float *values = 0;
- size_t dimension = 1;
- if (lua_isnumber(L, 3) || lua_isboolean(L, 3))
- values = _getScalars<float>(L, count, dimension);
- else if (lua_istable(L, 3))
- values = _getVectors<float>(L, count, dimension);
- else
- return luax_typerror(L, 3, "number, boolean, or table");
- if (!values)
- return luaL_error(L, "Error in arguments.");
- bool should_error = false;
- try
- {
- shader->sendFloat(name, dimension, values, count);
- }
- catch (love::Exception &e)
- {
- should_error = true;
- lua_pushstring(L, e.what());
- }
- delete[] values;
- if (should_error)
- return lua_error(L);
- return 0;
- }
- int w_Shader_sendMatrix(lua_State *L)
- {
- int count = lua_gettop(L) - 2;
- Shader *shader = luax_checkshader(L, 1);
- const char *name = luaL_checkstring(L, 2);
- if (!lua_istable(L, 3))
- return luax_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).",
- dimension, dimension);
- 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);
- }
- lua_pop(L, 1 + dimension);
- }
- bool should_error = false;
- try
- {
- shader->sendMatrix(name, dimension, values, count);
- }
- catch(love::Exception &e)
- {
- should_error = true;
- lua_pushstring(L, e.what());
- }
- delete[] values;
- if (should_error)
- return lua_error(L);
- return 0;
- }
- int w_Shader_sendImage(lua_State *L)
- {
- Shader *shader = luax_checkshader(L, 1);
- const char *name = luaL_checkstring(L, 2);
- Image *img = luax_checkimage(L, 3);
- EXCEPT_GUARD(shader->sendImage(name, *img);)
- return 0;
- }
- int w_Shader_sendCanvas(lua_State *L)
- {
- Shader *shader = luax_checkshader(L, 1);
- const char *name = luaL_checkstring(L, 2);
- Canvas *canvas = luax_checkcanvas(L, 3);
- EXCEPT_GUARD(shader->sendCanvas(name, *canvas);)
- return 0;
- }
- // Convert matrices on the stack for use with sendMatrix.
- static void w_convertMatrices(lua_State *L, int idx)
- {
- int matrixcount = lua_gettop(L) - (idx - 1);
- for (int matrix = idx; matrix < idx + matrixcount; matrix++)
- {
- luaL_checktype(L, matrix, LUA_TTABLE);
- int dimension = lua_objlen(L, matrix);
- int newi = 1;
- lua_createtable(L, dimension * dimension, 0);
- // Collapse {{a,b,c}, {d,e,f}, ...} to {a,b,c, d,e,f, ...}
- for (size_t i = 1; i <= lua_objlen(L, matrix); i++)
- {
- // Push args[matrix][i] onto the stack.
- lua_rawgeti(L, matrix, i);
- luaL_checktype(L, -1, LUA_TTABLE);
- for (size_t j = 1; j <= lua_objlen(L, -1); j++)
- {
- // Push args[matrix[i][j] onto the stack.
- lua_rawgeti(L, -1, j);
- luaL_checktype(L, -1, LUA_TNUMBER);
- // newtable[newi] = args[matrix][i][j]
- lua_rawseti(L, -3, newi++);
- }
- lua_pop(L, 1);
- }
- // newtable.dimension = #args[matrix]
- lua_pushinteger(L, dimension);
- lua_setfield(L, -2, "dimension");
- // Replace args[i] with the new table
- lua_replace(L, matrix);
- }
- }
- int w_Shader_send(lua_State *L)
- {
- int ttype = lua_type(L, 3);
- Proxy *p = 0;
- switch (ttype)
- {
- case LUA_TNUMBER:
- case LUA_TBOOLEAN:
- // Scalar float/boolean.
- return w_Shader_sendFloat(L);
- break;
- case LUA_TUSERDATA:
- // Image or Canvas.
- p = (Proxy *) lua_touserdata(L, 3);
- if (p->flags[GRAPHICS_IMAGE_ID])
- return w_Shader_sendImage(L);
- else if (p->flags[GRAPHICS_CANVAS_ID])
- return w_Shader_sendCanvas(L);
- break;
- case LUA_TTABLE:
- // Vector or Matrix.
- lua_rawgeti(L, 3, 1);
- ttype = lua_type(L, -1);
- lua_pop(L, 1);
- if (ttype == LUA_TNUMBER || ttype == LUA_TBOOLEAN)
- return w_Shader_sendFloat(L);
- else if (ttype == LUA_TTABLE)
- {
- w_convertMatrices(L, 3);
- return w_Shader_sendMatrix(L);
- }
- break;
- default:
- break;
- }
- return luaL_argerror(L, 3, "number, boolean, table, image, or canvas expected");
- }
- static const luaL_Reg functions[] =
- {
- { "getWarnings", w_Shader_getWarnings },
- { "sendInt", w_Shader_sendInt },
- { "sendBoolean", w_Shader_sendInt },
- { "sendFloat", w_Shader_sendFloat },
- { "sendMatrix", w_Shader_sendMatrix },
- { "sendImage", w_Shader_sendImage },
- { "sendCanvas", w_Shader_sendCanvas },
- { "send", w_Shader_send },
- { 0, 0 }
- };
- extern "C" int luaopen_shader(lua_State *L)
- {
- return luax_register_type(L, "Shader", functions);
- }
- } // opengl
- } // graphics
- } // love
|