1 /**
2  * Copyright (c) 2006-2019 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 "Body.h"
22 
23 #include "common/math.h"
24 
25 #include "Shape.h"
26 #include "Fixture.h"
27 #include "World.h"
28 #include "Physics.h"
29 
30 // Needed for luax_pushjoint.
31 #include "wrap_Joint.h"
32 
33 namespace love
34 {
35 namespace physics
36 {
37 namespace box2d
38 {
39 
Body(World * world,b2Vec2 p,Body::Type type)40 Body::Body(World *world, b2Vec2 p, Body::Type type)
41 	: world(world)
42 	, udata(nullptr)
43 {
44 	udata = new bodyudata();
45 	udata->ref = nullptr;
46 	b2BodyDef def;
47 	def.position = Physics::scaleDown(p);
48 	def.userData = (void *) udata;
49 	body = world->world->CreateBody(&def);
50 	// Box2D body holds a reference to the love Body.
51 	this->retain();
52 	this->setType(type);
53 	world->registerObject(body, this);
54 }
55 
~Body()56 Body::~Body()
57 {
58 	if (!udata)
59 		return;
60 
61 	if (udata->ref)
62 		delete udata->ref;
63 
64 	delete udata;
65 }
66 
getX()67 float Body::getX()
68 {
69 	return Physics::scaleUp(body->GetPosition().x);
70 }
71 
getY()72 float Body::getY()
73 {
74 	return Physics::scaleUp(body->GetPosition().y);
75 }
76 
getPosition(float & x_o,float & y_o)77 void Body::getPosition(float &x_o, float &y_o)
78 {
79 	b2Vec2 v = Physics::scaleUp(body->GetPosition());
80 	x_o = v.x;
81 	y_o = v.y;
82 }
83 
getLinearVelocity(float & x_o,float & y_o)84 void Body::getLinearVelocity(float &x_o, float &y_o)
85 {
86 	b2Vec2 v = Physics::scaleUp(body->GetLinearVelocity());
87 	x_o = v.x;
88 	y_o = v.y;
89 }
90 
getAngle()91 float Body::getAngle()
92 {
93 	return body->GetAngle();
94 }
95 
getWorldCenter(float & x_o,float & y_o)96 void Body::getWorldCenter(float &x_o, float &y_o)
97 {
98 	b2Vec2 v = Physics::scaleUp(body->GetWorldCenter());
99 	x_o = v.x;
100 	y_o = v.y;
101 }
102 
getLocalCenter(float & x_o,float & y_o)103 void Body::getLocalCenter(float &x_o, float &y_o)
104 {
105 	b2Vec2 v = Physics::scaleUp(body->GetLocalCenter());
106 	x_o = v.x;
107 	y_o = v.y;
108 }
109 
getAngularVelocity() const110 float Body::getAngularVelocity() const
111 {
112 	return body->GetAngularVelocity();
113 }
114 
getMass() const115 float Body::getMass() const
116 {
117 	return body->GetMass();
118 }
119 
getInertia() const120 float Body::getInertia() const
121 {
122 	return Physics::scaleUp(Physics::scaleUp(body->GetInertia()));
123 }
124 
getMassData(lua_State * L)125 int Body::getMassData(lua_State *L)
126 {
127 	b2MassData data;
128 	body->GetMassData(&data);
129 	b2Vec2 center = Physics::scaleUp(data.center);
130 	lua_pushnumber(L, center.x);
131 	lua_pushnumber(L, center.y);
132 	lua_pushnumber(L, data.mass);
133 	lua_pushnumber(L, Physics::scaleUp(Physics::scaleUp(data.I)));
134 	return 4;
135 }
136 
getAngularDamping() const137 float Body::getAngularDamping() const
138 {
139 	return body->GetAngularDamping();
140 }
141 
getLinearDamping() const142 float Body::getLinearDamping() const
143 {
144 	return body->GetLinearDamping();
145 }
146 
getGravityScale() const147 float Body::getGravityScale() const
148 {
149 	return body->GetGravityScale();
150 }
151 
getType() const152 Body::Type Body::getType() const
153 {
154 	switch (body->GetType())
155 	{
156 	case b2_staticBody:
157 		return BODY_STATIC;
158 		break;
159 	case b2_dynamicBody:
160 		return BODY_DYNAMIC;
161 		break;
162 	case b2_kinematicBody:
163 		return BODY_KINEMATIC;
164 		break;
165 	default:
166 		return BODY_INVALID;
167 		break;
168 	}
169 }
170 
applyLinearImpulse(float jx,float jy,bool wake)171 void Body::applyLinearImpulse(float jx, float jy, bool wake)
172 {
173 	body->ApplyLinearImpulse(Physics::scaleDown(b2Vec2(jx, jy)), body->GetWorldCenter(), wake);
174 }
175 
applyLinearImpulse(float jx,float jy,float rx,float ry,bool wake)176 void Body::applyLinearImpulse(float jx, float jy, float rx, float ry, bool wake)
177 {
178 	body->ApplyLinearImpulse(Physics::scaleDown(b2Vec2(jx, jy)), Physics::scaleDown(b2Vec2(rx, ry)), wake);
179 }
180 
applyAngularImpulse(float impulse,bool wake)181 void Body::applyAngularImpulse(float impulse, bool wake)
182 {
183 	// Angular impulse is in kg*m^2/s, meaning it needs to be scaled twice
184 	body->ApplyAngularImpulse(Physics::scaleDown(Physics::scaleDown(impulse)), wake);
185 }
186 
applyTorque(float t,bool wake)187 void Body::applyTorque(float t, bool wake)
188 {
189 	// Torque is in N*m, or kg*m^2/s^2, meaning it also needs to be scaled twice
190 	body->ApplyTorque(Physics::scaleDown(Physics::scaleDown(t)), wake);
191 }
192 
applyForce(float fx,float fy,float rx,float ry,bool wake)193 void Body::applyForce(float fx, float fy, float rx, float ry, bool wake)
194 {
195 	body->ApplyForce(Physics::scaleDown(b2Vec2(fx, fy)), Physics::scaleDown(b2Vec2(rx, ry)), wake);
196 }
197 
applyForce(float fx,float fy,bool wake)198 void Body::applyForce(float fx, float fy, bool wake)
199 {
200 	body->ApplyForceToCenter(Physics::scaleDown(b2Vec2(fx, fy)), wake);
201 }
202 
setX(float x)203 void Body::setX(float x)
204 {
205 	body->SetTransform(Physics::scaleDown(b2Vec2(x, getY())), getAngle());
206 }
207 
setY(float y)208 void Body::setY(float y)
209 {
210 	body->SetTransform(Physics::scaleDown(b2Vec2(getX(), y)), getAngle());
211 }
212 
setLinearVelocity(float x,float y)213 void Body::setLinearVelocity(float x, float y)
214 {
215 	body->SetLinearVelocity(Physics::scaleDown(b2Vec2(x, y)));
216 }
217 
setAngle(float d)218 void Body::setAngle(float d)
219 {
220 	body->SetTransform(body->GetPosition(), d);
221 }
222 
setAngularVelocity(float r)223 void Body::setAngularVelocity(float r)
224 {
225 	body->SetAngularVelocity(r);
226 }
227 
setPosition(float x,float y)228 void Body::setPosition(float x, float y)
229 {
230 	body->SetTransform(Physics::scaleDown(b2Vec2(x, y)), body->GetAngle());
231 }
232 
setAngularDamping(float d)233 void Body::setAngularDamping(float d)
234 {
235 	body->SetAngularDamping(d);
236 }
237 
setLinearDamping(float d)238 void Body::setLinearDamping(float d)
239 {
240 	body->SetLinearDamping(d);
241 }
242 
resetMassData()243 void Body::resetMassData()
244 {
245 	body->ResetMassData();
246 }
247 
setMassData(float x,float y,float m,float i)248 void Body::setMassData(float x, float y, float m, float i)
249 {
250 	b2MassData massData;
251 	massData.center = Physics::scaleDown(b2Vec2(x, y));
252 	massData.mass = m;
253 	massData.I = Physics::scaleDown(Physics::scaleDown(i));
254 	body->SetMassData(&massData);
255 }
256 
setMass(float m)257 void Body::setMass(float m)
258 {
259 	b2MassData data;
260 	body->GetMassData(&data);
261 	data.mass = m;
262 	body->SetMassData(&data);
263 }
264 
setInertia(float i)265 void Body::setInertia(float i)
266 {
267 	b2MassData massData;
268 	massData.center = body->GetLocalCenter();
269 	massData.mass = body->GetMass();
270 	massData.I = Physics::scaleDown(Physics::scaleDown(i));
271 	body->SetMassData(&massData);
272 }
273 
setGravityScale(float scale)274 void Body::setGravityScale(float scale)
275 {
276 	body->SetGravityScale(scale);
277 }
278 
setType(Body::Type type)279 void Body::setType(Body::Type type)
280 {
281 	switch (type)
282 	{
283 	case Body::BODY_STATIC:
284 		body->SetType(b2_staticBody);
285 		break;
286 	case Body::BODY_DYNAMIC:
287 		body->SetType(b2_dynamicBody);
288 		break;
289 	case Body::BODY_KINEMATIC:
290 		body->SetType(b2_kinematicBody);
291 		break;
292 	default:
293 		break;
294 	}
295 }
296 
getWorldPoint(float x,float y,float & x_o,float & y_o)297 void Body::getWorldPoint(float x, float y, float &x_o, float &y_o)
298 {
299 	b2Vec2 v = Physics::scaleUp(body->GetWorldPoint(Physics::scaleDown(b2Vec2(x, y))));
300 	x_o = v.x;
301 	y_o = v.y;
302 }
303 
getWorldVector(float x,float y,float & x_o,float & y_o)304 void Body::getWorldVector(float x, float y, float &x_o, float &y_o)
305 {
306 	b2Vec2 v = Physics::scaleUp(body->GetWorldVector(Physics::scaleDown(b2Vec2(x, y))));
307 	x_o = v.x;
308 	y_o = v.y;
309 }
310 
getWorldPoints(lua_State * L)311 int Body::getWorldPoints(lua_State *L)
312 {
313 	int argc = lua_gettop(L);
314 	int vcount = (int)argc/2;
315 	// at least one point
316 	love::luax_assert_argc(L, 2);
317 
318 	for (int i = 0; i<vcount; i++)
319 	{
320 		float x = (float)lua_tonumber(L, 1);
321 		float y = (float)lua_tonumber(L, 2);
322 		// Remove them, so we don't run out of stack space
323 		lua_remove(L, 1);
324 		lua_remove(L, 1);
325 		// Time for scaling
326 		b2Vec2 point = Physics::scaleUp(body->GetWorldPoint(Physics::scaleDown(b2Vec2(x, y))));
327 		// And then we push the result
328 		lua_pushnumber(L, point.x);
329 		lua_pushnumber(L, point.y);
330 	}
331 
332 	return argc;
333 }
334 
getLocalPoint(float x,float y,float & x_o,float & y_o)335 void Body::getLocalPoint(float x, float y, float &x_o, float &y_o)
336 {
337 	b2Vec2 v = Physics::scaleUp(body->GetLocalPoint(Physics::scaleDown(b2Vec2(x, y))));
338 	x_o = v.x;
339 	y_o = v.y;
340 }
341 
getLocalVector(float x,float y,float & x_o,float & y_o)342 void Body::getLocalVector(float x, float y, float &x_o, float &y_o)
343 {
344 	b2Vec2 v = Physics::scaleUp(body->GetLocalVector(Physics::scaleDown(b2Vec2(x, y))));
345 	x_o = v.x;
346 	y_o = v.y;
347 }
348 
getLinearVelocityFromWorldPoint(float x,float y,float & x_o,float & y_o)349 void Body::getLinearVelocityFromWorldPoint(float x, float y, float &x_o, float &y_o)
350 {
351 	b2Vec2 v = Physics::scaleUp(body->GetLinearVelocityFromWorldPoint(Physics::scaleDown(b2Vec2(x, y))));
352 	x_o = v.x;
353 	y_o = v.y;
354 }
355 
getLinearVelocityFromLocalPoint(float x,float y,float & x_o,float & y_o)356 void Body::getLinearVelocityFromLocalPoint(float x, float y, float &x_o, float &y_o)
357 {
358 	b2Vec2 v = Physics::scaleUp(body->GetLinearVelocityFromLocalPoint(Physics::scaleDown(b2Vec2(x, y))));
359 	x_o = v.x;
360 	y_o = v.y;
361 }
362 
isBullet() const363 bool Body::isBullet() const
364 {
365 	return body->IsBullet();
366 }
367 
setBullet(bool bullet)368 void Body::setBullet(bool bullet)
369 {
370 	return body->SetBullet(bullet);
371 }
372 
isActive() const373 bool Body::isActive() const
374 {
375 	return body->IsActive();
376 }
377 
isAwake() const378 bool Body::isAwake() const
379 {
380 	return body->IsAwake();
381 }
382 
setSleepingAllowed(bool allow)383 void Body::setSleepingAllowed(bool allow)
384 {
385 	body->SetSleepingAllowed(allow);
386 }
387 
isSleepingAllowed() const388 bool Body::isSleepingAllowed() const
389 {
390 	return body->IsSleepingAllowed();
391 }
392 
setActive(bool active)393 void Body::setActive(bool active)
394 {
395 	body->SetActive(active);
396 }
397 
setAwake(bool awake)398 void Body::setAwake(bool awake)
399 {
400 	body->SetAwake(awake);
401 }
402 
setFixedRotation(bool fixed)403 void Body::setFixedRotation(bool fixed)
404 {
405 	body->SetFixedRotation(fixed);
406 }
407 
isFixedRotation() const408 bool Body::isFixedRotation() const
409 {
410 	return body->IsFixedRotation();
411 }
412 
isTouching(Body * other) const413 bool Body::isTouching(Body *other) const
414 {
415 	const b2ContactEdge *ce = body->GetContactList();
416 	b2Body *otherbody = other->body;
417 
418 	while (ce != nullptr)
419 	{
420 		if (ce->other == otherbody && ce->contact != nullptr && ce->contact->IsTouching())
421 			return true;
422 
423 		ce = ce->next;
424 	}
425 
426 	return false;
427 }
428 
getWorld() const429 World *Body::getWorld() const
430 {
431 	return world;
432 }
433 
getFixtures(lua_State * L) const434 int Body::getFixtures(lua_State *L) const
435 {
436 	lua_newtable(L);
437 	b2Fixture *f = body->GetFixtureList();
438 	int i = 1;
439 	do
440 	{
441 		if (!f)
442 			break;
443 		Fixture *fixture = (Fixture *)world->findObject(f);
444 		if (!fixture)
445 			throw love::Exception("A fixture has escaped Memoizer!");
446 		luax_pushtype(L, fixture);
447 		lua_rawseti(L, -2, i);
448 		i++;
449 	}
450 	while ((f = f->GetNext()));
451 	return 1;
452 }
453 
getJoints(lua_State * L) const454 int Body::getJoints(lua_State *L) const
455 {
456 	lua_newtable(L);
457 	const b2JointEdge *je = body->GetJointList();
458 	int i = 1;
459 
460 	do
461 	{
462 		if (!je)
463 			break;
464 
465 		Joint *joint = (Joint *) world->findObject(je->joint);
466 		if (!joint)
467 			throw love::Exception("A joint has escaped Memoizer!");
468 
469 		luax_pushjoint(L, joint);
470 		lua_rawseti(L, -2, i);
471 		i++;
472 	}
473 	while ((je = je->next));
474 
475 	return 1;
476 }
477 
getContacts(lua_State * L) const478 int Body::getContacts(lua_State *L) const
479 {
480 	lua_newtable(L);
481 	const b2ContactEdge *ce = body->GetContactList();
482 	int i = 1;
483 	do
484 	{
485 		if (!ce)
486 			break;
487 
488 		Contact *contact = (Contact *) world->findObject(ce->contact);
489 		if (!contact)
490 			contact = new Contact(world, ce->contact);
491 		else
492 			contact->retain();
493 
494 		luax_pushtype(L, contact);
495 		contact->release();
496 		lua_rawseti(L, -2, i);
497 		i++;
498 	}
499 	while ((ce = ce->next));
500 	return 1;
501 }
502 
destroy()503 void Body::destroy()
504 {
505 	if (world->world->IsLocked())
506 	{
507 		// Called during time step. Save reference for destruction afterwards.
508 		this->retain();
509 		world->destructBodies.push_back(this);
510 		return;
511 	}
512 
513 	world->world->DestroyBody(body);
514 	world->unregisterObject(body);
515 	body = NULL;
516 
517 	// Remove userdata reference to avoid it sticking around after GC
518 	if (udata && udata->ref)
519 		udata->ref->unref();
520 
521 	// Box2D body destroyed. Release its reference to the love Body.
522 	this->release();
523 }
524 
setUserData(lua_State * L)525 int Body::setUserData(lua_State *L)
526 {
527 	love::luax_assert_argc(L, 1, 1);
528 
529 	if (udata == nullptr)
530 	{
531 		udata = new bodyudata();
532 		body->SetUserData((void *) udata);
533 	}
534 
535 	if(!udata->ref)
536 		udata->ref = new Reference();
537 
538 	udata->ref->ref(L);
539 
540 	return 0;
541 }
542 
getUserData(lua_State * L)543 int Body::getUserData(lua_State *L)
544 {
545 	if (udata != nullptr && udata->ref != nullptr)
546 		udata->ref->push(L);
547 	else
548 		lua_pushnil(L);
549 
550 	return 1;
551 }
552 
553 } // box2d
554 } // physics
555 } // love
556