2
0

wrap_ImageData.cpp 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. /**
  2. * Copyright (c) 2006-2016 LOVE Development Team
  3. *
  4. * This software is provided 'as-is', without any express or implied
  5. * warranty. In no event will the authors be held liable for any damages
  6. * arising from the use of this software.
  7. *
  8. * Permission is granted to anyone to use this software for any purpose,
  9. * including commercial applications, and to alter it and redistribute it
  10. * freely, subject to the following restrictions:
  11. *
  12. * 1. The origin of this software must not be misrepresented; you must not
  13. * claim that you wrote the original software. If you use this software
  14. * in a product, an acknowledgment in the product documentation would be
  15. * appreciated but is not required.
  16. * 2. Altered source versions must be plainly marked as such, and must not be
  17. * misrepresented as being the original software.
  18. * 3. This notice may not be removed or altered from any source distribution.
  19. **/
  20. #include "wrap_ImageData.h"
  21. #include "common/wrap_Data.h"
  22. #include "filesystem/File.h"
  23. // Shove the wrap_ImageData.lua code directly into a raw string literal.
  24. static const char imagedata_lua[] =
  25. #include "wrap_ImageData.lua"
  26. ;
  27. namespace love
  28. {
  29. namespace image
  30. {
  31. /**
  32. * NOTE: Additional wrapper code is in wrap_ImageData.lua. Be sure to keep it
  33. * in sync with any changes made to this file!
  34. **/
  35. ImageData *luax_checkimagedata(lua_State *L, int idx)
  36. {
  37. return luax_checktype<ImageData>(L, idx, IMAGE_IMAGE_DATA_ID);
  38. }
  39. int w_ImageData_getWidth(lua_State *L)
  40. {
  41. ImageData *t = luax_checkimagedata(L, 1);
  42. lua_pushinteger(L, t->getWidth());
  43. return 1;
  44. }
  45. int w_ImageData_getHeight(lua_State *L)
  46. {
  47. ImageData *t = luax_checkimagedata(L, 1);
  48. lua_pushinteger(L, t->getHeight());
  49. return 1;
  50. }
  51. int w_ImageData_getDimensions(lua_State *L)
  52. {
  53. ImageData *t = luax_checkimagedata(L, 1);
  54. lua_pushinteger(L, t->getWidth());
  55. lua_pushinteger(L, t->getHeight());
  56. return 2;
  57. }
  58. int w_ImageData_getPixel(lua_State *L)
  59. {
  60. ImageData *t = luax_checkimagedata(L, 1);
  61. int x = (int) luaL_checknumber(L, 2);
  62. int y = (int) luaL_checknumber(L, 3);
  63. pixel c;
  64. luax_catchexcept(L, [&](){ c = t->getPixel(x, y); });
  65. lua_pushnumber(L, (lua_Number) c.r / 255.0);
  66. lua_pushnumber(L, (lua_Number) c.g / 255.0);
  67. lua_pushnumber(L, (lua_Number) c.b / 255.0);
  68. lua_pushnumber(L, (lua_Number) c.a / 255.0);
  69. return 4;
  70. }
  71. int w_ImageData_setPixel(lua_State *L)
  72. {
  73. ImageData *t = luax_checkimagedata(L, 1);
  74. int x = (int) luaL_checknumber(L, 2);
  75. int y = (int) luaL_checknumber(L, 3);
  76. pixel c;
  77. if (lua_istable(L, 4))
  78. {
  79. for (int i = 1; i <= 4; i++)
  80. lua_rawgeti(L, 4, i);
  81. c.r = (unsigned char) (luaL_checknumber(L, -4) * 255.0);
  82. c.g = (unsigned char) (luaL_checknumber(L, -3) * 255.0);
  83. c.b = (unsigned char) (luaL_checknumber(L, -2) * 255.0);
  84. c.a = (unsigned char) (luaL_optnumber(L, -1, 1.0) * 255.0);
  85. lua_pop(L, 4);
  86. }
  87. else
  88. {
  89. c.r = (unsigned char) (luaL_checknumber(L, 4) * 255.0);
  90. c.g = (unsigned char) (luaL_checknumber(L, 5) * 255.0);
  91. c.b = (unsigned char) (luaL_checknumber(L, 6) * 255.0);
  92. c.a = (unsigned char) (luaL_optnumber(L, 7, 1.0) * 255.0);
  93. }
  94. luax_catchexcept(L, [&](){ t->setPixel(x, y, c); });
  95. return 0;
  96. }
  97. // Gets the result of luaL_where as a string.
  98. static std::string luax_getwhere(lua_State *L, int level)
  99. {
  100. luaL_where(L, level);
  101. const char *str = lua_tostring(L, -1);
  102. std::string where;
  103. if (str)
  104. where = str;
  105. lua_pop(L, 1);
  106. return where;
  107. }
  108. // Generates a Lua error with a nice error string when a return value of a
  109. // called function is not a number.
  110. static int luax_retnumbererror(lua_State *L, int level, int retnum, int ttype)
  111. {
  112. if (ttype == LUA_TNUMBER)
  113. return 0;
  114. const char *where = luax_getwhere(L, level).c_str();
  115. const char *ttypename = lua_typename(L, ttype);
  116. return luaL_error(L, "%sbad return value #%d (number expected, got %s)",
  117. where, retnum, ttypename);
  118. }
  119. // ImageData:mapPixel. Not thread-safe! See wrap_ImageData.lua for the thread-
  120. // safe wrapper function.
  121. int w_ImageData__mapPixelUnsafe(lua_State *L)
  122. {
  123. ImageData *t = luax_checkimagedata(L, 1);
  124. luaL_checktype(L, 2, LUA_TFUNCTION);
  125. // No optints because we assume they're done in the wrapper function.
  126. int sx = (int) lua_tonumber(L, 3);
  127. int sy = (int) lua_tonumber(L, 4);
  128. int w = (int) lua_tonumber(L, 5);
  129. int h = (int) lua_tonumber(L, 6);
  130. if (!(t->inside(sx, sy) && t->inside(sx+w-1, sy+h-1)))
  131. return luaL_error(L, "Invalid rectangle dimensions.");
  132. // Cache-friendlier loop. :)
  133. for (int y = sy; y < sy+h; y++)
  134. {
  135. for (int x = sx; x < sx+w; x++)
  136. {
  137. lua_pushvalue(L, 2);
  138. lua_pushnumber(L, x);
  139. lua_pushnumber(L, y);
  140. pixel c = t->getPixelUnsafe(x, y);
  141. lua_pushnumber(L, c.r / 255.0);
  142. lua_pushnumber(L, c.g / 255.0);
  143. lua_pushnumber(L, c.b / 255.0);
  144. lua_pushnumber(L, c.a / 255.0);
  145. lua_call(L, 6, 4);
  146. // If we used luaL_checkX / luaL_optX then we would get messy error
  147. // messages (e.g. Error: bad argument #-1 to '?'), so while this is
  148. // messier code, at least the errors are a bit more descriptive.
  149. // Treat the pixel as an array for less code duplication. :(
  150. unsigned char *parray = (unsigned char *) &c;
  151. for (int i = 0; i < 4; i++)
  152. {
  153. int ttype = lua_type(L, -4 + i);
  154. if (ttype == LUA_TNUMBER)
  155. parray[i] = (unsigned char) (lua_tonumber(L, -4 + i) * 255.0);
  156. else if (i == 3 && (ttype == LUA_TNONE || ttype == LUA_TNIL))
  157. parray[i] = 255; // Alpha component defaults to 255.
  158. else
  159. // Error (level 2 because this is function will be wrapped.)
  160. return luax_retnumbererror(L, 2, i + 1, ttype);
  161. }
  162. // Pop return values.
  163. lua_pop(L, 4);
  164. // We're locking the entire function, instead of each setPixel call.
  165. t->setPixelUnsafe(x, y, c);
  166. }
  167. }
  168. return 0;
  169. }
  170. int w_ImageData_paste(lua_State *L)
  171. {
  172. ImageData *t = luax_checkimagedata(L, 1);
  173. ImageData *src = luax_checkimagedata(L, 2);
  174. int dx = (int) luaL_checknumber(L, 3);
  175. int dy = (int) luaL_checknumber(L, 4);
  176. int sx = (int) luaL_optnumber(L, 5, 0);
  177. int sy = (int) luaL_optnumber(L, 6, 0);
  178. int sw = (int) luaL_optnumber(L, 7, src->getWidth());
  179. int sh = (int) luaL_optnumber(L, 8, src->getHeight());
  180. t->paste((love::image::ImageData *)src, dx, dy, sx, sy, sw, sh);
  181. return 0;
  182. }
  183. int w_ImageData_encode(lua_State *L)
  184. {
  185. ImageData *t = luax_checkimagedata(L, 1);
  186. ImageData::EncodedFormat format;
  187. const char *fmt = luaL_checkstring(L, 2);
  188. if (!ImageData::getConstant(fmt, format))
  189. return luaL_error(L, "Invalid encoded image format '%s'.", fmt);
  190. bool hasfilename = false;
  191. std::string filename = "Image." + std::string(fmt);
  192. if (!lua_isnoneornil(L, 3))
  193. {
  194. hasfilename = true;
  195. filename = luax_checkstring(L, 3);
  196. }
  197. love::filesystem::FileData *filedata = nullptr;
  198. luax_catchexcept(L, [&](){ filedata = t->encode(format, filename.c_str()); });
  199. luax_pushtype(L, FILESYSTEM_FILE_DATA_ID, filedata);
  200. filedata->release();
  201. if (hasfilename)
  202. {
  203. luax_getfunction(L, "filesystem", "write");
  204. lua_pushvalue(L, 3); // filename
  205. lua_pushvalue(L, -3); // FileData
  206. lua_call(L, 2, 0);
  207. }
  208. return 1;
  209. }
  210. int w_ImageData__performAtomic(lua_State *L)
  211. {
  212. ImageData *t = luax_checkimagedata(L, 1);
  213. int err = 0;
  214. {
  215. love::thread::Lock lock(t->getMutex());
  216. // call the function, passing any user-specified arguments.
  217. err = lua_pcall(L, lua_gettop(L) - 2, LUA_MULTRET, 0);
  218. }
  219. // Unfortunately, this eats the stack trace, too bad.
  220. if (err != 0)
  221. return lua_error(L);
  222. // The function and everything after it in the stack are eaten by the pcall,
  223. // leaving only the ImageData object. Everything else is a return value.
  224. return lua_gettop(L) - 1;
  225. }
  226. // C functions in a struct, necessary for the FFI versions of ImageData methods.
  227. struct FFI_ImageData
  228. {
  229. void (*lockMutex)(Proxy *p);
  230. void (*unlockMutex)(Proxy *p);
  231. };
  232. static FFI_ImageData ffifuncs =
  233. {
  234. [](Proxy *p) // lockMutex
  235. {
  236. // We don't do any type-checking for the Proxy here since these functions
  237. // are always called from code which has already done type checking.
  238. ImageData *i = (ImageData *) p->object;
  239. i->getMutex()->lock();
  240. },
  241. [](Proxy *p) // unlockMutex
  242. {
  243. ImageData *i = (ImageData *) p->object;
  244. i->getMutex()->unlock();
  245. }
  246. };
  247. static const luaL_Reg w_ImageData_functions[] =
  248. {
  249. { "getWidth", w_ImageData_getWidth },
  250. { "getHeight", w_ImageData_getHeight },
  251. { "getDimensions", w_ImageData_getDimensions },
  252. { "getPixel", w_ImageData_getPixel },
  253. { "setPixel", w_ImageData_setPixel },
  254. { "paste", w_ImageData_paste },
  255. { "encode", w_ImageData_encode },
  256. // Used in the Lua wrapper code.
  257. { "_mapPixelUnsafe", w_ImageData__mapPixelUnsafe },
  258. { "_performAtomic", w_ImageData__performAtomic },
  259. { 0, 0 }
  260. };
  261. extern "C" int luaopen_imagedata(lua_State *L)
  262. {
  263. int ret = luax_register_type(L, IMAGE_IMAGE_DATA_ID, "ImageData", w_Data_functions, w_ImageData_functions, nullptr);
  264. luax_gettypemetatable(L, IMAGE_IMAGE_DATA_ID);
  265. // Load and execute ImageData.lua, sending the metatable and the ffi
  266. // functions struct pointer as arguments.
  267. if (lua_istable(L, -1))
  268. {
  269. luaL_loadbuffer(L, imagedata_lua, sizeof(imagedata_lua), "ImageData.lua");
  270. lua_pushvalue(L, -2);
  271. lua_pushlightuserdata(L, &ffifuncs);
  272. lua_call(L, 2, 0);
  273. }
  274. // Pop the metatable.
  275. lua_pop(L, 1);
  276. return ret;
  277. }
  278. } // image
  279. } // love