1/**
2 * Copyright (c) 2006-2023 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// LOVE
22#include "wrap_Physics.h"
23#include "wrap_World.h"
24#include "wrap_Contact.h"
25#include "wrap_Body.h"
26#include "wrap_Fixture.h"
27#include "wrap_Shape.h"
28#include "wrap_CircleShape.h"
29#include "wrap_PolygonShape.h"
30#include "wrap_EdgeShape.h"
31#include "wrap_ChainShape.h"
32#include "wrap_Joint.h"
33#include "wrap_MouseJoint.h"
34#include "wrap_DistanceJoint.h"
35#include "wrap_PrismaticJoint.h"
36#include "wrap_RevoluteJoint.h"
37#include "wrap_PulleyJoint.h"
38#include "wrap_GearJoint.h"
39#include "wrap_FrictionJoint.h"
40#include "wrap_WeldJoint.h"
41#include "wrap_WheelJoint.h"
42#include "wrap_RopeJoint.h"
43#include "wrap_MotorJoint.h"
44
45namespace love
46{
47namespace physics
48{
49namespace box2d
50{
51
52#define instance() (Module::getInstance<Physics>(Module::M_PHYSICS))
53
54int w_newWorld(lua_State *L)
55{
56 float gx = (float)luaL_optnumber(L, 1, 0);
57 float gy = (float)luaL_optnumber(L, 2, 0);
58 bool sleep = luax_optboolean(L, 3, true);
59
60 World *w;
61 luax_catchexcept(L, [&](){ w = instance()->newWorld(gx, gy, sleep); });
62 luax_pushtype(L, w);
63 w->release();
64
65 return 1;
66}
67
68int w_newBody(lua_State *L)
69{
70 World *world = luax_checkworld(L, 1);
71 float x = (float)luaL_optnumber(L, 2, 0.0);
72 float y = (float)luaL_optnumber(L, 3, 0.0);
73
74 Body::Type btype = Body::BODY_STATIC;
75 const char *typestr = lua_isnoneornil(L, 4) ? 0 : lua_tostring(L, 4);
76 if (typestr && !Body::getConstant(typestr, btype))
77 return luax_enumerror(L, "Body type", Body::getConstants(btype), typestr);
78
79 Body *body;
80 luax_catchexcept(L, [&](){ body = instance()->newBody(world, x, y, btype); });
81 luax_pushtype(L, body);
82 body->release();
83 return 1;
84}
85
86int w_newFixture(lua_State *L)
87{
88 Body *body = luax_checkbody(L, 1);
89 Shape *shape = luax_checkshape(L, 2);
90 float density = (float)luaL_optnumber(L, 3, 1.0f);
91 Fixture *fixture;
92 luax_catchexcept(L, [&](){ fixture = instance()->newFixture(body, shape, density); });
93 luax_pushtype(L, fixture);
94 fixture->release();
95 return 1;
96}
97
98int w_newCircleShape(lua_State *L)
99{
100 int top = lua_gettop(L);
101
102 if (top == 1)
103 {
104 float radius = (float)luaL_checknumber(L, 1);
105 CircleShape *shape;
106 luax_catchexcept(L, [&](){ shape = instance()->newCircleShape(radius); });
107 luax_pushtype(L, shape);
108 shape->release();
109 return 1;
110 }
111 else if (top == 3)
112 {
113 float x = (float)luaL_checknumber(L, 1);
114 float y = (float)luaL_checknumber(L, 2);
115 float radius = (float)luaL_checknumber(L, 3);
116 CircleShape *shape;
117 luax_catchexcept(L, [&](){ shape = instance()->newCircleShape(x, y, radius); });
118 luax_pushtype(L, shape);
119 shape->release();
120 return 1;
121 }
122 else
123 return luaL_error(L, "Incorrect number of parameters");
124}
125
126int w_newRectangleShape(lua_State *L)
127{
128 int top = lua_gettop(L);
129
130 if (top == 2)
131 {
132 float w = (float)luaL_checknumber(L, 1);
133 float h = (float)luaL_checknumber(L, 2);
134 PolygonShape *shape;
135 luax_catchexcept(L, [&](){ shape = instance()->newRectangleShape(w, h); });
136 luax_pushtype(L, shape);
137 shape->release();
138 return 1;
139 }
140 else if (top == 4 || top == 5)
141 {
142 float x = (float)luaL_checknumber(L, 1);
143 float y = (float)luaL_checknumber(L, 2);
144 float w = (float)luaL_checknumber(L, 3);
145 float h = (float)luaL_checknumber(L, 4);
146 float angle = (float)luaL_optnumber(L, 5, 0);
147 PolygonShape *shape;
148 luax_catchexcept(L, [&](){ shape = instance()->newRectangleShape(x, y, w, h, angle); });
149 luax_pushtype(L, shape);
150 shape->release();
151 return 1;
152 }
153 else
154 return luaL_error(L, "Incorrect number of parameters");
155}
156
157int w_newEdgeShape(lua_State *L)
158{
159 float x1 = (float)luaL_checknumber(L, 1);
160 float y1 = (float)luaL_checknumber(L, 2);
161 float x2 = (float)luaL_checknumber(L, 3);
162 float y2 = (float)luaL_checknumber(L, 4);
163 EdgeShape *shape;
164 luax_catchexcept(L, [&](){ shape = instance()->newEdgeShape(x1, y1, x2, y2); });
165 luax_pushtype(L, shape);
166 shape->release();
167 return 1;
168}
169
170int w_newPolygonShape(lua_State *L)
171{
172 int ret = 0;
173 luax_catchexcept(L, [&](){ ret = instance()->newPolygonShape(L); });
174 return ret;
175}
176
177int w_newChainShape(lua_State *L)
178{
179 int ret = 0;
180 luax_catchexcept(L, [&](){ ret = instance()->newChainShape(L); });
181 return ret;
182}
183
184int w_newDistanceJoint(lua_State *L)
185{
186 Body *body1 = luax_checkbody(L, 1);
187 Body *body2 = luax_checkbody(L, 2);
188 float x1 = (float)luaL_checknumber(L, 3);
189 float y1 = (float)luaL_checknumber(L, 4);
190 float x2 = (float)luaL_checknumber(L, 5);
191 float y2 = (float)luaL_checknumber(L, 6);
192 bool collideConnected = luax_optboolean(L, 7, false);
193 DistanceJoint *j;
194 luax_catchexcept(L, [&]() {
195 j = instance()->newDistanceJoint(body1, body2, x1, y1, x2, y2, collideConnected);
196 });
197 luax_pushtype(L, j);
198 j->release();
199 return 1;
200}
201
202int w_newMouseJoint(lua_State *L)
203{
204 Body *body = luax_checkbody(L, 1);
205 float x = (float)luaL_checknumber(L, 2);
206 float y = (float)luaL_checknumber(L, 3);
207 MouseJoint *j;
208 luax_catchexcept(L, [&](){ j = instance()->newMouseJoint(body, x, y); });
209 luax_pushtype(L, j);
210 j->release();
211 return 1;
212}
213
214int w_newRevoluteJoint(lua_State *L)
215{
216 Body *body1 = luax_checkbody(L, 1);
217 Body *body2 = luax_checkbody(L, 2);
218 float xA = (float)luaL_checknumber(L, 3);
219 float yA = (float)luaL_checknumber(L, 4);
220 float xB, yB;
221 bool collideConnected;
222 if (lua_gettop(L) >= 6)
223 {
224 xB = (float)luaL_checknumber(L, 5);
225 yB = (float)luaL_checknumber(L, 6);
226 collideConnected = luax_optboolean(L, 7, false);
227 }
228 else
229 {
230 xB = xA;
231 yB = yA;
232 collideConnected = luax_optboolean(L, 5, false);
233 }
234 RevoluteJoint *j;
235 luax_catchexcept(L, [&]() {
236 if (lua_gettop(L) >= 8)
237 {
238 float referenceAngle = (float)luaL_checknumber(L, 8);
239 j = instance()->newRevoluteJoint(body1, body2, xA, yA, xB, yB, collideConnected, referenceAngle);
240 }
241 else
242 j = instance()->newRevoluteJoint(body1, body2, xA, yA, xB, yB, collideConnected);
243 });
244 luax_pushtype(L, j);
245 j->release();
246 return 1;
247}
248
249int w_newPrismaticJoint(lua_State *L)
250{
251 Body *body1 = luax_checkbody(L, 1);
252 Body *body2 = luax_checkbody(L, 2);
253 float xA = (float)luaL_checknumber(L, 3);
254 float yA = (float)luaL_checknumber(L, 4);
255 float xB, yB, ax, ay;
256 bool collideConnected;
257 if (lua_gettop(L) >= 8)
258 {
259 xB = (float)luaL_checknumber(L, 5);
260 yB = (float)luaL_checknumber(L, 6);
261 ax = (float)luaL_checknumber(L, 7);
262 ay = (float)luaL_checknumber(L, 8);
263 collideConnected = luax_optboolean(L, 9, false);
264 }
265 else
266 {
267 xB = xA;
268 yB = yA;
269 ax = (float)luaL_checknumber(L, 5);
270 ay = (float)luaL_checknumber(L, 6);
271 collideConnected = luax_optboolean(L, 7, false);
272 }
273 PrismaticJoint *j;
274 luax_catchexcept(L, [&]() {
275 if (lua_gettop(L) >= 10)
276 {
277 float referenceAngle = (float)luaL_checknumber(L, 10);
278 j = instance()->newPrismaticJoint(body1, body2, xA, yA, xB, yB, ax, ay, collideConnected, referenceAngle);
279 }
280 else
281 j = instance()->newPrismaticJoint(body1, body2, xA, yA, xB, yB, ax, ay, collideConnected);
282 });
283 luax_pushtype(L, j);
284 j->release();
285 return 1;
286}
287
288int w_newPulleyJoint(lua_State *L)
289{
290 Body *body1 = luax_checkbody(L, 1);
291 Body *body2 = luax_checkbody(L, 2);
292 float gx1 = (float)luaL_checknumber(L, 3);
293 float gy1 = (float)luaL_checknumber(L, 4);
294 float gx2 = (float)luaL_checknumber(L, 5);
295 float gy2 = (float)luaL_checknumber(L, 6);
296 float x1 = (float)luaL_checknumber(L, 7);
297 float y1 = (float)luaL_checknumber(L, 8);
298 float x2 = (float)luaL_checknumber(L, 9);
299 float y2 = (float)luaL_checknumber(L, 10);
300 float ratio = (float)luaL_optnumber(L, 11, 1.0);
301 bool collideConnected = luax_optboolean(L, 12, true); // PulleyJoints default to colliding connected bodies, see b2PulleyJoint.h
302
303 PulleyJoint *j;
304 luax_catchexcept(L, [&]() {
305 j = instance()->newPulleyJoint(body1, body2, b2Vec2(gx1,gy1), b2Vec2(gx2,gy2), b2Vec2(x1,y1), b2Vec2(x2,y2), ratio, collideConnected);
306 });
307 luax_pushtype(L, j);
308 j->release();
309 return 1;
310}
311
312int w_newGearJoint(lua_State *L)
313{
314 Joint *joint1 = luax_checkjoint(L, 1);
315 Joint *joint2 = luax_checkjoint(L, 2);
316 float ratio = (float)luaL_optnumber(L, 3, 1.0);
317 bool collideConnected = luax_optboolean(L, 4, false);
318
319 GearJoint *j;
320 luax_catchexcept(L, [&]() {
321 j = instance()->newGearJoint(joint1, joint2, ratio, collideConnected);
322 });
323 luax_pushtype(L, j);
324 j->release();
325 return 1;
326}
327
328int w_newFrictionJoint(lua_State *L)
329{
330 Body *body1 = luax_checkbody(L, 1);
331 Body *body2 = luax_checkbody(L, 2);
332 float xA = (float)luaL_checknumber(L, 3);
333 float yA = (float)luaL_checknumber(L, 4);
334 float xB, yB;
335 bool collideConnected;
336 if (lua_gettop(L) >= 6)
337 {
338 xB = (float)luaL_checknumber(L, 5);
339 yB = (float)luaL_checknumber(L, 6);
340 collideConnected = luax_optboolean(L, 7, false);
341 }
342 else
343 {
344 xB = xA;
345 yB = yA;
346 collideConnected = luax_optboolean(L, 5, false);
347 }
348 FrictionJoint *j;
349 luax_catchexcept(L, [&]() {
350 j = instance()->newFrictionJoint(body1, body2, xA, yA, xB, yB, collideConnected);
351 });
352 luax_pushtype(L, j);
353 j->release();
354 return 1;
355}
356
357int w_newWeldJoint(lua_State *L)
358{
359 Body *body1 = luax_checkbody(L, 1);
360 Body *body2 = luax_checkbody(L, 2);
361 float xA = (float)luaL_checknumber(L, 3);
362 float yA = (float)luaL_checknumber(L, 4);
363 float xB, yB;
364 bool collideConnected;
365 if (lua_gettop(L) >= 6)
366 {
367 xB = (float)luaL_checknumber(L, 5);
368 yB = (float)luaL_checknumber(L, 6);
369 collideConnected = luax_optboolean(L, 7, false);
370 }
371 else
372 {
373 xB = xA;
374 yB = yA;
375 collideConnected = luax_optboolean(L, 5, false);
376 }
377 WeldJoint *j;
378 luax_catchexcept(L, [&]() {
379 if (lua_gettop(L) >= 8)
380 {
381 float referenceAngle = (float)luaL_checknumber(L, 8);
382 j = instance()->newWeldJoint(body1, body2, xA, yA, xB, yB, collideConnected, referenceAngle);
383 }
384 else
385 j = instance()->newWeldJoint(body1, body2, xA, yA, xB, yB, collideConnected);
386 });
387 luax_pushtype(L, j);
388 j->release();
389 return 1;
390}
391
392int w_newWheelJoint(lua_State *L)
393{
394 Body *body1 = luax_checkbody(L, 1);
395 Body *body2 = luax_checkbody(L, 2);
396 float xA = (float)luaL_checknumber(L, 3);
397 float yA = (float)luaL_checknumber(L, 4);
398 float xB, yB, ax, ay;
399 bool collideConnected;
400 if (lua_gettop(L) >= 8)
401 {
402 xB = (float)luaL_checknumber(L, 5);
403 yB = (float)luaL_checknumber(L, 6);
404 ax = (float)luaL_checknumber(L, 7);
405 ay = (float)luaL_checknumber(L, 8);
406 collideConnected = luax_optboolean(L, 9, false);
407 }
408 else
409 {
410 xB = xA;
411 yB = yA;
412 ax = (float)luaL_checknumber(L, 5);
413 ay = (float)luaL_checknumber(L, 6);
414 collideConnected = luax_optboolean(L, 7, false);
415 }
416
417 WheelJoint *j;
418 luax_catchexcept(L, [&]() {
419 j = instance()->newWheelJoint(body1, body2, xA, yA, xB, yB, ax, ay, collideConnected);
420 });
421 luax_pushtype(L, j);
422 j->release();
423 return 1;
424}
425
426int w_newRopeJoint(lua_State *L)
427{
428 Body *body1 = luax_checkbody(L, 1);
429 Body *body2 = luax_checkbody(L, 2);
430 float x1 = (float)luaL_checknumber(L, 3);
431 float y1 = (float)luaL_checknumber(L, 4);
432 float x2 = (float)luaL_checknumber(L, 5);
433 float y2 = (float)luaL_checknumber(L, 6);
434 float maxLength = (float)luaL_checknumber(L, 7);
435 bool collideConnected = luax_optboolean(L, 8, false);
436 RopeJoint *j;
437 luax_catchexcept(L, [&]() {
438 j = instance()->newRopeJoint(body1, body2, x1, y1, x2, y2, maxLength, collideConnected);
439 });
440 luax_pushtype(L, j);
441 j->release();
442 return 1;
443}
444
445int w_newMotorJoint(lua_State *L)
446{
447 Body *body1 = luax_checkbody(L, 1);
448 Body *body2 = luax_checkbody(L, 2);
449 MotorJoint *j = 0;
450 if (!lua_isnoneornil(L, 3))
451 {
452 float correctionFactor = (float)luaL_checknumber(L, 3);
453 bool collideConnected = luax_optboolean(L, 4, false);
454 luax_catchexcept(L, [&]() {
455 j = instance()->newMotorJoint(body1, body2, correctionFactor, collideConnected);
456 });
457 }
458 else
459 {
460 luax_catchexcept(L, [&](){ j = instance()->newMotorJoint(body1, body2); });
461 }
462 luax_pushtype(L, j);
463 j->release();
464 return 1;
465}
466
467int w_getDistance(lua_State *L)
468{
469 return instance()->getDistance(L);
470}
471
472int w_setMeter(lua_State *L)
473{
474 float arg1 = (float) luaL_checknumber(L, 1);
475 luax_catchexcept(L, [&](){ Physics::setMeter(arg1); });
476 return 0;
477
478}
479int w_getMeter(lua_State *L)
480{
481 lua_pushinteger(L, Physics::getMeter());
482 return 1;
483}
484
485// List of functions to wrap.
486static const luaL_Reg functions[] =
487{
488 { "newWorld", w_newWorld },
489 { "newBody", w_newBody },
490 { "newFixture", w_newFixture },
491 { "newCircleShape", w_newCircleShape },
492 { "newRectangleShape", w_newRectangleShape },
493 { "newPolygonShape", w_newPolygonShape },
494 { "newEdgeShape", w_newEdgeShape },
495 { "newChainShape", w_newChainShape },
496 { "newDistanceJoint", w_newDistanceJoint },
497 { "newMouseJoint", w_newMouseJoint },
498 { "newRevoluteJoint", w_newRevoluteJoint },
499 { "newPrismaticJoint", w_newPrismaticJoint },
500 { "newPulleyJoint", w_newPulleyJoint },
501 { "newGearJoint", w_newGearJoint },
502 { "newFrictionJoint", w_newFrictionJoint },
503 { "newWeldJoint", w_newWeldJoint },
504 { "newWheelJoint", w_newWheelJoint },
505 { "newRopeJoint", w_newRopeJoint },
506 { "newMotorJoint", w_newMotorJoint },
507 { "getDistance", w_getDistance },
508 { "getMeter", w_getMeter },
509 { "setMeter", w_setMeter },
510 { 0, 0 },
511};
512
513static const lua_CFunction types[] =
514{
515 luaopen_world,
516 luaopen_contact,
517 luaopen_body,
518 luaopen_fixture,
519 luaopen_shape,
520 luaopen_circleshape,
521 luaopen_polygonshape,
522 luaopen_edgeshape,
523 luaopen_chainshape,
524 luaopen_joint,
525 luaopen_mousejoint,
526 luaopen_distancejoint,
527 luaopen_prismaticjoint,
528 luaopen_revolutejoint,
529 luaopen_pulleyjoint,
530 luaopen_gearjoint,
531 luaopen_frictionjoint,
532 luaopen_weldjoint,
533 luaopen_wheeljoint,
534 luaopen_ropejoint,
535 luaopen_motorjoint,
536 0
537};
538
539extern "C" int luaopen_love_physics(lua_State *L)
540{
541 Physics *instance = instance();
542 if (instance == nullptr)
543 {
544 luax_catchexcept(L, [&](){ instance = new Physics(); });
545 }
546 else
547 instance->retain();
548
549 WrappedModule w;
550 w.module = instance;
551 w.name = "physics";
552 w.type = &Module::type;
553 w.functions = functions;
554 w.types = types;
555
556 return luax_register_module(L, w);
557}
558
559} // box2d
560} // physics
561} // love
562