wrap_Math.cpp 10 KB

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