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