wrap_Math.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501
  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_Math.h"
  21. #include "wrap_RandomGenerator.h"
  22. #include "wrap_BezierCurve.h"
  23. #include "wrap_Transform.h"
  24. #include "MathModule.h"
  25. #include "BezierCurve.h"
  26. #include "Transform.h"
  27. #include "data/wrap_DataModule.h"
  28. #include "data/wrap_CompressedData.h"
  29. #include "data/DataModule.h"
  30. #include <cmath>
  31. #include <iostream>
  32. #include <algorithm>
  33. // Put the Lua code directly into a raw string literal.
  34. static const char math_lua[] =
  35. #include "wrap_Math.lua"
  36. ;
  37. namespace love
  38. {
  39. namespace math
  40. {
  41. int w__getRandomGenerator(lua_State *L)
  42. {
  43. RandomGenerator *t = Math::instance.getRandomGenerator();
  44. luax_pushtype(L, t);
  45. return 1;
  46. }
  47. int w_newRandomGenerator(lua_State *L)
  48. {
  49. RandomGenerator::Seed s;
  50. if (lua_gettop(L) > 0)
  51. s = luax_checkrandomseed(L, 1);
  52. RandomGenerator *t = Math::instance.newRandomGenerator();
  53. if (lua_gettop(L) > 0)
  54. {
  55. bool should_error = false;
  56. try
  57. {
  58. t->setSeed(s);
  59. }
  60. catch (love::Exception &e)
  61. {
  62. t->release();
  63. should_error = true;
  64. lua_pushstring(L, e.what());
  65. }
  66. if (should_error)
  67. return luaL_error(L, "%s", lua_tostring(L, -1));
  68. }
  69. luax_pushtype(L, t);
  70. t->release();
  71. return 1;
  72. }
  73. int w_newBezierCurve(lua_State *L)
  74. {
  75. std::vector<Vector2> points;
  76. if (lua_istable(L, 1))
  77. {
  78. int top = (int) luax_objlen(L, 1);
  79. points.reserve(top / 2);
  80. for (int i = 1; i <= top; i += 2)
  81. {
  82. lua_rawgeti(L, 1, i);
  83. lua_rawgeti(L, 1, i+1);
  84. Vector2 v;
  85. v.x = (float) luaL_checknumber(L, -2);
  86. v.y = (float) luaL_checknumber(L, -1);
  87. points.push_back(v);
  88. lua_pop(L, 2);
  89. }
  90. }
  91. else
  92. {
  93. int top = (int) lua_gettop(L);
  94. points.reserve(top / 2);
  95. for (int i = 1; i <= top; i += 2)
  96. {
  97. Vector2 v;
  98. v.x = (float) luaL_checknumber(L, i);
  99. v.y = (float) luaL_checknumber(L, i+1);
  100. points.push_back(v);
  101. }
  102. }
  103. BezierCurve *curve = Math::instance.newBezierCurve(points);
  104. luax_pushtype(L, curve);
  105. curve->release();
  106. return 1;
  107. }
  108. int w_newTransform(lua_State *L)
  109. {
  110. Transform *t = nullptr;
  111. if (lua_isnoneornil(L, 1))
  112. t = Math::instance.newTransform();
  113. else
  114. {
  115. float x = (float) luaL_checknumber(L, 1);
  116. float y = (float) luaL_checknumber(L, 2);
  117. float a = (float) luaL_optnumber(L, 3, 0.0);
  118. float sx = (float) luaL_optnumber(L, 4, 1.0);
  119. float sy = (float) luaL_optnumber(L, 5, sx);
  120. float ox = (float) luaL_optnumber(L, 6, 0.0);
  121. float oy = (float) luaL_optnumber(L, 7, 0.0);
  122. float kx = (float) luaL_optnumber(L, 8, 0.0);
  123. float ky = (float) luaL_optnumber(L, 9, 0.0);
  124. t = Math::instance.newTransform(x, y, a, sx, sy, ox, oy, kx, ky);
  125. }
  126. luax_pushtype(L, t);
  127. t->release();
  128. return 1;
  129. }
  130. int w_triangulate(lua_State *L)
  131. {
  132. std::vector<love::Vector2> vertices;
  133. if (lua_istable(L, 1))
  134. {
  135. int top = (int) luax_objlen(L, 1);
  136. vertices.reserve(top / 2);
  137. for (int i = 1; i <= top; i += 2)
  138. {
  139. lua_rawgeti(L, 1, i);
  140. lua_rawgeti(L, 1, i+1);
  141. Vector2 v;
  142. v.x = (float) luaL_checknumber(L, -2);
  143. v.y = (float) luaL_checknumber(L, -1);
  144. vertices.push_back(v);
  145. lua_pop(L, 2);
  146. }
  147. }
  148. else
  149. {
  150. int top = (int) lua_gettop(L);
  151. vertices.reserve(top / 2);
  152. for (int i = 1; i <= top; i += 2)
  153. {
  154. Vector2 v;
  155. v.x = (float) luaL_checknumber(L, i);
  156. v.y = (float) luaL_checknumber(L, i+1);
  157. vertices.push_back(v);
  158. }
  159. }
  160. if (vertices.size() < 3)
  161. return luaL_error(L, "Need at least 3 vertices to triangulate");
  162. std::vector<Triangle> triangles;
  163. luax_catchexcept(L, [&]() {
  164. if (vertices.size() == 3)
  165. triangles.push_back(Triangle(vertices[0], vertices[1], vertices[2]));
  166. else
  167. triangles = triangulate(vertices);
  168. });
  169. lua_createtable(L, (int) triangles.size(), 0);
  170. for (int i = 0; i < (int) triangles.size(); ++i)
  171. {
  172. const Triangle &tri = triangles[i];
  173. lua_createtable(L, 6, 0);
  174. lua_pushnumber(L, tri.a.x);
  175. lua_rawseti(L, -2, 1);
  176. lua_pushnumber(L, tri.a.y);
  177. lua_rawseti(L, -2, 2);
  178. lua_pushnumber(L, tri.b.x);
  179. lua_rawseti(L, -2, 3);
  180. lua_pushnumber(L, tri.b.y);
  181. lua_rawseti(L, -2, 4);
  182. lua_pushnumber(L, tri.c.x);
  183. lua_rawseti(L, -2, 5);
  184. lua_pushnumber(L, tri.c.y);
  185. lua_rawseti(L, -2, 6);
  186. lua_rawseti(L, -2, i+1);
  187. }
  188. return 1;
  189. }
  190. int w_isConvex(lua_State *L)
  191. {
  192. std::vector<love::Vector2> vertices;
  193. if (lua_istable(L, 1))
  194. {
  195. int top = (int) luax_objlen(L, 1);
  196. vertices.reserve(top / 2);
  197. for (int i = 1; i <= top; i += 2)
  198. {
  199. lua_rawgeti(L, 1, i);
  200. lua_rawgeti(L, 1, i+1);
  201. love::Vector2 v;
  202. v.x = (float) luaL_checknumber(L, -2);
  203. v.y = (float) luaL_checknumber(L, -1);
  204. vertices.push_back(v);
  205. lua_pop(L, 2);
  206. }
  207. }
  208. else
  209. {
  210. int top = lua_gettop(L);
  211. vertices.reserve(top / 2);
  212. for (int i = 1; i <= top; i += 2)
  213. {
  214. love::Vector2 v;
  215. v.x = (float) luaL_checknumber(L, i);
  216. v.y = (float) luaL_checknumber(L, i+1);
  217. vertices.push_back(v);
  218. }
  219. }
  220. luax_pushboolean(L, isConvex(vertices));
  221. return 1;
  222. }
  223. static int getGammaArgs(lua_State *L, float color[4])
  224. {
  225. int numcomponents = 0;
  226. if (lua_istable(L, 1))
  227. {
  228. int n = (int) luax_objlen(L, 1);
  229. for (int i = 1; i <= n && i <= 4; i++)
  230. {
  231. lua_rawgeti(L, 1, i);
  232. color[i - 1] = (float) luax_checknumberclamped01(L, -1);
  233. numcomponents++;
  234. }
  235. lua_pop(L, numcomponents);
  236. }
  237. else
  238. {
  239. int n = lua_gettop(L);
  240. for (int i = 1; i <= n && i <= 4; i++)
  241. {
  242. color[i - 1] = (float) luax_checknumberclamped01(L, i);
  243. numcomponents++;
  244. }
  245. }
  246. if (numcomponents == 0)
  247. luaL_checknumber(L, 1);
  248. return numcomponents;
  249. }
  250. int w_gammaToLinear(lua_State *L)
  251. {
  252. float color[4];
  253. int numcomponents = getGammaArgs(L, color);
  254. for (int i = 0; i < numcomponents; i++)
  255. {
  256. // Alpha should always be linear.
  257. if (i < 3)
  258. color[i] = gammaToLinear(color[i]);
  259. lua_pushnumber(L, color[i]);
  260. }
  261. return numcomponents;
  262. }
  263. int w_linearToGamma(lua_State *L)
  264. {
  265. float color[4];
  266. int numcomponents = getGammaArgs(L, color);
  267. for (int i = 0; i < numcomponents; i++)
  268. {
  269. // Alpha should always be linear.
  270. if (i < 3)
  271. color[i] = linearToGamma(color[i]);
  272. lua_pushnumber(L, color[i]);
  273. }
  274. return numcomponents;
  275. }
  276. int w_noise(lua_State *L)
  277. {
  278. int nargs = std::min(std::max(lua_gettop(L), 1), 4);
  279. float args[4];
  280. for (int i = 0; i < nargs; i++)
  281. args[i] = (float) luaL_checknumber(L, i + 1);
  282. float val = 0.0f;
  283. switch (nargs)
  284. {
  285. case 1:
  286. val = noise1(args[0]);
  287. break;
  288. case 2:
  289. val = noise2(args[0], args[1]);
  290. break;
  291. case 3:
  292. val = noise3(args[0], args[1], args[2]);
  293. break;
  294. case 4:
  295. val = noise4(args[0], args[1], args[2], args[3]);
  296. break;
  297. }
  298. lua_pushnumber(L, (lua_Number) val);
  299. return 1;
  300. }
  301. int w_compress(lua_State *L)
  302. {
  303. using namespace love::data;
  304. luax_markdeprecated(L, "love.math.compress", API_FUNCTION, DEPRECATED_REPLACED, "love.data.compress");
  305. const char *fstr = lua_isnoneornil(L, 2) ? nullptr : luaL_checkstring(L, 2);
  306. Compressor::Format format = Compressor::FORMAT_LZ4;
  307. if (fstr && !Compressor::getConstant(fstr, format))
  308. return luax_enumerror(L, "compressed data format", Compressor::getConstants(format), fstr);
  309. int level = (int) luaL_optinteger(L, 3, -1);
  310. CompressedData *cdata = nullptr;
  311. if (lua_isstring(L, 1))
  312. {
  313. size_t rawsize = 0;
  314. const char *rawbytes = luaL_checklstring(L, 1, &rawsize);
  315. luax_catchexcept(L, [&](){ cdata = compress(format, rawbytes, rawsize, level); });
  316. }
  317. else
  318. {
  319. Data *rawdata = luax_checktype<Data>(L, 1);
  320. luax_catchexcept(L, [&](){ cdata = compress(format, rawdata, level); });
  321. }
  322. luax_pushtype(L, cdata);
  323. cdata->release();
  324. return 1;
  325. }
  326. int w_decompress(lua_State *L)
  327. {
  328. using namespace love::data;
  329. luax_markdeprecated(L, "love.math.decompress", API_FUNCTION, DEPRECATED_REPLACED, "love.data.decompress");
  330. char *rawbytes = nullptr;
  331. size_t rawsize = 0;
  332. if (luax_istype(L, 1, CompressedData::type))
  333. {
  334. CompressedData *data = luax_checkcompresseddata(L, 1);
  335. rawsize = data->getDecompressedSize();
  336. luax_catchexcept(L, [&](){ rawbytes = decompress(data, rawsize); });
  337. }
  338. else
  339. {
  340. Compressor::Format format = Compressor::FORMAT_LZ4;
  341. const char *fstr = luaL_checkstring(L, 2);
  342. if (!Compressor::getConstant(fstr, format))
  343. return luax_enumerror(L, "compressed data format", Compressor::getConstants(format), fstr);
  344. size_t compressedsize = 0;
  345. const char *cbytes = nullptr;
  346. if (luax_istype(L, 1, Data::type))
  347. {
  348. Data *data = luax_checktype<Data>(L, 1);
  349. cbytes = (const char *) data->getData();
  350. compressedsize = data->getSize();
  351. }
  352. else
  353. cbytes = luaL_checklstring(L, 1, &compressedsize);
  354. luax_catchexcept(L, [&](){ rawbytes = decompress(format, cbytes, compressedsize, rawsize); });
  355. }
  356. lua_pushlstring(L, rawbytes, rawsize);
  357. delete[] rawbytes;
  358. return 1;
  359. }
  360. // C functions in a struct, necessary for the FFI versions of math functions.
  361. struct FFI_Math
  362. {
  363. float (*noise1)(float x);
  364. float (*noise2)(float x, float y);
  365. float (*noise3)(float x, float y, float z);
  366. float (*noise4)(float x, float y, float z, float w);
  367. float (*gammaToLinear)(float c);
  368. float (*linearToGamma)(float c);
  369. };
  370. static FFI_Math ffifuncs =
  371. {
  372. noise1,
  373. noise2,
  374. noise3,
  375. noise4,
  376. gammaToLinear,
  377. linearToGamma,
  378. };
  379. // List of functions to wrap.
  380. static const luaL_Reg functions[] =
  381. {
  382. // love.math.random etc. are defined in wrap_Math.lua.
  383. { "_getRandomGenerator", w__getRandomGenerator },
  384. { "newRandomGenerator", w_newRandomGenerator },
  385. { "newBezierCurve", w_newBezierCurve },
  386. { "newTransform", w_newTransform },
  387. { "triangulate", w_triangulate },
  388. { "isConvex", w_isConvex },
  389. { "gammaToLinear", w_gammaToLinear },
  390. { "linearToGamma", w_linearToGamma },
  391. { "noise", w_noise },
  392. // Deprecated.
  393. { "compress", w_compress },
  394. { "decompress", w_decompress },
  395. { 0, 0 }
  396. };
  397. static const lua_CFunction types[] =
  398. {
  399. luaopen_randomgenerator,
  400. luaopen_beziercurve,
  401. luaopen_transform,
  402. 0
  403. };
  404. extern "C" int luaopen_love_math(lua_State *L)
  405. {
  406. Math::instance.retain();
  407. WrappedModule w;
  408. w.module = &Math::instance;
  409. w.name = "math";
  410. w.type = &Module::type;
  411. w.functions = functions;
  412. w.types = types;
  413. int n = luax_register_module(L, w);
  414. // Execute wrap_Math.lua, sending the math table and ffifuncs pointer as args.
  415. luaL_loadbuffer(L, math_lua, sizeof(math_lua), "wrap_Math.lua");
  416. lua_pushvalue(L, -2);
  417. lua_pushlightuserdata(L, &ffifuncs);
  418. lua_call(L, 2, 0);
  419. return n;
  420. }
  421. } // math
  422. } // love