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 "Fixture.h"
22 
23 // Module
24 #include "Body.h"
25 #include "World.h"
26 #include "Physics.h"
27 
28 #include "common/Memoizer.h"
29 
30 // STD
31 #include <bitset>
32 
33 namespace love
34 {
35 namespace physics
36 {
37 namespace box2d
38 {
39 
Fixture(Body * body,Shape * shape,float density)40 Fixture::Fixture(Body *body, Shape *shape, float density)
41 	: body(body)
42 	, fixture(nullptr)
43 {
44 	data = new fixtureudata();
45 	data->ref = nullptr;
46 	b2FixtureDef def;
47 	def.shape = shape->shape;
48 	def.userData = (void *)data;
49 	def.density = density;
50 	fixture = body->body->CreateFixture(&def);
51 	this->retain();
52 	Memoizer::add(fixture, this);
53 }
54 
Fixture(b2Fixture * f)55 Fixture::Fixture(b2Fixture *f)
56 	: fixture(f)
57 {
58 	data = (fixtureudata *)f->GetUserData();
59 	body = (Body *)Memoizer::find(f->GetBody());
60 	if (!body)
61 		body = new Body(f->GetBody());
62 	this->retain();
63 	Memoizer::add(fixture, this);
64 }
65 
~Fixture()66 Fixture::~Fixture()
67 {
68 	if (data != nullptr)
69 		delete data->ref;
70 
71 	delete data;
72 }
73 
getType() const74 Shape::Type Fixture::getType() const
75 {
76 	return Shape(fixture->GetShape(), false).getType();
77 }
78 
setFriction(float friction)79 void Fixture::setFriction(float friction)
80 {
81 	fixture->SetFriction(friction);
82 }
83 
setRestitution(float restitution)84 void Fixture::setRestitution(float restitution)
85 {
86 	fixture->SetRestitution(restitution);
87 }
88 
setDensity(float density)89 void Fixture::setDensity(float density)
90 {
91 	fixture->SetDensity(density);
92 }
93 
setSensor(bool sensor)94 void Fixture::setSensor(bool sensor)
95 {
96 	fixture->SetSensor(sensor);
97 }
98 
getFriction() const99 float Fixture::getFriction() const
100 {
101 	return fixture->GetFriction();
102 }
103 
getRestitution() const104 float Fixture::getRestitution() const
105 {
106 	return fixture->GetRestitution();
107 }
108 
getDensity() const109 float Fixture::getDensity() const
110 {
111 	return fixture->GetDensity();
112 }
113 
isSensor() const114 bool Fixture::isSensor() const
115 {
116 	return fixture->IsSensor();
117 }
118 
getBody() const119 Body *Fixture::getBody() const
120 {
121 	return body;
122 }
123 
getShape() const124 Shape *Fixture::getShape() const
125 {
126 	if (!fixture->GetShape())
127 		return nullptr;
128 
129 	return new Shape(fixture->GetShape(), false);
130 }
131 
isValid() const132 bool Fixture::isValid() const
133 {
134 	return fixture != nullptr;
135 }
136 
setFilterData(int * v)137 void Fixture::setFilterData(int *v)
138 {
139 	b2Filter f;
140 	f.categoryBits = (uint16) v[0];
141 	f.maskBits = (uint16) v[1];
142 	f.groupIndex = (int16) v[2];
143 	fixture->SetFilterData(f);
144 }
145 
getFilterData(int * v)146 void Fixture::getFilterData(int *v)
147 {
148 	b2Filter f = fixture->GetFilterData();
149 	v[0] = (int) f.categoryBits;
150 	v[1] = (int) f.maskBits;
151 	v[2] = (int) f.groupIndex;
152 }
153 
setCategory(lua_State * L)154 int Fixture::setCategory(lua_State *L)
155 {
156 	b2Filter f = fixture->GetFilterData();
157 	f.categoryBits = (uint16)getBits(L);
158 	fixture->SetFilterData(f);
159 	return 0;
160 }
161 
setMask(lua_State * L)162 int Fixture::setMask(lua_State *L)
163 {
164 	b2Filter f = fixture->GetFilterData();
165 	f.maskBits = ~(uint16)getBits(L);
166 	fixture->SetFilterData(f);
167 	return 0;
168 }
169 
setGroupIndex(int index)170 void Fixture::setGroupIndex(int index)
171 {
172 	b2Filter f = fixture->GetFilterData();
173 	f.groupIndex = (uint16)index;
174 	fixture->SetFilterData(f);
175 }
176 
getGroupIndex() const177 int Fixture::getGroupIndex() const
178 {
179 	b2Filter f = fixture->GetFilterData();
180 	return f.groupIndex;
181 }
182 
getCategory(lua_State * L)183 int Fixture::getCategory(lua_State *L)
184 {
185 	return pushBits(L, fixture->GetFilterData().categoryBits);
186 }
187 
getMask(lua_State * L)188 int Fixture::getMask(lua_State *L)
189 {
190 	return pushBits(L, ~(fixture->GetFilterData().maskBits));
191 }
192 
getBits(lua_State * L)193 uint16 Fixture::getBits(lua_State *L)
194 {
195 	// Get number of args.
196 	bool istable = lua_istable(L, 1);
197 	int argc = istable ? (int) luax_objlen(L, 1) : lua_gettop(L);
198 
199 	// The new bitset.
200 	std::bitset<16> b;
201 
202 	for (int i = 1; i <= argc; i++)
203 	{
204 		size_t bpos = 0;
205 
206 		if (istable)
207 		{
208 			lua_rawgeti(L, 1, i);
209 			bpos = (size_t) (lua_tointeger(L, -1) - 1);
210 			lua_pop(L, 1);
211 		}
212 		else
213 			bpos = (size_t) (lua_tointeger(L, i) - 1);
214 
215 		if (bpos >= 16)
216 			luaL_error(L, "Values must be in range 1-16.");
217 
218 		b.set(bpos, true);
219 	}
220 
221 	return (uint16)b.to_ulong();
222 }
223 
pushBits(lua_State * L,uint16 bits)224 int Fixture::pushBits(lua_State *L, uint16 bits)
225 {
226 	// Create a bitset.
227 	std::bitset<16> b((int)bits);
228 
229 	// Push all set bits.
230 	for (int i = 0; i<16; i++)
231 		if (b.test(i))
232 			lua_pushinteger(L, i+1);
233 
234 	// Count number of set bits.
235 	return (int)b.count();
236 }
237 
setUserData(lua_State * L)238 int Fixture::setUserData(lua_State *L)
239 {
240 	love::luax_assert_argc(L, 1, 1);
241 
242 	delete data->ref;
243 	data->ref = new Reference(L);
244 
245 	return 0;
246 }
247 
getUserData(lua_State * L)248 int Fixture::getUserData(lua_State *L)
249 {
250 	if (data->ref != nullptr)
251 		data->ref->push(L);
252 	else
253 		lua_pushnil(L);
254 
255 	return 1;
256 }
257 
testPoint(float x,float y) const258 bool Fixture::testPoint(float x, float y) const
259 {
260 	return fixture->TestPoint(Physics::scaleDown(b2Vec2(x, y)));
261 }
262 
rayCast(lua_State * L) const263 int Fixture::rayCast(lua_State *L) const
264 {
265 	float p1x = Physics::scaleDown((float)luaL_checknumber(L, 1));
266 	float p1y = Physics::scaleDown((float)luaL_checknumber(L, 2));
267 	float p2x = Physics::scaleDown((float)luaL_checknumber(L, 3));
268 	float p2y = Physics::scaleDown((float)luaL_checknumber(L, 4));
269 	float maxFraction = (float)luaL_checknumber(L, 5);
270 	int childIndex = (int) luaL_optnumber(L, 6, 1) - 1; // Convert from 1-based index
271 	b2RayCastInput input;
272 	input.p1.Set(p1x, p1y);
273 	input.p2.Set(p2x, p2y);
274 	input.maxFraction = maxFraction;
275 	b2RayCastOutput output;
276 	if (!fixture->RayCast(&output, input, childIndex))
277 		return 0; // Nothing hit.
278 	lua_pushnumber(L, output.normal.x);
279 	lua_pushnumber(L, output.normal.y);
280 	lua_pushnumber(L, output.fraction);
281 	return 3;
282 }
283 
getBoundingBox(lua_State * L) const284 int Fixture::getBoundingBox(lua_State *L) const
285 {
286 	int childIndex = (int) luaL_optnumber(L, 1, 1) - 1; // Convert from 1-based index
287 	b2AABB box;
288 	luax_catchexcept(L, [&]() { box = fixture->GetAABB(childIndex); });
289 	box = Physics::scaleUp(box);
290 	lua_pushnumber(L, box.lowerBound.x);
291 	lua_pushnumber(L, box.lowerBound.y);
292 	lua_pushnumber(L, box.upperBound.x);
293 	lua_pushnumber(L, box.upperBound.y);
294 	return 4;
295 }
296 
getMassData(lua_State * L) const297 int Fixture::getMassData(lua_State *L) const
298 {
299 	b2MassData data;
300 	fixture->GetMassData(&data);
301 	b2Vec2 center = Physics::scaleUp(data.center);
302 	lua_pushnumber(L, center.x);
303 	lua_pushnumber(L, center.y);
304 	lua_pushnumber(L, data.mass);
305 	lua_pushnumber(L, data.I);
306 	return 4;
307 }
308 
destroy(bool implicit)309 void Fixture::destroy(bool implicit)
310 {
311 	if (body->world->world->IsLocked())
312 	{
313 		// Called during time step. Save reference for destruction afterwards.
314 		this->retain();
315 		body->world->destructFixtures.push_back(this);
316 		return;
317 	}
318 
319 	if (!implicit && fixture != nullptr)
320 		body->body->DestroyFixture(fixture);
321 	Memoizer::remove(fixture);
322 	fixture = nullptr;
323 
324 	// Box2D fixture destroyed. Release its reference to the love Fixture.
325 	this->release();
326 }
327 
328 } // box2d
329 } // physics
330 } // love
331