reflexion 0.4.2 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/src/fixture.cpp CHANGED
@@ -2,8 +2,7 @@
2
2
 
3
3
 
4
4
  #include <assert.h>
5
- #include <box2d/b2_fixture.h>
6
- #include <box2d/b2_circle_shape.h>
5
+ #include <box2d/box2d.h>
7
6
  #include "reflex/exception.h"
8
7
  #include "reflex/debug.h"
9
8
  #include "view.h"
@@ -15,103 +14,171 @@ namespace Reflex
15
14
  {
16
15
 
17
16
 
18
- Fixture::Fixture (Body* body, const b2Shape* b2shape, void* userdata)
19
- : b2fixture(NULL)
17
+ static b2ShapeDef
18
+ make_shape_def (
19
+ void* data,
20
+ float density = Fixture::DEFAULT_DENSITY,
21
+ float friction = Fixture::DEFAULT_FRICTION,
22
+ float restitution = Fixture::DEFAULT_RESTITUTION,
23
+ bool sensor = false)
24
+ {
25
+ b2ShapeDef def = b2DefaultShapeDef();
26
+ def.userData = data;
27
+ def.density = density;
28
+ def.material.friction = friction;
29
+ def.material.restitution = restitution;
30
+ def.isSensor = sensor;
31
+ def.enableSensorEvents = true;
32
+ def.enableContactEvents = true;
33
+ return def;
34
+ }
35
+
36
+
37
+ Fixture::Fixture (Body* body, const b2Circle& circle, void* data)
38
+ : body(body), data(data)
39
+ {
40
+ assert(body);
41
+
42
+ b2ShapeDef def = make_shape_def(data);
43
+ b2ShapeId b2shape = b2CreateCircleShape(Body_get_id(body), &def, &circle);
44
+ if (!b2Shape_IsValid(b2shape))
45
+ physics_error(__FILE__, __LINE__);
46
+
47
+ b2shapes.push_back(b2shape);
48
+ }
49
+
50
+ Fixture::Fixture (Body* body, const b2Polygon& polygon, void* data)
51
+ : body(body), data(data)
20
52
  {
21
53
  assert(body);
22
54
 
23
- b2Body* b2body = Body_get_b2ptr(body);
24
- assert(b2body);
55
+ b2ShapeDef def = make_shape_def(data);
56
+ b2ShapeId b2shape = b2CreatePolygonShape(Body_get_id(body), &def, &polygon);
57
+ if (!b2Shape_IsValid(b2shape))
58
+ physics_error(__FILE__, __LINE__);
59
+
60
+ b2shapes.push_back(b2shape);
61
+ }
62
+
63
+ Fixture::Fixture (Body* body, const b2Segment& segment, void* data)
64
+ : body(body), data(data)
65
+ {
66
+ assert(body);
25
67
 
26
- b2fixture = b2body->CreateFixture(b2shape, 0);
27
- if (!b2fixture)
28
- system_error(__FILE__, __LINE__);
68
+ b2ShapeDef def = make_shape_def(data);
69
+ b2ShapeId b2shape = b2CreateSegmentShape(Body_get_id(body), &def, &segment);
70
+ if (!b2Shape_IsValid(b2shape))
71
+ physics_error(__FILE__, __LINE__);
29
72
 
30
- b2fixture->GetUserData().pointer = (uintptr_t) userdata;
73
+ b2shapes.push_back(b2shape);
74
+ }
75
+
76
+ Fixture::Fixture (
77
+ Body* body, const b2Vec2* points, size_t size, bool loop, void* data)
78
+ : body(body), data(data), chain_loop(loop), chain_points(points, points + size)
79
+ {
80
+ assert(body);
81
+
82
+ create_chain(DEFAULT_FRICTION, DEFAULT_RESTITUTION);
31
83
  }
32
84
 
33
85
  Fixture::~Fixture ()
34
86
  {
35
- b2fixture->GetUserData().pointer = (uintptr_t) NULL;
36
- b2fixture->GetBody()->DestroyFixture(b2fixture);
87
+ destroy_shapes();
37
88
  }
38
89
 
39
90
  void
40
91
  Fixture::set_density (float density)
41
92
  {
42
- if (density == this->density())
93
+ if (density == density_)
43
94
  return;
44
95
 
45
- for (Fixture* p = this; p; p = p->pnext.get())
46
- p->b2fixture->SetDensity(density);
96
+ for (Fixture* fix = this; fix; fix = fix->pnext.get())
97
+ {
98
+ fix->density_ = density;
99
+ fix->apply_density(density);
100
+ }
47
101
 
48
- b2fixture->GetBody()->ResetMassData();
102
+ b2BodyId b2body = Body_get_id(body);
103
+ if (b2Body_IsValid(b2body))
104
+ b2Body_ApplyMassFromShapes(b2body);
49
105
  }
50
106
 
51
107
  float
52
108
  Fixture::density () const
53
109
  {
54
- return b2fixture->GetDensity();
110
+ return density_;
55
111
  }
56
112
 
57
113
  void
58
114
  Fixture::set_friction (float friction)
59
115
  {
60
- if (friction == this->friction())
116
+ if (friction == friction_)
61
117
  return;
62
118
 
63
- for (Fixture* p = this; p; p = p->pnext.get())
64
- p->b2fixture->SetFriction(friction);
119
+ for (Fixture* fix = this; fix; fix = fix->pnext.get())
120
+ {
121
+ fix->friction_ = friction;
122
+
123
+ if (b2Chain_IsValid(fix->b2chain))
124
+ b2Chain_SetFriction(fix->b2chain, friction);
125
+ else for (auto& b2shape : fix->b2shapes)
126
+ {
127
+ if (b2Shape_IsValid(b2shape))
128
+ b2Shape_SetFriction(b2shape, friction);
129
+ }
130
+ }
65
131
  }
66
132
 
67
133
  float
68
134
  Fixture::friction () const
69
135
  {
70
- return b2fixture->GetFriction();
136
+ return friction_;
71
137
  }
72
138
 
73
139
  void
74
140
  Fixture::set_restitution (float restitution)
75
141
  {
76
- if (restitution == this->restitution())
142
+ if (restitution == restitution_)
77
143
  return;
78
144
 
79
- for (Fixture* p = this; p; p = p->pnext.get())
80
- p->b2fixture->SetRestitution(restitution);
145
+ for (Fixture* fix = this; fix; fix = fix->pnext.get())
146
+ {
147
+ fix->restitution_ = restitution;
148
+
149
+ if (b2Chain_IsValid(fix->b2chain))
150
+ b2Chain_SetRestitution(fix->b2chain, restitution);
151
+ else for (auto& b2shape : fix->b2shapes)
152
+ {
153
+ if (b2Shape_IsValid(b2shape))
154
+ b2Shape_SetRestitution(b2shape, restitution);
155
+ }
156
+ }
81
157
  }
82
158
 
83
159
  float
84
160
  Fixture::restitution () const
85
161
  {
86
- return b2fixture->GetRestitution();
162
+ return restitution_;
87
163
  }
88
164
 
89
165
  void
90
- Fixture::set_sensor (bool state)
166
+ Fixture::set_sensor (bool sensor)
91
167
  {
92
- if (state == is_sensor())
168
+ if (sensor == sensor_)
93
169
  return;
94
170
 
95
- for (Fixture* p = this; p; p = p->pnext.get())
96
- p->b2fixture->SetSensor(state);
171
+ for (Fixture* fix = this; fix; fix = fix->pnext.get())
172
+ {
173
+ fix->sensor_ = sensor;
174
+ fix->apply_sensor(sensor);
175
+ }
97
176
  }
98
177
 
99
178
  bool
100
179
  Fixture::is_sensor () const
101
180
  {
102
- return b2fixture->IsSensor();
103
- }
104
-
105
- b2Fixture*
106
- Fixture::b2ptr ()
107
- {
108
- return b2fixture;
109
- }
110
-
111
- const b2Fixture*
112
- Fixture::b2ptr () const
113
- {
114
- return const_cast<Fixture*>(this)->b2ptr();
181
+ return sensor_;
115
182
  }
116
183
 
117
184
  void
@@ -135,12 +202,194 @@ namespace Reflex
135
202
  return const_cast<Fixture*>(this)->next();
136
203
  }
137
204
 
205
+ void
206
+ Fixture::create_chain (float friction, float restitution)
207
+ {
208
+ size_t size = chain_points.size();
209
+ if (size < 2) return;
210
+
211
+ const b2Vec2* p = chain_points.data();
212
+ bool loop = chain_loop;
213
+ std::vector<b2Vec2> points;
214
+
215
+ if (loop && size >= 4)
216
+ points.assign(p, p + size);
217
+ else if (loop && size == 3)
218
+ {
219
+ // Box2D 3.x chains need 4+ points, so emulate small loops
220
+ // with an open chain wrapped around by ghost points
221
+ points = {p[2], p[0], p[1], p[2], p[0], p[1]};
222
+ loop = false;
223
+ }
224
+ else
225
+ {
226
+ // open chains treat the first and last points as ghosts,
227
+ // so duplicate both end points like Box2D 2.x did
228
+ points.reserve(size + 2);
229
+ points.emplace_back(p[0]);
230
+ points.insert(points.end(), p, p + size);
231
+ points.emplace_back(p[size - 1]);
232
+ loop = false;
233
+ }
234
+
235
+ b2SurfaceMaterial mat = b2DefaultSurfaceMaterial();
236
+ mat.friction = friction;
237
+ mat.restitution = restitution;
238
+
239
+ b2ChainDef def = b2DefaultChainDef();
240
+ def.userData = data;
241
+ def.points = points.data();
242
+ def.count = (int) points.size();
243
+ def.materials = &mat;
244
+ def.materialCount = 1;
245
+ def.isLoop = loop;
246
+ def.enableSensorEvents = true;
247
+
248
+ b2chain = b2CreateChain(Body_get_id(body), &def);
249
+ if (!b2Chain_IsValid(b2chain))
250
+ physics_error(__FILE__, __LINE__);
251
+
252
+ int count = b2Chain_GetSegmentCount(b2chain);
253
+ b2shapes.resize(count);
254
+ b2Chain_GetSegments(b2chain, b2shapes.data(), count);
255
+
256
+ // chain segments are created with contact events disabled
257
+ for (auto& b2shape : b2shapes)
258
+ b2Shape_EnableContactEvents(b2shape, true);
259
+ }
138
260
 
139
261
  void
140
- Fixture_copy_attributes (Fixture* to, const Fixture& from)
262
+ Fixture::create_chain_sensors (float friction, float restitution)
141
263
  {
142
- if (!to)
264
+ size_t size = chain_points.size();
265
+ if (size < 2) return;
266
+
267
+ b2ShapeDef def = make_shape_def(data, density_, friction_, restitution_, true);
268
+ b2BodyId b2body = Body_get_id(body);
269
+
270
+ size_t nedges = chain_loop ? size : size - 1;
271
+ for (size_t i = 0; i < nedges; ++i)
272
+ {
273
+ b2Segment seg = {chain_points[i], chain_points[(i + 1) % size]};
274
+ b2ShapeId b2shape = b2CreateSegmentShape(b2body, &def, &seg);
275
+ if (b2Shape_IsValid(b2shape)) b2shapes.push_back(b2shape);
276
+ }
277
+ }
278
+
279
+ void
280
+ Fixture::apply_density (float density)
281
+ {
282
+ if (b2Chain_IsValid(b2chain))
283
+ return;// chains have no mass
284
+
285
+ for (auto& b2shape : b2shapes)
286
+ {
287
+ if (b2Shape_IsValid(b2shape))
288
+ b2Shape_SetDensity(b2shape, density, false);
289
+ }
290
+ }
291
+
292
+ static void
293
+ cleanup_b2shape (b2ShapeId b2shape, World* world)
294
+ {
295
+ if (world)
296
+ World_end_contacts_for(world, b2shape);
297
+
298
+ b2Shape_SetUserData(b2shape, NULL);
299
+ }
300
+
301
+ void
302
+ Fixture::apply_sensor (bool sensor)
303
+ {
304
+ if (!chain_points.empty())
305
+ {
306
+ // chains can not be sensors, so recreate the chain
307
+ // as a list of segment sensors
308
+ destroy_shapes();
309
+ if (sensor)
310
+ create_chain_sensors(friction_, restitution_);
311
+ else
312
+ create_chain(friction_, restitution_);
143
313
  return;
314
+ }
315
+
316
+ b2BodyId b2body = Body_get_id(body);
317
+ World* world = Body_get_world(body);
318
+ b2ShapeDef def = make_shape_def(data, density_, friction_, restitution_, sensor);
319
+
320
+ for (auto& b2shape : b2shapes)
321
+ {
322
+ if (!b2Shape_IsValid(b2shape)) continue;
323
+
324
+ switch (b2Shape_GetType(b2shape))
325
+ {
326
+ case b2_circleShape:
327
+ {
328
+ b2Circle circle = b2Shape_GetCircle(b2shape);
329
+ cleanup_b2shape(b2shape, world);
330
+ b2DestroyShape(b2shape, false);
331
+ b2shape = b2CreateCircleShape(b2body, &def, &circle);
332
+ }
333
+ break;
334
+
335
+ case b2_polygonShape:
336
+ {
337
+ b2Polygon polygon = b2Shape_GetPolygon(b2shape);
338
+ cleanup_b2shape(b2shape, world);
339
+ b2DestroyShape(b2shape, false);
340
+ b2shape = b2CreatePolygonShape(b2body, &def, &polygon);
341
+ }
342
+ break;
343
+
344
+ case b2_segmentShape:
345
+ {
346
+ b2Segment segment = b2Shape_GetSegment(b2shape);
347
+ cleanup_b2shape(b2shape, world);
348
+ b2DestroyShape(b2shape, false);
349
+ b2shape = b2CreateSegmentShape(b2body, &def, &segment);
350
+ }
351
+ break;
352
+
353
+ default: break;
354
+ }
355
+ }
356
+ }
357
+
358
+ void
359
+ Fixture::destroy_shapes ()
360
+ {
361
+ World* world = Body_get_world(body);
362
+
363
+ for (auto& b2shape : b2shapes)
364
+ {
365
+ if (b2Shape_IsValid(b2shape))
366
+ cleanup_b2shape(b2shape, world);
367
+ }
368
+
369
+ if (b2Chain_IsValid(b2chain))
370
+ b2DestroyChain(b2chain);
371
+
372
+ for (auto& b2shape : b2shapes)
373
+ {
374
+ if (b2Shape_IsValid(b2shape))
375
+ b2DestroyShape(b2shape, false);
376
+ }
377
+
378
+ b2chain = b2_nullChainId;
379
+ b2shapes.clear();
380
+ }
381
+
382
+ b2ShapeId
383
+ Fixture::head_shape () const
384
+ {
385
+ return b2shapes.empty() ? b2_nullShapeId : b2shapes[0];
386
+ }
387
+
388
+
389
+ void
390
+ Fixture_copy_attributes (Fixture* to, const Fixture& from)
391
+ {
392
+ if (!to) return;
144
393
 
145
394
  to->set_density( from.density());
146
395
  to->set_friction( from.friction());
@@ -163,16 +412,19 @@ namespace Reflex
163
412
  if (!body)
164
413
  invalid_state_error(__FILE__, __LINE__);
165
414
 
166
- b2CircleShape b2shape;
167
- b2shape.m_radius = 1;
168
-
169
- return new Fixture(body, &b2shape);
415
+ b2Circle b2shape = {{0, 0}, 1};
416
+ return new Fixture(body, b2shape);
170
417
  }
171
418
 
172
419
  bool
173
420
  Fixture_is_temporary (const Fixture& fixture)
174
421
  {
175
- return fixture.b2ptr()->GetBody() == Body_get_b2ptr(get_temporary_body());
422
+ b2ShapeId b2shape = fixture.head_shape();
423
+ if (B2_IS_NULL(b2shape)) return false;
424
+
425
+ b2BodyId b2body = b2Shape_GetBody(b2shape);
426
+ b2BodyId tmp = Body_get_id(get_temporary_body());
427
+ return B2_ID_EQUALS(b2body, tmp);
176
428
  }
177
429
 
178
430
 
data/src/fixture.h CHANGED
@@ -5,14 +5,13 @@
5
5
 
6
6
 
7
7
  #include <memory>
8
+ #include <vector>
9
+ #include <box2d/id.h>
10
+ #include <box2d/collision.h>
8
11
  #include <xot/noncopyable.h>
9
12
  #include "reflex/defs.h"
10
13
 
11
14
 
12
- class b2Fixture;
13
- class b2Shape;
14
-
15
-
16
15
  namespace Reflex
17
16
  {
18
17
 
@@ -25,7 +24,21 @@ namespace Reflex
25
24
 
26
25
  public:
27
26
 
28
- Fixture (Body* body, const b2Shape* b2shape, void* userdata = NULL);
27
+ static constexpr float DEFAULT_DENSITY = 1;
28
+
29
+ static constexpr float DEFAULT_FRICTION = 0.6f;// Box2D 3.x defaults
30
+
31
+ static constexpr float DEFAULT_RESTITUTION = 0;
32
+
33
+ Fixture (Body* body, const b2Circle& circle, void* data = NULL);
34
+
35
+ Fixture (Body* body, const b2Polygon& polygon, void* data = NULL);
36
+
37
+ Fixture (Body* body, const b2Segment& segment, void* data = NULL);
38
+
39
+ Fixture (
40
+ Body* body, const b2Vec2* points, size_t size, bool loop,
41
+ void* data = NULL);
29
42
 
30
43
  ~Fixture ();
31
44
 
@@ -45,10 +58,6 @@ namespace Reflex
45
58
 
46
59
  bool is_sensor () const;
47
60
 
48
- b2Fixture* b2ptr ();
49
-
50
- const b2Fixture* b2ptr () const;
51
-
52
61
  void set_next (Fixture* fixture);
53
62
 
54
63
  Fixture* next ();
@@ -57,10 +66,46 @@ namespace Reflex
57
66
 
58
67
  private:
59
68
 
60
- b2Fixture* b2fixture;
69
+ typedef std::vector<b2Vec2> b2Vec2List;
70
+
71
+ typedef std::vector<b2ShapeId> b2ShapeIdList;
72
+
73
+ Body* body = NULL;
74
+
75
+ void* data = NULL;
76
+
77
+ float density_ = DEFAULT_DENSITY;
78
+
79
+ float friction_ = DEFAULT_FRICTION;
80
+
81
+ float restitution_ = DEFAULT_RESTITUTION;
82
+
83
+ bool sensor_ = false;
84
+
85
+ b2ShapeIdList b2shapes;
86
+
87
+ b2ChainId b2chain = b2_nullChainId;
88
+
89
+ bool chain_loop = false;
90
+
91
+ b2Vec2List chain_points;
61
92
 
62
93
  std::unique_ptr<Fixture> pnext;
63
94
 
95
+ void create_chain (float friction, float restitution);
96
+
97
+ void create_chain_sensors (float friction, float restitution);
98
+
99
+ void apply_density (float density);
100
+
101
+ void apply_sensor (bool state);
102
+
103
+ void destroy_shapes ();
104
+
105
+ b2ShapeId head_shape () const;
106
+
107
+ friend bool Fixture_is_temporary (const Fixture& fixture);
108
+
64
109
  };// Fixture
65
110
 
66
111
 
@@ -103,15 +103,17 @@
103
103
  [NSApp orderFrontStandardAboutPanel: nil];
104
104
  }
105
105
 
106
+ - (void) applicationWillFinishLaunching: (NSNotification*) notification
107
+ {
108
+ [self setupMenu];
109
+ }
110
+
106
111
  - (void) applicationDidFinishLaunching: (NSNotification*) notification
107
112
  {
108
113
  [NSApp setActivationPolicy: NSApplicationActivationPolicyRegular];
109
114
  [NSApp activateIgnoringOtherApps: YES];
110
115
 
111
- if (![self callOnStart])
112
- return;
113
-
114
- [self setupMenu];
116
+ [self callOnStart];
115
117
  }
116
118
 
117
119
  - (NSApplicationTerminateReply) applicationShouldTerminate: (NSApplication*) application