wrap_ImageData.cpp 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. /**
  2. * Copyright (c) 2006-2017 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 "data/wrap_Data.h"
  22. #include "filesystem/File.h"
  23. #include "filesystem/Filesystem.h"
  24. // Shove the wrap_ImageData.lua code directly into a raw string literal.
  25. static const char imagedata_lua[] =
  26. #include "wrap_ImageData.lua"
  27. ;
  28. namespace love
  29. {
  30. namespace image
  31. {
  32. /**
  33. * NOTE: Additional wrapper code is in wrap_ImageData.lua. Be sure to keep it
  34. * in sync with any changes made to this file!
  35. **/
  36. ImageData *luax_checkimagedata(lua_State *L, int idx)
  37. {
  38. return luax_checktype<ImageData>(L, idx);
  39. }
  40. int w_ImageData_clone(lua_State *L)
  41. {
  42. ImageData *t = luax_checkimagedata(L, 1), *c = nullptr;
  43. luax_catchexcept(L, [&](){ c = t->clone(); });
  44. luax_pushtype(L, c);
  45. c->release();
  46. return 1;
  47. }
  48. int w_ImageData_getFormat(lua_State *L)
  49. {
  50. ImageData *t = luax_checkimagedata(L, 1);
  51. PixelFormat format = t->getFormat();
  52. const char *fstr = nullptr;
  53. if (!getConstant(format, fstr))
  54. return luaL_error(L, "Unknown pixel format.");
  55. lua_pushstring(L, fstr);
  56. return 1;
  57. }
  58. int w_ImageData_getWidth(lua_State *L)
  59. {
  60. ImageData *t = luax_checkimagedata(L, 1);
  61. lua_pushinteger(L, t->getWidth());
  62. return 1;
  63. }
  64. int w_ImageData_getHeight(lua_State *L)
  65. {
  66. ImageData *t = luax_checkimagedata(L, 1);
  67. lua_pushinteger(L, t->getHeight());
  68. return 1;
  69. }
  70. int w_ImageData_getDimensions(lua_State *L)
  71. {
  72. ImageData *t = luax_checkimagedata(L, 1);
  73. lua_pushinteger(L, t->getWidth());
  74. lua_pushinteger(L, t->getHeight());
  75. return 2;
  76. }
  77. // TODO: rgba16f
  78. static void luax_checkpixel_rgba8(lua_State *L, int startidx, Pixel &p)
  79. {
  80. for (int i = 0; i < 3; i++)
  81. p.rgba8[i] = (uint8) (luaL_checknumber(L, startidx + i) * 255.0);
  82. p.rgba8[3] = (uint8) (luaL_optnumber(L, startidx + 3, 1.0) * 255.0);
  83. }
  84. static void luax_checkpixel_rgba16(lua_State *L, int startidx, Pixel &p)
  85. {
  86. for (int i = 0; i < 3; i++)
  87. p.rgba16[i] = (uint16) (luaL_checknumber(L, startidx + i) * 65535.0);
  88. p.rgba16[3] = (uint16) (luaL_optnumber(L, startidx + 3, 1.0) * 65535.0);
  89. }
  90. static void luax_checkpixel_rgba16f(lua_State *L, int startidx, Pixel &p)
  91. {
  92. for (int i = 0; i < 3; i++)
  93. p.rgba16f[i] = floatToHalf((float) luaL_checknumber(L, startidx + i));
  94. p.rgba16f[3] = floatToHalf((float) luaL_optnumber(L, startidx + 3, 1.0));
  95. }
  96. static void luax_checkpixel_rgba32f(lua_State *L, int startidx, Pixel &p)
  97. {
  98. for (int i = 0; i < 3; i++)
  99. p.rgba32f[i] = (float) luaL_checknumber(L, startidx + i);
  100. p.rgba32f[3] = (float) luaL_optnumber(L, startidx + 3, 1.0);
  101. }
  102. static int luax_pushpixel_rgba8(lua_State *L, const Pixel &p)
  103. {
  104. for (int i = 0; i < 4; i++)
  105. lua_pushnumber(L, (lua_Number) p.rgba8[i] / 255.0);
  106. return 4;
  107. }
  108. static int luax_pushpixel_rgba16(lua_State *L, const Pixel &p)
  109. {
  110. for (int i = 0; i < 4; i++)
  111. lua_pushnumber(L, (lua_Number) p.rgba16[i] / 65535.0);
  112. return 4;
  113. }
  114. static int luax_pushpixel_rgba16f(lua_State *L, const Pixel &p)
  115. {
  116. for (int i = 0; i < 4; i++)
  117. lua_pushnumber(L, (lua_Number) halfToFloat(p.rgba16f[i]));
  118. return 4;
  119. }
  120. static int luax_pushpixel_rgba32f(lua_State *L, const Pixel &p)
  121. {
  122. for (int i = 0; i < 4; i++)
  123. lua_pushnumber(L, (lua_Number) p.rgba32f[i]);
  124. return 4;
  125. }
  126. typedef void(*checkpixel)(lua_State *L, int startidx, Pixel &p);
  127. typedef int(*pushpixel)(lua_State *L, const Pixel &p);
  128. static checkpixel checkFormats[PIXELFORMAT_MAX_ENUM] = {};
  129. static pushpixel pushFormats[PIXELFORMAT_MAX_ENUM] = {};
  130. int w_ImageData_getPixel(lua_State *L)
  131. {
  132. ImageData *t = luax_checkimagedata(L, 1);
  133. int x = (int) luaL_checkinteger(L, 2);
  134. int y = (int) luaL_checkinteger(L, 3);
  135. PixelFormat format = t->getFormat();
  136. Pixel p;
  137. luax_catchexcept(L, [&](){ t->getPixel(x, y, p); });
  138. return pushFormats[format](L, p);
  139. }
  140. int w_ImageData_setPixel(lua_State *L)
  141. {
  142. ImageData *t = luax_checkimagedata(L, 1);
  143. int x = (int) luaL_checkinteger(L, 2);
  144. int y = (int) luaL_checkinteger(L, 3);
  145. PixelFormat format = t->getFormat();
  146. Pixel p;
  147. if (lua_istable(L, 4))
  148. {
  149. for (int i = 1; i <= 4; i++)
  150. lua_rawgeti(L, 4, i);
  151. checkFormats[format](L, -4, p);
  152. lua_pop(L, 4);
  153. }
  154. else
  155. checkFormats[format](L, 4, p);
  156. luax_catchexcept(L, [&](){ t->setPixel(x, y, p); });
  157. return 0;
  158. }
  159. // ImageData:mapPixel. Not thread-safe! See wrap_ImageData.lua for the thread-
  160. // safe wrapper function.
  161. int w_ImageData__mapPixelUnsafe(lua_State *L)
  162. {
  163. ImageData *t = luax_checkimagedata(L, 1);
  164. luaL_checktype(L, 2, LUA_TFUNCTION);
  165. // No optints because we assume they're done in the wrapper function.
  166. int sx = (int) lua_tonumber(L, 3);
  167. int sy = (int) lua_tonumber(L, 4);
  168. int w = (int) lua_tonumber(L, 5);
  169. int h = (int) lua_tonumber(L, 6);
  170. if (!(t->inside(sx, sy) && t->inside(sx+w-1, sy+h-1)))
  171. return luaL_error(L, "Invalid rectangle dimensions.");
  172. int iw = t->getWidth();
  173. PixelFormat format = t->getFormat();
  174. auto checkpixel = checkFormats[format];
  175. auto pushpixel = pushFormats[format];
  176. uint8 *data = (uint8 *) t->getData();
  177. size_t pixelsize = t->getPixelSize();
  178. for (int y = sy; y < sy+h; y++)
  179. {
  180. for (int x = sx; x < sx+w; x++)
  181. {
  182. Pixel *pixeldata = (Pixel *) (data + (y * iw + x) * pixelsize);
  183. lua_pushvalue(L, 2); // ImageData
  184. lua_pushnumber(L, x);
  185. lua_pushnumber(L, y);
  186. pushpixel(L, *pixeldata);
  187. lua_call(L, 6, 4);
  188. checkpixel(L, -4, *pixeldata);
  189. lua_pop(L, 4); // Pop return values.
  190. }
  191. }
  192. return 0;
  193. }
  194. int w_ImageData_paste(lua_State *L)
  195. {
  196. ImageData *t = luax_checkimagedata(L, 1);
  197. ImageData *src = luax_checkimagedata(L, 2);
  198. int dx = (int) luaL_checkinteger(L, 3);
  199. int dy = (int) luaL_checkinteger(L, 4);
  200. int sx = (int) luaL_optinteger(L, 5, 0);
  201. int sy = (int) luaL_optinteger(L, 6, 0);
  202. int sw = (int) luaL_optinteger(L, 7, src->getWidth());
  203. int sh = (int) luaL_optinteger(L, 8, src->getHeight());
  204. t->paste((love::image::ImageData *)src, dx, dy, sx, sy, sw, sh);
  205. return 0;
  206. }
  207. int w_ImageData_encode(lua_State *L)
  208. {
  209. ImageData *t = luax_checkimagedata(L, 1);
  210. FormatHandler::EncodedFormat format;
  211. const char *fmt = luaL_checkstring(L, 2);
  212. if (!ImageData::getConstant(fmt, format))
  213. return luax_enumerror(L, "encoded image format", ImageData::getConstants(format), fmt);
  214. bool hasfilename = false;
  215. std::string filename = "Image." + std::string(fmt);
  216. if (!lua_isnoneornil(L, 3))
  217. {
  218. hasfilename = true;
  219. filename = luax_checkstring(L, 3);
  220. }
  221. love::filesystem::FileData *filedata = nullptr;
  222. luax_catchexcept(L, [&](){ filedata = t->encode(format, filename.c_str(), hasfilename); });
  223. luax_pushtype(L, filedata);
  224. filedata->release();
  225. return 1;
  226. }
  227. int w_ImageData__performAtomic(lua_State *L)
  228. {
  229. ImageData *t = luax_checkimagedata(L, 1);
  230. int err = 0;
  231. {
  232. love::thread::Lock lock(t->getMutex());
  233. // call the function, passing any user-specified arguments.
  234. err = lua_pcall(L, lua_gettop(L) - 2, LUA_MULTRET, 0);
  235. }
  236. // Unfortunately, this eats the stack trace, too bad.
  237. if (err != 0)
  238. return lua_error(L);
  239. // The function and everything after it in the stack are eaten by the pcall,
  240. // leaving only the ImageData object. Everything else is a return value.
  241. return lua_gettop(L) - 1;
  242. }
  243. // C functions in a struct, necessary for the FFI versions of ImageData methods.
  244. struct FFI_ImageData
  245. {
  246. void (*lockMutex)(Proxy *p);
  247. void (*unlockMutex)(Proxy *p);
  248. float (*halfToFloat)(half h);
  249. half (*floatToHalf)(float f);
  250. };
  251. static FFI_ImageData ffifuncs =
  252. {
  253. [](Proxy *p) // lockMutex
  254. {
  255. // We don't do any type-checking for the Proxy here since these functions
  256. // are always called from code which has already done type checking.
  257. ImageData *i = (ImageData *) p->object;
  258. i->getMutex()->lock();
  259. },
  260. [](Proxy *p) // unlockMutex
  261. {
  262. ImageData *i = (ImageData *) p->object;
  263. i->getMutex()->unlock();
  264. },
  265. halfToFloat,
  266. floatToHalf,
  267. };
  268. static const luaL_Reg w_ImageData_functions[] =
  269. {
  270. { "clone", w_ImageData_clone },
  271. { "getFormat", w_ImageData_getFormat },
  272. { "getWidth", w_ImageData_getWidth },
  273. { "getHeight", w_ImageData_getHeight },
  274. { "getDimensions", w_ImageData_getDimensions },
  275. { "getPixel", w_ImageData_getPixel },
  276. { "setPixel", w_ImageData_setPixel },
  277. { "paste", w_ImageData_paste },
  278. { "encode", w_ImageData_encode },
  279. // Used in the Lua wrapper code.
  280. { "_mapPixelUnsafe", w_ImageData__mapPixelUnsafe },
  281. { "_performAtomic", w_ImageData__performAtomic },
  282. { 0, 0 }
  283. };
  284. extern "C" int luaopen_imagedata(lua_State *L)
  285. {
  286. checkFormats[PIXELFORMAT_RGBA8] = luax_checkpixel_rgba8;
  287. checkFormats[PIXELFORMAT_RGBA16] = luax_checkpixel_rgba16;
  288. checkFormats[PIXELFORMAT_RGBA16F] = luax_checkpixel_rgba16f;
  289. checkFormats[PIXELFORMAT_RGBA32F] = luax_checkpixel_rgba32f;
  290. pushFormats[PIXELFORMAT_RGBA8] = luax_pushpixel_rgba8;
  291. pushFormats[PIXELFORMAT_RGBA16] = luax_pushpixel_rgba16;
  292. pushFormats[PIXELFORMAT_RGBA16F] = luax_pushpixel_rgba16f;
  293. pushFormats[PIXELFORMAT_RGBA32F] = luax_pushpixel_rgba32f;
  294. int ret = luax_register_type(L, &ImageData::type, data::w_Data_functions, w_ImageData_functions, nullptr);
  295. luax_gettypemetatable(L, ImageData::type);
  296. // Load and execute ImageData.lua, sending the metatable and the ffi
  297. // functions struct pointer as arguments.
  298. if (lua_istable(L, -1))
  299. {
  300. luaL_loadbuffer(L, imagedata_lua, sizeof(imagedata_lua), "ImageData.lua");
  301. lua_pushvalue(L, -2);
  302. lua_pushlightuserdata(L, &ffifuncs);
  303. lua_call(L, 2, 0);
  304. }
  305. // Pop the metatable.
  306. lua_pop(L, 1);
  307. return ret;
  308. }
  309. } // image
  310. } // love