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