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 | #include "Physics.h" |
22 | |
23 | // LOVE |
24 | #include "common/math.h" |
25 | #include "wrap_Body.h" |
26 | |
27 | namespace love |
28 | { |
29 | namespace physics |
30 | { |
31 | namespace box2d |
32 | { |
33 | |
34 | // TODO: Make this not static. |
35 | float Physics::meter = Physics::DEFAULT_METER; |
36 | |
37 | Physics::Physics() |
38 | { |
39 | meter = DEFAULT_METER; |
40 | } |
41 | |
42 | Physics::~Physics() |
43 | { |
44 | } |
45 | |
46 | const char *Physics::getName() const |
47 | { |
48 | return "love.physics.box2d" ; |
49 | } |
50 | |
51 | World *Physics::newWorld(float gx, float gy, bool sleep) |
52 | { |
53 | return new World(b2Vec2(gx, gy), sleep); |
54 | } |
55 | |
56 | Body *Physics::newBody(World *world, float x, float y, Body::Type type) |
57 | { |
58 | return new Body(world, b2Vec2(x, y), type); |
59 | } |
60 | |
61 | Body *Physics::newBody(World *world, Body::Type type) |
62 | { |
63 | return new Body(world, b2Vec2(0, 0), type); |
64 | } |
65 | |
66 | CircleShape *Physics::newCircleShape(float radius) |
67 | { |
68 | return newCircleShape(0, 0, radius); |
69 | } |
70 | |
71 | CircleShape *Physics::newCircleShape(float x, float y, float radius) |
72 | { |
73 | b2CircleShape *s = new b2CircleShape(); |
74 | s->m_p = Physics::scaleDown(b2Vec2(x, y)); |
75 | s->m_radius = Physics::scaleDown(radius); |
76 | return new CircleShape(s); |
77 | } |
78 | |
79 | PolygonShape *Physics::newRectangleShape(float w, float h) |
80 | { |
81 | return newRectangleShape(0, 0, w, h, 0); |
82 | } |
83 | |
84 | PolygonShape *Physics::newRectangleShape(float x, float y, float w, float h) |
85 | { |
86 | return newRectangleShape(x, y, w, h, 0); |
87 | } |
88 | |
89 | PolygonShape *Physics::newRectangleShape(float x, float y, float w, float h, float angle) |
90 | { |
91 | b2PolygonShape *s = new b2PolygonShape(); |
92 | s->SetAsBox(Physics::scaleDown(w/2.0f), Physics::scaleDown(h/2.0f), Physics::scaleDown(b2Vec2(x, y)), angle); |
93 | return new PolygonShape(s); |
94 | } |
95 | |
96 | EdgeShape *Physics::newEdgeShape(float x1, float y1, float x2, float y2) |
97 | { |
98 | b2EdgeShape *s = new b2EdgeShape(); |
99 | s->Set(Physics::scaleDown(b2Vec2(x1, y1)), Physics::scaleDown(b2Vec2(x2, y2))); |
100 | return new EdgeShape(s); |
101 | } |
102 | |
103 | int Physics::newPolygonShape(lua_State *L) |
104 | { |
105 | int argc = lua_gettop(L); |
106 | |
107 | bool istable = lua_istable(L, 1); |
108 | |
109 | if (istable) |
110 | argc = (int) luax_objlen(L, 1); |
111 | |
112 | if (argc % 2 != 0) |
113 | return luaL_error(L, "Number of vertex components must be a multiple of two." ); |
114 | |
115 | // 3 to 8 (b2_maxPolygonVertices) vertices |
116 | int vcount = argc / 2; |
117 | if (vcount < 3) |
118 | return luaL_error(L, "Expected a minimum of 3 vertices, got %d." , vcount); |
119 | else if (vcount > b2_maxPolygonVertices) |
120 | return luaL_error(L, "Expected a maximum of %d vertices, got %d." , b2_maxPolygonVertices, vcount); |
121 | |
122 | b2Vec2 vecs[b2_maxPolygonVertices]; |
123 | |
124 | if (istable) |
125 | { |
126 | for (int i = 0; i < vcount; i++) |
127 | { |
128 | lua_rawgeti(L, 1, 1 + i * 2); |
129 | lua_rawgeti(L, 1, 2 + i * 2); |
130 | float x = (float)luaL_checknumber(L, -2); |
131 | float y = (float)luaL_checknumber(L, -1); |
132 | vecs[i] = Physics::scaleDown(b2Vec2(x, y)); |
133 | lua_pop(L, 2); |
134 | } |
135 | } |
136 | else |
137 | { |
138 | for (int i = 0; i < vcount; i++) |
139 | { |
140 | float x = (float)luaL_checknumber(L, 1 + i * 2); |
141 | float y = (float)luaL_checknumber(L, 2 + i * 2); |
142 | vecs[i] = Physics::scaleDown(b2Vec2(x, y)); |
143 | } |
144 | } |
145 | |
146 | b2PolygonShape *s = new b2PolygonShape(); |
147 | |
148 | try |
149 | { |
150 | s->Set(vecs, vcount); |
151 | } |
152 | catch (love::Exception &) |
153 | { |
154 | delete s; |
155 | throw; |
156 | } |
157 | |
158 | PolygonShape *p = new PolygonShape(s); |
159 | luax_pushtype(L, p); |
160 | p->release(); |
161 | return 1; |
162 | } |
163 | |
164 | int Physics::newChainShape(lua_State *L) |
165 | { |
166 | int argc = lua_gettop(L)-1; // first argument is looping |
167 | |
168 | bool istable = lua_istable(L, 2); |
169 | |
170 | if (istable) |
171 | argc = (int) luax_objlen(L, 2); |
172 | |
173 | if (argc % 2 != 0) |
174 | return luaL_error(L, "Number of vertex components must be a multiple of two." ); |
175 | |
176 | int vcount = argc/2; |
177 | bool loop = luax_checkboolean(L, 1); |
178 | b2Vec2 *vecs = new b2Vec2[vcount]; |
179 | |
180 | if (istable) |
181 | { |
182 | for (int i = 0; i < vcount; i++) |
183 | { |
184 | lua_rawgeti(L, 2, 1 + i * 2); |
185 | lua_rawgeti(L, 2, 2 + i * 2); |
186 | float x = (float)lua_tonumber(L, -2); |
187 | float y = (float)lua_tonumber(L, -1); |
188 | vecs[i] = Physics::scaleDown(b2Vec2(x, y)); |
189 | lua_pop(L, 2); |
190 | } |
191 | } |
192 | else |
193 | { |
194 | for (int i = 0; i < vcount; i++) |
195 | { |
196 | float x = (float)luaL_checknumber(L, 2 + i * 2); |
197 | float y = (float)luaL_checknumber(L, 3 + i * 2); |
198 | vecs[i] = Physics::scaleDown(b2Vec2(x, y)); |
199 | } |
200 | } |
201 | |
202 | b2ChainShape *s = new b2ChainShape(); |
203 | |
204 | try |
205 | { |
206 | if (loop) |
207 | s->CreateLoop(vecs, vcount); |
208 | else |
209 | s->CreateChain(vecs, vcount); |
210 | } |
211 | catch (love::Exception &) |
212 | { |
213 | delete[] vecs; |
214 | delete s; |
215 | throw; |
216 | } |
217 | |
218 | delete[] vecs; |
219 | |
220 | ChainShape *c = new ChainShape(s); |
221 | luax_pushtype(L, c); |
222 | c->release(); |
223 | return 1; |
224 | } |
225 | |
226 | DistanceJoint *Physics::newDistanceJoint(Body *body1, Body *body2, float x1, float y1, float x2, float y2, bool collideConnected) |
227 | { |
228 | return new DistanceJoint(body1, body2, x1, y1, x2, y2, collideConnected); |
229 | } |
230 | |
231 | MouseJoint *Physics::newMouseJoint(Body *body, float x, float y) |
232 | { |
233 | return new MouseJoint(body, x, y); |
234 | } |
235 | |
236 | RevoluteJoint *Physics::newRevoluteJoint(Body *body1, Body *body2, float xA, float yA, float xB, float yB, bool collideConnected) |
237 | { |
238 | return new RevoluteJoint(body1, body2, xA, yA, xB, yB, collideConnected); |
239 | } |
240 | |
241 | RevoluteJoint *Physics::newRevoluteJoint(Body *body1, Body *body2, float xA, float yA, float xB, float yB, bool collideConnected, float referenceAngle) |
242 | { |
243 | return new RevoluteJoint(body1, body2, xA, yA, xB, yB, collideConnected, referenceAngle); |
244 | } |
245 | |
246 | PrismaticJoint *Physics::newPrismaticJoint(Body *body1, Body *body2, float xA, float yA, float xB, float yB, float ax, float ay, bool collideConnected) |
247 | { |
248 | return new PrismaticJoint(body1, body2, xA, yA, xB, yB, ax, ay, collideConnected); |
249 | } |
250 | |
251 | PrismaticJoint *Physics::newPrismaticJoint(Body *body1, Body *body2, float xA, float yA, float xB, float yB, float ax, float ay, bool collideConnected, float referenceAngle) |
252 | { |
253 | return new PrismaticJoint(body1, body2, xA, yA, xB, yB, ax, ay, collideConnected, referenceAngle); |
254 | } |
255 | |
256 | PulleyJoint *Physics::newPulleyJoint(Body *body1, Body *body2, b2Vec2 groundAnchor1, b2Vec2 groundAnchor2, b2Vec2 anchor1, b2Vec2 anchor2, float ratio, bool collideConnected) |
257 | { |
258 | return new PulleyJoint(body1, body2, groundAnchor1, groundAnchor2, anchor1, anchor2, ratio, collideConnected); |
259 | } |
260 | |
261 | GearJoint *Physics::newGearJoint(Joint *joint1, Joint *joint2, float ratio, bool collideConnected) |
262 | { |
263 | return new GearJoint(joint1, joint2, ratio, collideConnected); |
264 | } |
265 | |
266 | FrictionJoint *Physics::newFrictionJoint(Body *body1, Body *body2, float xA, float yA, float xB, float yB, bool collideConnected) |
267 | { |
268 | return new FrictionJoint(body1, body2, xA, yA, xB, yB, collideConnected); |
269 | } |
270 | |
271 | WeldJoint *Physics::newWeldJoint(Body *body1, Body *body2, float xA, float yA, float xB, float yB, bool collideConnected) |
272 | { |
273 | return new WeldJoint(body1, body2, xA, yA, xB, yB, collideConnected); |
274 | } |
275 | |
276 | WeldJoint *Physics::newWeldJoint(Body *body1, Body *body2, float xA, float yA, float xB, float yB, bool collideConnected, float referenceAngle) |
277 | { |
278 | return new WeldJoint(body1, body2, xA, yA, xB, yB, collideConnected, referenceAngle); |
279 | } |
280 | |
281 | WheelJoint *Physics::newWheelJoint(Body *body1, Body *body2, float xA, float yA, float xB, float yB, float ax, float ay, bool collideConnected) |
282 | { |
283 | return new WheelJoint(body1, body2, xA, yA, xB, yB, ax, ay, collideConnected); |
284 | } |
285 | |
286 | RopeJoint *Physics::newRopeJoint(Body *body1, Body *body2, float x1, float y1, float x2, float y2, float maxLength, bool collideConnected) |
287 | { |
288 | return new RopeJoint(body1, body2, x1, y1, x2, y2, maxLength, collideConnected); |
289 | } |
290 | |
291 | MotorJoint *Physics::newMotorJoint(Body *body1, Body *body2) |
292 | { |
293 | return new MotorJoint(body1, body2); |
294 | } |
295 | |
296 | MotorJoint *Physics::newMotorJoint(Body *body1, Body *body2, float correctionFactor, bool collideConnected) |
297 | { |
298 | return new MotorJoint(body1, body2, correctionFactor, collideConnected); |
299 | } |
300 | |
301 | |
302 | Fixture *Physics::newFixture(Body *body, Shape *shape, float density) |
303 | { |
304 | return new Fixture(body, shape, density); |
305 | } |
306 | |
307 | int Physics::getDistance(lua_State *L) |
308 | { |
309 | Fixture *fixtureA = luax_checktype<Fixture>(L, 1); |
310 | Fixture *fixtureB = luax_checktype<Fixture>(L, 2); |
311 | b2DistanceProxy pA, pB; |
312 | b2DistanceInput i; |
313 | b2DistanceOutput o; |
314 | b2SimplexCache c; |
315 | c.count = 0; |
316 | |
317 | luax_catchexcept(L, [&]() { |
318 | pA.Set(fixtureA->fixture->GetShape(), 0); |
319 | pB.Set(fixtureB->fixture->GetShape(), 0); |
320 | i.proxyA = pA; |
321 | i.proxyB = pB; |
322 | i.transformA = fixtureA->fixture->GetBody()->GetTransform(); |
323 | i.transformB = fixtureB->fixture->GetBody()->GetTransform(); |
324 | i.useRadii = true; |
325 | b2Distance(&o, &c, &i); |
326 | }); |
327 | |
328 | lua_pushnumber(L, Physics::scaleUp(o.distance)); |
329 | lua_pushnumber(L, Physics::scaleUp(o.pointA.x)); |
330 | lua_pushnumber(L, Physics::scaleUp(o.pointA.y)); |
331 | lua_pushnumber(L, Physics::scaleUp(o.pointB.x)); |
332 | lua_pushnumber(L, Physics::scaleUp(o.pointB.y)); |
333 | return 5; |
334 | } |
335 | |
336 | void Physics::setMeter(float scale) |
337 | { |
338 | if (scale < 1) throw love::Exception("Physics error: invalid meter" ); |
339 | Physics::meter = scale; |
340 | } |
341 | |
342 | float Physics::getMeter() |
343 | { |
344 | return meter; |
345 | } |
346 | |
347 | void Physics::scaleDown(float &x, float &y) |
348 | { |
349 | x /= meter; |
350 | y /= meter; |
351 | } |
352 | |
353 | void Physics::scaleUp(float &x, float &y) |
354 | { |
355 | x *= meter; |
356 | y *= meter; |
357 | } |
358 | |
359 | float Physics::scaleDown(float f) |
360 | { |
361 | return f/meter; |
362 | } |
363 | |
364 | float Physics::scaleUp(float f) |
365 | { |
366 | return f*meter; |
367 | } |
368 | |
369 | b2Vec2 Physics::scaleDown(const b2Vec2 &v) |
370 | { |
371 | b2Vec2 t = v; |
372 | scaleDown(t.x, t.y); |
373 | return t; |
374 | } |
375 | |
376 | b2Vec2 Physics::scaleUp(const b2Vec2 &v) |
377 | { |
378 | b2Vec2 t = v; |
379 | scaleUp(t.x, t.y); |
380 | return t; |
381 | } |
382 | |
383 | b2AABB Physics::scaleDown(const b2AABB &aabb) |
384 | { |
385 | b2AABB t; |
386 | t.lowerBound = scaleDown(aabb.lowerBound); |
387 | t.upperBound = scaleDown(aabb.upperBound); |
388 | return t; |
389 | } |
390 | |
391 | b2AABB Physics::scaleUp(const b2AABB &aabb) |
392 | { |
393 | b2AABB t; |
394 | t.lowerBound = scaleUp(aabb.lowerBound); |
395 | t.upperBound = scaleUp(aabb.upperBound); |
396 | return t; |
397 | } |
398 | |
399 | } // box2d |
400 | } // physics |
401 | } // love |
402 | |