pbox2d 0.6.0-java → 0.8.0-java

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.
Files changed (154) hide show
  1. checksums.yaml +4 -4
  2. data/.mvn/extensions.xml +8 -0
  3. data/.mvn/wrapper/maven-wrapper.properties +1 -0
  4. data/.travis.yml +23 -0
  5. data/CHANGELOG.md +8 -0
  6. data/README.md +7 -7
  7. data/Rakefile +1 -2
  8. data/lib/box2d.jar +0 -0
  9. data/lib/pbox2d/version.rb +1 -1
  10. data/lib/pbox2d.rb +1 -0
  11. data/pbox2d.gemspec +6 -11
  12. data/pom.rb +59 -0
  13. data/pom.xml +82 -73
  14. data/src/org/jbox2d/JBox2D.gwt.xml +12 -0
  15. data/src/org/jbox2d/callbacks/ContactAdaptor.java +27 -0
  16. data/src/org/jbox2d/callbacks/ContactFilter.java +59 -0
  17. data/src/org/jbox2d/callbacks/ContactImpulse.java +42 -0
  18. data/src/org/jbox2d/callbacks/ContactListener.java +87 -0
  19. data/src/org/jbox2d/callbacks/DebugDraw.java +297 -0
  20. data/src/org/jbox2d/callbacks/DestructionListener.java +53 -0
  21. data/src/org/jbox2d/callbacks/PairCallback.java +29 -0
  22. data/src/org/jbox2d/callbacks/ParticleDestructionListener.java +20 -0
  23. data/src/org/jbox2d/callbacks/ParticleQueryCallback.java +19 -0
  24. data/src/org/jbox2d/callbacks/ParticleRaycastCallback.java +19 -0
  25. data/src/org/jbox2d/callbacks/QueryCallback.java +45 -0
  26. data/src/org/jbox2d/callbacks/RayCastCallback.java +55 -0
  27. data/src/org/jbox2d/callbacks/TreeCallback.java +42 -0
  28. data/src/org/jbox2d/callbacks/TreeRayCastCallback.java +44 -0
  29. data/src/org/jbox2d/collision/AABB.java +338 -0
  30. data/src/org/jbox2d/collision/Collision.java +1444 -0
  31. data/src/org/jbox2d/collision/ContactID.java +106 -0
  32. data/src/org/jbox2d/collision/Distance.java +773 -0
  33. data/src/org/jbox2d/collision/DistanceInput.java +41 -0
  34. data/src/org/jbox2d/collision/DistanceOutput.java +43 -0
  35. data/src/org/jbox2d/collision/Manifold.java +116 -0
  36. data/src/org/jbox2d/collision/ManifoldPoint.java +104 -0
  37. data/src/org/jbox2d/collision/RayCastInput.java +47 -0
  38. data/src/org/jbox2d/collision/RayCastOutput.java +46 -0
  39. data/src/org/jbox2d/collision/TimeOfImpact.java +526 -0
  40. data/src/org/jbox2d/collision/WorldManifold.java +200 -0
  41. data/src/org/jbox2d/collision/broadphase/BroadPhase.java +92 -0
  42. data/src/org/jbox2d/collision/broadphase/BroadPhaseStrategy.java +88 -0
  43. data/src/org/jbox2d/collision/broadphase/DefaultBroadPhaseBuffer.java +268 -0
  44. data/src/org/jbox2d/collision/broadphase/DynamicTree.java +883 -0
  45. data/src/org/jbox2d/collision/broadphase/DynamicTreeFlatNodes.java +873 -0
  46. data/src/org/jbox2d/collision/broadphase/DynamicTreeNode.java +54 -0
  47. data/src/org/jbox2d/collision/broadphase/Pair.java +46 -0
  48. data/src/org/jbox2d/collision/shapes/ChainShape.java +264 -0
  49. data/src/org/jbox2d/collision/shapes/CircleShape.java +207 -0
  50. data/src/org/jbox2d/collision/shapes/EdgeShape.java +254 -0
  51. data/src/org/jbox2d/collision/shapes/MassData.java +105 -0
  52. data/src/org/jbox2d/collision/shapes/PolygonShape.java +718 -0
  53. data/src/org/jbox2d/collision/shapes/Shape.java +136 -0
  54. data/src/org/jbox2d/collision/shapes/ShapeType.java +32 -0
  55. data/src/org/jbox2d/common/BufferUtils.java +209 -0
  56. data/src/org/jbox2d/common/Color3f.java +88 -0
  57. data/src/org/jbox2d/common/IViewportTransform.java +133 -0
  58. data/src/org/jbox2d/common/Mat22.java +609 -0
  59. data/src/org/jbox2d/common/Mat33.java +290 -0
  60. data/src/org/jbox2d/common/MathUtils.java +335 -0
  61. data/src/org/jbox2d/common/OBBViewportTransform.java +174 -0
  62. data/src/org/jbox2d/common/PlatformMathUtils.java +46 -0
  63. data/src/org/jbox2d/common/RaycastResult.java +37 -0
  64. data/src/org/jbox2d/common/Rot.java +150 -0
  65. data/src/org/jbox2d/common/Settings.java +246 -0
  66. data/src/org/jbox2d/common/Sweep.java +116 -0
  67. data/src/org/jbox2d/common/Timer.java +46 -0
  68. data/src/org/jbox2d/common/Transform.java +203 -0
  69. data/src/org/jbox2d/common/Vec2.java +388 -0
  70. data/src/org/jbox2d/common/Vec3.java +170 -0
  71. data/src/org/jbox2d/dynamics/Body.java +1246 -0
  72. data/src/org/jbox2d/dynamics/BodyDef.java +382 -0
  73. data/src/org/jbox2d/dynamics/BodyType.java +41 -0
  74. data/src/org/jbox2d/dynamics/ContactManager.java +293 -0
  75. data/src/org/jbox2d/dynamics/Filter.java +62 -0
  76. data/src/org/jbox2d/dynamics/Fixture.java +454 -0
  77. data/src/org/jbox2d/dynamics/FixtureDef.java +214 -0
  78. data/src/org/jbox2d/dynamics/FixtureProxy.java +38 -0
  79. data/src/org/jbox2d/dynamics/Island.java +602 -0
  80. data/src/org/jbox2d/dynamics/Profile.java +97 -0
  81. data/src/org/jbox2d/dynamics/SolverData.java +33 -0
  82. data/src/org/jbox2d/dynamics/TimeStep.java +46 -0
  83. data/src/org/jbox2d/dynamics/World.java +2075 -0
  84. data/src/org/jbox2d/dynamics/contacts/ChainAndCircleContact.java +57 -0
  85. data/src/org/jbox2d/dynamics/contacts/ChainAndPolygonContact.java +57 -0
  86. data/src/org/jbox2d/dynamics/contacts/CircleContact.java +50 -0
  87. data/src/org/jbox2d/dynamics/contacts/Contact.java +365 -0
  88. data/src/org/jbox2d/dynamics/contacts/ContactCreator.java +35 -0
  89. data/src/org/jbox2d/dynamics/contacts/ContactEdge.java +56 -0
  90. data/src/org/jbox2d/dynamics/contacts/ContactPositionConstraint.java +49 -0
  91. data/src/org/jbox2d/dynamics/contacts/ContactRegister.java +31 -0
  92. data/src/org/jbox2d/dynamics/contacts/ContactSolver.java +1104 -0
  93. data/src/org/jbox2d/dynamics/contacts/ContactVelocityConstraint.java +60 -0
  94. data/src/org/jbox2d/dynamics/contacts/EdgeAndCircleContact.java +52 -0
  95. data/src/org/jbox2d/dynamics/contacts/EdgeAndPolygonContact.java +52 -0
  96. data/src/org/jbox2d/dynamics/contacts/PolygonAndCircleContact.java +51 -0
  97. data/src/org/jbox2d/dynamics/contacts/PolygonContact.java +50 -0
  98. data/src/org/jbox2d/dynamics/contacts/Position.java +31 -0
  99. data/src/org/jbox2d/dynamics/contacts/Velocity.java +31 -0
  100. data/src/org/jbox2d/dynamics/joints/ConstantVolumeJoint.java +258 -0
  101. data/src/org/jbox2d/dynamics/joints/ConstantVolumeJointDef.java +75 -0
  102. data/src/org/jbox2d/dynamics/joints/DistanceJoint.java +356 -0
  103. data/src/org/jbox2d/dynamics/joints/DistanceJointDef.java +106 -0
  104. data/src/org/jbox2d/dynamics/joints/FrictionJoint.java +294 -0
  105. data/src/org/jbox2d/dynamics/joints/FrictionJointDef.java +78 -0
  106. data/src/org/jbox2d/dynamics/joints/GearJoint.java +520 -0
  107. data/src/org/jbox2d/dynamics/joints/GearJointDef.java +58 -0
  108. data/src/org/jbox2d/dynamics/joints/Jacobian.java +32 -0
  109. data/src/org/jbox2d/dynamics/joints/Joint.java +235 -0
  110. data/src/org/jbox2d/dynamics/joints/JointDef.java +65 -0
  111. data/src/org/jbox2d/dynamics/joints/JointEdge.java +57 -0
  112. data/src/org/jbox2d/dynamics/joints/JointType.java +28 -0
  113. data/src/org/jbox2d/dynamics/joints/LimitState.java +28 -0
  114. data/src/org/jbox2d/dynamics/joints/MotorJoint.java +339 -0
  115. data/src/org/jbox2d/dynamics/joints/MotorJointDef.java +55 -0
  116. data/src/org/jbox2d/dynamics/joints/MouseJoint.java +262 -0
  117. data/src/org/jbox2d/dynamics/joints/MouseJointDef.java +62 -0
  118. data/src/org/jbox2d/dynamics/joints/PrismaticJoint.java +808 -0
  119. data/src/org/jbox2d/dynamics/joints/PrismaticJointDef.java +120 -0
  120. data/src/org/jbox2d/dynamics/joints/PulleyJoint.java +393 -0
  121. data/src/org/jbox2d/dynamics/joints/PulleyJointDef.java +105 -0
  122. data/src/org/jbox2d/dynamics/joints/RevoluteJoint.java +554 -0
  123. data/src/org/jbox2d/dynamics/joints/RevoluteJointDef.java +137 -0
  124. data/src/org/jbox2d/dynamics/joints/RopeJoint.java +276 -0
  125. data/src/org/jbox2d/dynamics/joints/RopeJointDef.java +34 -0
  126. data/src/org/jbox2d/dynamics/joints/WeldJoint.java +424 -0
  127. data/src/org/jbox2d/dynamics/joints/WeldJointDef.java +85 -0
  128. data/src/org/jbox2d/dynamics/joints/WheelJoint.java +498 -0
  129. data/src/org/jbox2d/dynamics/joints/WheelJointDef.java +98 -0
  130. data/src/org/jbox2d/particle/ParticleBodyContact.java +17 -0
  131. data/src/org/jbox2d/particle/ParticleColor.java +52 -0
  132. data/src/org/jbox2d/particle/ParticleContact.java +14 -0
  133. data/src/org/jbox2d/particle/ParticleDef.java +24 -0
  134. data/src/org/jbox2d/particle/ParticleGroup.java +154 -0
  135. data/src/org/jbox2d/particle/ParticleGroupDef.java +62 -0
  136. data/src/org/jbox2d/particle/ParticleGroupType.java +8 -0
  137. data/src/org/jbox2d/particle/ParticleSystem.java +2172 -0
  138. data/src/org/jbox2d/particle/ParticleType.java +28 -0
  139. data/src/org/jbox2d/particle/StackQueue.java +44 -0
  140. data/src/org/jbox2d/particle/VoronoiDiagram.java +209 -0
  141. data/src/org/jbox2d/pooling/IDynamicStack.java +47 -0
  142. data/src/org/jbox2d/pooling/IOrderedStack.java +57 -0
  143. data/src/org/jbox2d/pooling/IWorldPool.java +101 -0
  144. data/src/org/jbox2d/pooling/arrays/FloatArray.java +50 -0
  145. data/src/org/jbox2d/pooling/arrays/GeneratorArray.java +33 -0
  146. data/src/org/jbox2d/pooling/arrays/IntArray.java +53 -0
  147. data/src/org/jbox2d/pooling/arrays/Vec2Array.java +57 -0
  148. data/src/org/jbox2d/pooling/normal/CircleStack.java +77 -0
  149. data/src/org/jbox2d/pooling/normal/DefaultWorldPool.java +331 -0
  150. data/src/org/jbox2d/pooling/normal/MutableStack.java +72 -0
  151. data/src/org/jbox2d/pooling/normal/OrderedStack.java +73 -0
  152. data/src/org/jbox2d/pooling/stacks/DynamicIntStack.java +60 -0
  153. metadata +161 -14
  154. data/lib/jbox2d-library-2.3.1-SNAPSHOT.jar +0 -0
@@ -0,0 +1,2075 @@
1
+ /**
2
+ * *****************************************************************************
3
+ * Copyright (c) 2013, Daniel Murphy
4
+ * All rights reserved.
5
+ *
6
+ * Redistribution and use in source and binary forms, with or without modification,
7
+ * are permitted provided that the following conditions are met:
8
+ * * Redistributions of source code must retain the above copyright notice,
9
+ * this list of conditions and the following disclaimer.
10
+ * * Redistributions in binary form must reproduce the above copyright notice,
11
+ * this list of conditions and the following disclaimer in the documentation
12
+ * and/or other materials provided with the distribution.
13
+ *
14
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
18
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
21
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
23
+ * POSSIBILITY OF SUCH DAMAGE.
24
+ *****************************************************************************
25
+ */
26
+ package org.jbox2d.dynamics;
27
+
28
+ import org.jbox2d.callbacks.ContactFilter;
29
+ import org.jbox2d.callbacks.ContactListener;
30
+ import org.jbox2d.callbacks.DebugDraw;
31
+ import org.jbox2d.callbacks.DestructionListener;
32
+ import org.jbox2d.callbacks.ParticleDestructionListener;
33
+ import org.jbox2d.callbacks.ParticleQueryCallback;
34
+ import org.jbox2d.callbacks.ParticleRaycastCallback;
35
+ import org.jbox2d.callbacks.QueryCallback;
36
+ import org.jbox2d.callbacks.RayCastCallback;
37
+ import org.jbox2d.callbacks.TreeCallback;
38
+ import org.jbox2d.callbacks.TreeRayCastCallback;
39
+ import org.jbox2d.collision.AABB;
40
+ import org.jbox2d.collision.RayCastInput;
41
+ import org.jbox2d.collision.RayCastOutput;
42
+ import org.jbox2d.collision.TimeOfImpact.TOIInput;
43
+ import org.jbox2d.collision.TimeOfImpact.TOIOutput;
44
+ import org.jbox2d.collision.TimeOfImpact.TOIOutputState;
45
+ import org.jbox2d.collision.broadphase.BroadPhase;
46
+ import org.jbox2d.collision.broadphase.BroadPhaseStrategy;
47
+ import org.jbox2d.collision.broadphase.DefaultBroadPhaseBuffer;
48
+ import org.jbox2d.collision.broadphase.DynamicTree;
49
+ import org.jbox2d.collision.shapes.ChainShape;
50
+ import org.jbox2d.collision.shapes.CircleShape;
51
+ import org.jbox2d.collision.shapes.EdgeShape;
52
+ import org.jbox2d.collision.shapes.PolygonShape;
53
+ import org.jbox2d.collision.shapes.Shape;
54
+ import org.jbox2d.collision.shapes.ShapeType;
55
+ import org.jbox2d.common.Color3f;
56
+ import org.jbox2d.common.MathUtils;
57
+ import org.jbox2d.common.Settings;
58
+ import org.jbox2d.common.Sweep;
59
+ import org.jbox2d.common.Timer;
60
+ import org.jbox2d.common.Transform;
61
+ import org.jbox2d.common.Vec2;
62
+ import org.jbox2d.dynamics.contacts.Contact;
63
+ import org.jbox2d.dynamics.contacts.ContactEdge;
64
+ import org.jbox2d.dynamics.contacts.ContactRegister;
65
+ import org.jbox2d.dynamics.joints.Joint;
66
+ import org.jbox2d.dynamics.joints.JointDef;
67
+ import org.jbox2d.dynamics.joints.JointEdge;
68
+ import org.jbox2d.dynamics.joints.PulleyJoint;
69
+ import org.jbox2d.particle.ParticleBodyContact;
70
+ import org.jbox2d.particle.ParticleColor;
71
+ import org.jbox2d.particle.ParticleContact;
72
+ import org.jbox2d.particle.ParticleDef;
73
+ import org.jbox2d.particle.ParticleGroup;
74
+ import org.jbox2d.particle.ParticleGroupDef;
75
+ import org.jbox2d.particle.ParticleSystem;
76
+ import org.jbox2d.pooling.IDynamicStack;
77
+ import org.jbox2d.pooling.IWorldPool;
78
+ import org.jbox2d.pooling.arrays.Vec2Array;
79
+ import org.jbox2d.pooling.normal.DefaultWorldPool;
80
+
81
+ /**
82
+ * The world class manages all physics entities, dynamic simulation, and
83
+ * asynchronous queries. The world also contains efficient memory management
84
+ * facilities.
85
+ *
86
+ * @author Daniel Murphy
87
+ */
88
+ public class World {
89
+
90
+ public static final int WORLD_POOL_SIZE = 100;
91
+ public static final int WORLD_POOL_CONTAINER_SIZE = 10;
92
+
93
+ public static final int NEW_FIXTURE = 0x0001;
94
+ public static final int LOCKED = 0x0002;
95
+ public static final int CLEAR_FORCES = 0x0004;
96
+
97
+ // statistics gathering
98
+ public int activeContacts = 0;
99
+ public int contactPoolCount = 0;
100
+
101
+ protected int m_flags;
102
+
103
+ protected ContactManager m_contactManager;
104
+
105
+ private Body m_bodyList;
106
+ private Joint m_jointList;
107
+
108
+ private int m_bodyCount;
109
+ private int m_jointCount;
110
+
111
+ private final Vec2 m_gravity = new Vec2();
112
+ private boolean m_allowSleep;
113
+
114
+ // private Body m_groundBody;
115
+ private DestructionListener m_destructionListener;
116
+ private ParticleDestructionListener m_particleDestructionListener;
117
+ private DebugDraw m_debugDraw;
118
+
119
+ private final IWorldPool pool;
120
+
121
+ /**
122
+ * This is used to compute the time step ratio to support a variable time
123
+ * step.
124
+ */
125
+ private float m_inv_dt0;
126
+
127
+ // these are for debugging the solver
128
+ private boolean m_warmStarting;
129
+ private boolean m_continuousPhysics;
130
+ private boolean m_subStepping;
131
+
132
+ private boolean m_stepComplete;
133
+
134
+ private Profile m_profile;
135
+
136
+ private ParticleSystem m_particleSystem;
137
+
138
+ private ContactRegister[][] contactStacks
139
+ = new ContactRegister[ShapeType.values().length][ShapeType.values().length];
140
+
141
+ /**
142
+ * Construct a world object.
143
+ *
144
+ * @param gravity the world gravity vector.
145
+ */
146
+ public World(Vec2 gravity) {
147
+ this(gravity, new DefaultWorldPool(WORLD_POOL_SIZE, WORLD_POOL_CONTAINER_SIZE));
148
+ }
149
+
150
+ /**
151
+ * Construct a world object.
152
+ *
153
+ * @param gravity the world gravity vector.
154
+ * @param pool
155
+ */
156
+ public World(Vec2 gravity, IWorldPool pool) {
157
+ this(gravity, pool, new DynamicTree());
158
+ }
159
+
160
+ public World(Vec2 gravity, IWorldPool pool, BroadPhaseStrategy strategy) {
161
+ this(gravity, pool, new DefaultBroadPhaseBuffer(strategy));
162
+ }
163
+
164
+ public World(Vec2 gravity, IWorldPool pool, BroadPhase broadPhase) {
165
+ this.pool = pool;
166
+ m_destructionListener = null;
167
+ m_debugDraw = null;
168
+
169
+ m_bodyList = null;
170
+ m_jointList = null;
171
+
172
+ m_bodyCount = 0;
173
+ m_jointCount = 0;
174
+
175
+ m_warmStarting = true;
176
+ m_continuousPhysics = true;
177
+ m_subStepping = false;
178
+ m_stepComplete = true;
179
+
180
+ m_allowSleep = true;
181
+ m_gravity.set(gravity);
182
+
183
+ m_flags = CLEAR_FORCES;
184
+
185
+ m_inv_dt0 = 0f;
186
+
187
+ m_contactManager = new ContactManager(this, broadPhase);
188
+ m_profile = new Profile();
189
+
190
+ m_particleSystem = new ParticleSystem(this);
191
+
192
+ initializeRegisters();
193
+ }
194
+
195
+ public void setAllowSleep(boolean flag) {
196
+ if (flag == m_allowSleep) {
197
+ return;
198
+ }
199
+
200
+ m_allowSleep = flag;
201
+ if (m_allowSleep == false) {
202
+ for (Body b = m_bodyList; b != null; b = b.m_next) {
203
+ b.setAwake(true);
204
+ }
205
+ }
206
+ }
207
+
208
+ public void setSubStepping(boolean subStepping) {
209
+ this.m_subStepping = subStepping;
210
+ }
211
+
212
+ public boolean isSubStepping() {
213
+ return m_subStepping;
214
+ }
215
+
216
+ public boolean isAllowSleep() {
217
+ return m_allowSleep;
218
+ }
219
+
220
+ private void addType(IDynamicStack<Contact> creator, ShapeType type1, ShapeType type2) {
221
+ ContactRegister register = new ContactRegister();
222
+ register.creator = creator;
223
+ register.primary = true;
224
+ contactStacks[type1.ordinal()][type2.ordinal()] = register;
225
+
226
+ if (type1 != type2) {
227
+ ContactRegister register2 = new ContactRegister();
228
+ register2.creator = creator;
229
+ register2.primary = false;
230
+ contactStacks[type2.ordinal()][type1.ordinal()] = register2;
231
+ }
232
+ }
233
+
234
+ private void initializeRegisters() {
235
+ addType(pool.getCircleContactStack(), ShapeType.CIRCLE, ShapeType.CIRCLE);
236
+ addType(pool.getPolyCircleContactStack(), ShapeType.POLYGON, ShapeType.CIRCLE);
237
+ addType(pool.getPolyContactStack(), ShapeType.POLYGON, ShapeType.POLYGON);
238
+ addType(pool.getEdgeCircleContactStack(), ShapeType.EDGE, ShapeType.CIRCLE);
239
+ addType(pool.getEdgePolyContactStack(), ShapeType.EDGE, ShapeType.POLYGON);
240
+ addType(pool.getChainCircleContactStack(), ShapeType.CHAIN, ShapeType.CIRCLE);
241
+ addType(pool.getChainPolyContactStack(), ShapeType.CHAIN, ShapeType.POLYGON);
242
+ }
243
+
244
+ public DestructionListener getDestructionListener() {
245
+ return m_destructionListener;
246
+ }
247
+
248
+ public ParticleDestructionListener getParticleDestructionListener() {
249
+ return m_particleDestructionListener;
250
+ }
251
+
252
+ public void setParticleDestructionListener(ParticleDestructionListener listener) {
253
+ m_particleDestructionListener = listener;
254
+ }
255
+
256
+ public Contact popContact(Fixture fixtureA, int indexA, Fixture fixtureB, int indexB) {
257
+ final ShapeType type1 = fixtureA.getType();
258
+ final ShapeType type2 = fixtureB.getType();
259
+
260
+ final ContactRegister reg = contactStacks[type1.ordinal()][type2.ordinal()];
261
+ if (reg != null) {
262
+ if (reg.primary) {
263
+ Contact c = reg.creator.pop();
264
+ c.init(fixtureA, indexA, fixtureB, indexB);
265
+ return c;
266
+ } else {
267
+ Contact c = reg.creator.pop();
268
+ c.init(fixtureB, indexB, fixtureA, indexA);
269
+ return c;
270
+ }
271
+ } else {
272
+ return null;
273
+ }
274
+ }
275
+
276
+ public void pushContact(Contact contact) {
277
+ Fixture fixtureA = contact.getFixtureA();
278
+ Fixture fixtureB = contact.getFixtureB();
279
+
280
+ if (contact.m_manifold.pointCount > 0 && !fixtureA.isSensor() && !fixtureB.isSensor()) {
281
+ fixtureA.getBody().setAwake(true);
282
+ fixtureB.getBody().setAwake(true);
283
+ }
284
+
285
+ ShapeType type1 = fixtureA.getType();
286
+ ShapeType type2 = fixtureB.getType();
287
+
288
+ IDynamicStack<Contact> creator = contactStacks[type1.ordinal()][type2.ordinal()].creator;
289
+ creator.push(contact);
290
+ }
291
+
292
+ public IWorldPool getPool() {
293
+ return pool;
294
+ }
295
+
296
+ /**
297
+ * Register a destruction listener. The listener is owned by you and must
298
+ * remain in scope.
299
+ *
300
+ * @param listener
301
+ */
302
+ public void setDestructionListener(DestructionListener listener) {
303
+ m_destructionListener = listener;
304
+ }
305
+
306
+ /**
307
+ * Register a contact filter to provide specific control over collision.
308
+ * Otherwise the default filter is used (_defaultFilter). The listener is
309
+ * owned by you and must remain in scope.
310
+ *
311
+ * @param filter
312
+ */
313
+ public void setContactFilter(ContactFilter filter) {
314
+ m_contactManager.m_contactFilter = filter;
315
+ }
316
+
317
+ /**
318
+ * Register a contact event listener. The listener is owned by you and must
319
+ * remain in scope.
320
+ *
321
+ * @param listener
322
+ */
323
+ public void setContactListener(ContactListener listener) {
324
+ m_contactManager.m_contactListener = listener;
325
+ }
326
+
327
+ /**
328
+ * Register a routine for debug drawing. The debug draw functions are called
329
+ * inside with World.DrawDebugData method. The debug draw object is owned by
330
+ * you and must remain in scope.
331
+ *
332
+ * @param debugDraw
333
+ */
334
+ public void setDebugDraw(DebugDraw debugDraw) {
335
+ m_debugDraw = debugDraw;
336
+ }
337
+
338
+ /**
339
+ * create a rigid body given a definition. No reference to the definition is
340
+ * retained.
341
+ *
342
+ * @warning This function is locked during callbacks.
343
+ * @param def
344
+ * @return
345
+ */
346
+ public Body createBody(BodyDef def) {
347
+ assert (isLocked() == false);
348
+ if (isLocked()) {
349
+ return null;
350
+ }
351
+ // TODO djm pooling
352
+ Body b = new Body(def, this);
353
+
354
+ // add to world doubly linked list
355
+ b.m_prev = null;
356
+ b.m_next = m_bodyList;
357
+ if (m_bodyList != null) {
358
+ m_bodyList.m_prev = b;
359
+ }
360
+ m_bodyList = b;
361
+ ++m_bodyCount;
362
+
363
+ return b;
364
+ }
365
+
366
+ /**
367
+ * destroy a rigid body given a definition. No reference to the definition
368
+ * is retained. This function is locked during callbacks.
369
+ *
370
+ * @warning This automatically deletes all associated shapes and joints.
371
+ * @warning This function is locked during callbacks.
372
+ * @param body
373
+ */
374
+ public void destroyBody(Body body) {
375
+ assert (m_bodyCount > 0);
376
+ assert (isLocked() == false);
377
+ if (isLocked()) {
378
+ return;
379
+ }
380
+
381
+ // Delete the attached joints.
382
+ JointEdge je = body.m_jointList;
383
+ while (je != null) {
384
+ JointEdge je0 = je;
385
+ je = je.next;
386
+ if (m_destructionListener != null) {
387
+ m_destructionListener.sayGoodbye(je0.joint);
388
+ }
389
+
390
+ destroyJoint(je0.joint);
391
+
392
+ body.m_jointList = je;
393
+ }
394
+ body.m_jointList = null;
395
+
396
+ // Delete the attached contacts.
397
+ ContactEdge ce = body.m_contactList;
398
+ while (ce != null) {
399
+ ContactEdge ce0 = ce;
400
+ ce = ce.next;
401
+ m_contactManager.destroy(ce0.contact);
402
+ }
403
+ body.m_contactList = null;
404
+
405
+ Fixture f = body.m_fixtureList;
406
+ while (f != null) {
407
+ Fixture f0 = f;
408
+ f = f.m_next;
409
+
410
+ if (m_destructionListener != null) {
411
+ m_destructionListener.sayGoodbye(f0);
412
+ }
413
+
414
+ f0.destroyProxies(m_contactManager.m_broadPhase);
415
+ f0.destroy();
416
+ // TODO djm recycle fixtures (here or in that destroy method)
417
+ body.m_fixtureList = f;
418
+ body.m_fixtureCount -= 1;
419
+ }
420
+ body.m_fixtureList = null;
421
+ body.m_fixtureCount = 0;
422
+
423
+ // Remove world body list.
424
+ if (body.m_prev != null) {
425
+ body.m_prev.m_next = body.m_next;
426
+ }
427
+
428
+ if (body.m_next != null) {
429
+ body.m_next.m_prev = body.m_prev;
430
+ }
431
+
432
+ if (body == m_bodyList) {
433
+ m_bodyList = body.m_next;
434
+ }
435
+
436
+ --m_bodyCount;
437
+ // TODO djm recycle body
438
+ }
439
+
440
+ /**
441
+ * create a joint to constrain bodies together. No reference to the
442
+ * definition is retained. This may cause the connected bodies to cease
443
+ * colliding.
444
+ *
445
+ * @warning This function is locked during callbacks.
446
+ * @param def
447
+ * @return
448
+ */
449
+ public Joint createJoint(JointDef def) {
450
+ assert (isLocked() == false);
451
+ if (isLocked()) {
452
+ return null;
453
+ }
454
+
455
+ Joint j = Joint.create(this, def);
456
+
457
+ // Connect to the world list.
458
+ j.m_prev = null;
459
+ j.m_next = m_jointList;
460
+ if (m_jointList != null) {
461
+ m_jointList.m_prev = j;
462
+ }
463
+ m_jointList = j;
464
+ ++m_jointCount;
465
+
466
+ // Connect to the bodies' doubly linked lists.
467
+ j.m_edgeA.joint = j;
468
+ j.m_edgeA.other = j.getBodyB();
469
+ j.m_edgeA.prev = null;
470
+ j.m_edgeA.next = j.getBodyA().m_jointList;
471
+ if (j.getBodyA().m_jointList != null) {
472
+ j.getBodyA().m_jointList.prev = j.m_edgeA;
473
+ }
474
+ j.getBodyA().m_jointList = j.m_edgeA;
475
+
476
+ j.m_edgeB.joint = j;
477
+ j.m_edgeB.other = j.getBodyA();
478
+ j.m_edgeB.prev = null;
479
+ j.m_edgeB.next = j.getBodyB().m_jointList;
480
+ if (j.getBodyB().m_jointList != null) {
481
+ j.getBodyB().m_jointList.prev = j.m_edgeB;
482
+ }
483
+ j.getBodyB().m_jointList = j.m_edgeB;
484
+
485
+ Body bodyA = def.bodyA;
486
+ Body bodyB = def.bodyB;
487
+
488
+ // If the joint prevents collisions, then flag any contacts for filtering.
489
+ if (def.collideConnected == false) {
490
+ ContactEdge edge = bodyB.getContactList();
491
+ while (edge != null) {
492
+ if (edge.other == bodyA) {
493
+ // Flag the contact for filtering at the next time step (where either
494
+ // body is awake).
495
+ edge.contact.flagForFiltering();
496
+ }
497
+
498
+ edge = edge.next;
499
+ }
500
+ }
501
+
502
+ // Note: creating a joint doesn't wake the bodies.
503
+ return j;
504
+ }
505
+
506
+ /**
507
+ * destroy a joint. This may cause the connected bodies to begin colliding.
508
+ *
509
+ * @warning This function is locked during callbacks.
510
+ * @param joint
511
+ */
512
+ public void destroyJoint(Joint j) {
513
+ assert (isLocked() == false);
514
+ if (isLocked()) {
515
+ return;
516
+ }
517
+
518
+ boolean collideConnected = j.getCollideConnected();
519
+
520
+ // Remove from the doubly linked list.
521
+ if (j.m_prev != null) {
522
+ j.m_prev.m_next = j.m_next;
523
+ }
524
+
525
+ if (j.m_next != null) {
526
+ j.m_next.m_prev = j.m_prev;
527
+ }
528
+
529
+ if (j == m_jointList) {
530
+ m_jointList = j.m_next;
531
+ }
532
+
533
+ // Disconnect from island graph.
534
+ Body bodyA = j.getBodyA();
535
+ Body bodyB = j.getBodyB();
536
+
537
+ // Wake up connected bodies.
538
+ bodyA.setAwake(true);
539
+ bodyB.setAwake(true);
540
+
541
+ // Remove from body 1.
542
+ if (j.m_edgeA.prev != null) {
543
+ j.m_edgeA.prev.next = j.m_edgeA.next;
544
+ }
545
+
546
+ if (j.m_edgeA.next != null) {
547
+ j.m_edgeA.next.prev = j.m_edgeA.prev;
548
+ }
549
+
550
+ if (j.m_edgeA == bodyA.m_jointList) {
551
+ bodyA.m_jointList = j.m_edgeA.next;
552
+ }
553
+
554
+ j.m_edgeA.prev = null;
555
+ j.m_edgeA.next = null;
556
+
557
+ // Remove from body 2
558
+ if (j.m_edgeB.prev != null) {
559
+ j.m_edgeB.prev.next = j.m_edgeB.next;
560
+ }
561
+
562
+ if (j.m_edgeB.next != null) {
563
+ j.m_edgeB.next.prev = j.m_edgeB.prev;
564
+ }
565
+
566
+ if (j.m_edgeB == bodyB.m_jointList) {
567
+ bodyB.m_jointList = j.m_edgeB.next;
568
+ }
569
+
570
+ j.m_edgeB.prev = null;
571
+ j.m_edgeB.next = null;
572
+
573
+ Joint.destroy(j);
574
+
575
+ assert (m_jointCount > 0);
576
+ --m_jointCount;
577
+
578
+ // If the joint prevents collisions, then flag any contacts for filtering.
579
+ if (collideConnected == false) {
580
+ ContactEdge edge = bodyB.getContactList();
581
+ while (edge != null) {
582
+ if (edge.other == bodyA) {
583
+ // Flag the contact for filtering at the next time step (where either
584
+ // body is awake).
585
+ edge.contact.flagForFiltering();
586
+ }
587
+
588
+ edge = edge.next;
589
+ }
590
+ }
591
+ }
592
+
593
+ // djm pooling
594
+ private final TimeStep step = new TimeStep();
595
+ private final Timer stepTimer = new Timer();
596
+ private final Timer tempTimer = new Timer();
597
+
598
+ /**
599
+ * Take a time step. This performs collision detection, integration, and
600
+ * constraint solution.
601
+ *
602
+ * @param timeStep the amount of time to simulate, this should not vary.
603
+ * @param velocityIterations for the velocity constraint solver.
604
+ * @param positionIterations for the position constraint solver.
605
+ */
606
+ public void step(float dt, int velocityIterations, int positionIterations) {
607
+ stepTimer.reset();
608
+ tempTimer.reset();
609
+ // log.debug("Starting step");
610
+ // If new fixtures were added, we need to find the new contacts.
611
+ if ((m_flags & NEW_FIXTURE) == NEW_FIXTURE) {
612
+ // log.debug("There's a new fixture, lets look for new contacts");
613
+ m_contactManager.findNewContacts();
614
+ m_flags &= ~NEW_FIXTURE;
615
+ }
616
+
617
+ m_flags |= LOCKED;
618
+
619
+ step.dt = dt;
620
+ step.velocityIterations = velocityIterations;
621
+ step.positionIterations = positionIterations;
622
+ if (dt > 0.0f) {
623
+ step.inv_dt = 1.0f / dt;
624
+ } else {
625
+ step.inv_dt = 0.0f;
626
+ }
627
+
628
+ step.dtRatio = m_inv_dt0 * dt;
629
+
630
+ step.warmStarting = m_warmStarting;
631
+ m_profile.stepInit.record(tempTimer.getMilliseconds());
632
+
633
+ // Update contacts. This is where some contacts are destroyed.
634
+ tempTimer.reset();
635
+ m_contactManager.collide();
636
+ m_profile.collide.record(tempTimer.getMilliseconds());
637
+
638
+ // Integrate velocities, solve velocity constraints, and integrate positions.
639
+ if (m_stepComplete && step.dt > 0.0f) {
640
+ tempTimer.reset();
641
+ m_particleSystem.solve(step); // Particle Simulation
642
+ m_profile.solveParticleSystem.record(tempTimer.getMilliseconds());
643
+ tempTimer.reset();
644
+ solve(step);
645
+ m_profile.solve.record(tempTimer.getMilliseconds());
646
+ }
647
+
648
+ // Handle TOI events.
649
+ if (m_continuousPhysics && step.dt > 0.0f) {
650
+ tempTimer.reset();
651
+ solveTOI(step);
652
+ m_profile.solveTOI.record(tempTimer.getMilliseconds());
653
+ }
654
+
655
+ if (step.dt > 0.0f) {
656
+ m_inv_dt0 = step.inv_dt;
657
+ }
658
+
659
+ if ((m_flags & CLEAR_FORCES) == CLEAR_FORCES) {
660
+ clearForces();
661
+ }
662
+
663
+ m_flags &= ~LOCKED;
664
+ // log.debug("ending step");
665
+
666
+ m_profile.step.record(stepTimer.getMilliseconds());
667
+ }
668
+
669
+ /**
670
+ * Call this after you are done with time steps to clear the forces. You
671
+ * normally call this after each call to Step, unless you are performing
672
+ * sub-steps. By default, forces will be automatically cleared, so you don't
673
+ * need to call this function.
674
+ *
675
+ * @see setAutoClearForces
676
+ */
677
+ public void clearForces() {
678
+ for (Body body = m_bodyList; body != null; body = body.getNext()) {
679
+ body.m_force.setZero();
680
+ body.m_torque = 0.0f;
681
+ }
682
+ }
683
+
684
+ private final Color3f color = new Color3f();
685
+ private final Transform xf = new Transform();
686
+ private final Vec2 cA = new Vec2();
687
+ private final Vec2 cB = new Vec2();
688
+ private final Vec2Array avs = new Vec2Array();
689
+
690
+ /**
691
+ * Call this to draw shapes and other debug draw data.
692
+ */
693
+ public void drawDebugData() {
694
+ if (m_debugDraw == null) {
695
+ return;
696
+ }
697
+
698
+ int flags = m_debugDraw.getFlags();
699
+ boolean wireframe = (flags & DebugDraw.e_wireframeDrawingBit) != 0;
700
+
701
+ if ((flags & DebugDraw.e_shapeBit) != 0) {
702
+ for (Body b = m_bodyList; b != null; b = b.getNext()) {
703
+ xf.set(b.getTransform());
704
+ for (Fixture f = b.getFixtureList(); f != null; f = f.getNext()) {
705
+ if (b.isActive() == false) {
706
+ color.set(0.5f, 0.5f, 0.3f);
707
+ drawShape(f, xf, color, wireframe);
708
+ } else if (b.getType() == BodyType.STATIC) {
709
+ color.set(0.5f, 0.9f, 0.3f);
710
+ drawShape(f, xf, color, wireframe);
711
+ } else if (b.getType() == BodyType.KINEMATIC) {
712
+ color.set(0.5f, 0.5f, 0.9f);
713
+ drawShape(f, xf, color, wireframe);
714
+ } else if (b.isAwake() == false) {
715
+ color.set(0.5f, 0.5f, 0.5f);
716
+ drawShape(f, xf, color, wireframe);
717
+ } else {
718
+ color.set(0.9f, 0.7f, 0.7f);
719
+ drawShape(f, xf, color, wireframe);
720
+ }
721
+ }
722
+ }
723
+ drawParticleSystem(m_particleSystem);
724
+ }
725
+
726
+ if ((flags & DebugDraw.e_jointBit) != 0) {
727
+ for (Joint j = m_jointList; j != null; j = j.getNext()) {
728
+ drawJoint(j);
729
+ }
730
+ }
731
+
732
+ if ((flags & DebugDraw.e_pairBit) != 0) {
733
+ color.set(0.3f, 0.9f, 0.9f);
734
+ for (Contact c = m_contactManager.m_contactList; c != null; c = c.getNext()) {
735
+ Fixture fixtureA = c.getFixtureA();
736
+ Fixture fixtureB = c.getFixtureB();
737
+ fixtureA.getAABB(c.getChildIndexA()).getCenterToOut(cA);
738
+ fixtureB.getAABB(c.getChildIndexB()).getCenterToOut(cB);
739
+ m_debugDraw.drawSegment(cA, cB, color);
740
+ }
741
+ }
742
+
743
+ if ((flags & DebugDraw.e_aabbBit) != 0) {
744
+ color.set(0.9f, 0.3f, 0.9f);
745
+
746
+ for (Body b = m_bodyList; b != null; b = b.getNext()) {
747
+ if (b.isActive() == false) {
748
+ continue;
749
+ }
750
+
751
+ for (Fixture f = b.getFixtureList(); f != null; f = f.getNext()) {
752
+ for (int i = 0; i < f.m_proxyCount; ++i) {
753
+ FixtureProxy proxy = f.m_proxies[i];
754
+ AABB aabb = m_contactManager.m_broadPhase.getFatAABB(proxy.proxyId);
755
+ if (aabb != null) {
756
+ Vec2[] vs = avs.get(4);
757
+ vs[0].set(aabb.lowerBound.x, aabb.lowerBound.y);
758
+ vs[1].set(aabb.upperBound.x, aabb.lowerBound.y);
759
+ vs[2].set(aabb.upperBound.x, aabb.upperBound.y);
760
+ vs[3].set(aabb.lowerBound.x, aabb.upperBound.y);
761
+ m_debugDraw.drawPolygon(vs, 4, color);
762
+ }
763
+ }
764
+ }
765
+ }
766
+ }
767
+
768
+ if ((flags & DebugDraw.e_centerOfMassBit) != 0) {
769
+ for (Body b = m_bodyList; b != null; b = b.getNext()) {
770
+ xf.set(b.getTransform());
771
+ xf.p.set(b.getWorldCenter());
772
+ m_debugDraw.drawTransform(xf);
773
+ }
774
+ }
775
+
776
+ if ((flags & DebugDraw.e_dynamicTreeBit) != 0) {
777
+ m_contactManager.m_broadPhase.drawTree(m_debugDraw);
778
+ }
779
+
780
+ m_debugDraw.flush();
781
+ }
782
+
783
+ private final WorldQueryWrapper wqwrapper = new WorldQueryWrapper();
784
+
785
+ /**
786
+ * Query the world for all fixtures that potentially overlap the provided
787
+ * AABB.
788
+ *
789
+ * @param callback a user implemented callback class.
790
+ * @param aabb the query box.
791
+ */
792
+ public void queryAABB(QueryCallback callback, AABB aabb) {
793
+ wqwrapper.broadPhase = m_contactManager.m_broadPhase;
794
+ wqwrapper.callback = callback;
795
+ m_contactManager.m_broadPhase.query(wqwrapper, aabb);
796
+ }
797
+
798
+ /**
799
+ * Query the world for all fixtures and particles that potentially overlap
800
+ * the provided AABB.
801
+ *
802
+ * @param callback a user implemented callback class.
803
+ * @param particleCallback callback for particles.
804
+ * @param aabb the query box.
805
+ */
806
+ public void queryAABB(QueryCallback callback, ParticleQueryCallback particleCallback, AABB aabb) {
807
+ wqwrapper.broadPhase = m_contactManager.m_broadPhase;
808
+ wqwrapper.callback = callback;
809
+ m_contactManager.m_broadPhase.query(wqwrapper, aabb);
810
+ m_particleSystem.queryAABB(particleCallback, aabb);
811
+ }
812
+
813
+ /**
814
+ * Query the world for all particles that potentially overlap the provided
815
+ * AABB.
816
+ *
817
+ * @param particleCallback callback for particles.
818
+ * @param aabb the query box.
819
+ */
820
+ public void queryAABB(ParticleQueryCallback particleCallback, AABB aabb) {
821
+ m_particleSystem.queryAABB(particleCallback, aabb);
822
+ }
823
+
824
+ private final WorldRayCastWrapper wrcwrapper = new WorldRayCastWrapper();
825
+ private final RayCastInput input = new RayCastInput();
826
+
827
+ /**
828
+ * Ray-cast the world for all fixtures in the path of the ray. Your callback
829
+ * controls whether you get the closest point, any point, or n-points. The
830
+ * ray-cast ignores shapes that contain the starting point.
831
+ *
832
+ * @param callback a user implemented callback class.
833
+ * @param point1 the ray starting point
834
+ * @param point2 the ray ending point
835
+ */
836
+ public void raycast(RayCastCallback callback, Vec2 point1, Vec2 point2) {
837
+ wrcwrapper.broadPhase = m_contactManager.m_broadPhase;
838
+ wrcwrapper.callback = callback;
839
+ input.maxFraction = 1.0f;
840
+ input.p1.set(point1);
841
+ input.p2.set(point2);
842
+ m_contactManager.m_broadPhase.raycast(wrcwrapper, input);
843
+ }
844
+
845
+ /**
846
+ * Ray-cast the world for all fixtures and particles in the path of the ray.
847
+ * Your callback controls whether you get the closest point, any point, or
848
+ * n-points. The ray-cast ignores shapes that contain the starting point.
849
+ *
850
+ * @param callback a user implemented callback class.
851
+ * @param particleCallback the particle callback class.
852
+ * @param point1 the ray starting point
853
+ * @param point2 the ray ending point
854
+ */
855
+ public void raycast(RayCastCallback callback, ParticleRaycastCallback particleCallback,
856
+ Vec2 point1, Vec2 point2) {
857
+ wrcwrapper.broadPhase = m_contactManager.m_broadPhase;
858
+ wrcwrapper.callback = callback;
859
+ input.maxFraction = 1.0f;
860
+ input.p1.set(point1);
861
+ input.p2.set(point2);
862
+ m_contactManager.m_broadPhase.raycast(wrcwrapper, input);
863
+ m_particleSystem.raycast(particleCallback, point1, point2);
864
+ }
865
+
866
+ /**
867
+ * Ray-cast the world for all particles in the path of the ray. Your
868
+ * callback controls whether you get the closest point, any point, or
869
+ * n-points.
870
+ *
871
+ * @param particleCallback the particle callback class.
872
+ * @param point1 the ray starting point
873
+ * @param point2 the ray ending point
874
+ */
875
+ public void raycast(ParticleRaycastCallback particleCallback, Vec2 point1, Vec2 point2) {
876
+ m_particleSystem.raycast(particleCallback, point1, point2);
877
+ }
878
+
879
+ /**
880
+ * Get the world body list. With the returned body, use Body.getNext to get
881
+ * the next body in the world list. A null body indicates the end of the
882
+ * list.
883
+ *
884
+ * @return the head of the world body list.
885
+ */
886
+ public Body getBodyList() {
887
+ return m_bodyList;
888
+ }
889
+
890
+ /**
891
+ * Get the world joint list. With the returned joint, use Joint.getNext to
892
+ * get the next joint in the world list. A null joint indicates the end of
893
+ * the list.
894
+ *
895
+ * @return the head of the world joint list.
896
+ */
897
+ public Joint getJointList() {
898
+ return m_jointList;
899
+ }
900
+
901
+ /**
902
+ * Get the world contact list. With the returned contact, use
903
+ * Contact.getNext to get the next contact in the world list. A null contact
904
+ * indicates the end of the list.
905
+ *
906
+ * @return the head of the world contact list.
907
+ * @warning contacts are created and destroyed in the middle of a time step.
908
+ * Use ContactListener to avoid missing contacts.
909
+ */
910
+ public Contact getContactList() {
911
+ return m_contactManager.m_contactList;
912
+ }
913
+
914
+ public boolean isSleepingAllowed() {
915
+ return m_allowSleep;
916
+ }
917
+
918
+ public void setSleepingAllowed(boolean sleepingAllowed) {
919
+ m_allowSleep = sleepingAllowed;
920
+ }
921
+
922
+ /**
923
+ * Enable/disable warm starting. For testing.
924
+ *
925
+ * @param flag
926
+ */
927
+ public void setWarmStarting(boolean flag) {
928
+ m_warmStarting = flag;
929
+ }
930
+
931
+ public boolean isWarmStarting() {
932
+ return m_warmStarting;
933
+ }
934
+
935
+ /**
936
+ * Enable/disable continuous physics. For testing.
937
+ *
938
+ * @param flag
939
+ */
940
+ public void setContinuousPhysics(boolean flag) {
941
+ m_continuousPhysics = flag;
942
+ }
943
+
944
+ public boolean isContinuousPhysics() {
945
+ return m_continuousPhysics;
946
+ }
947
+
948
+ /**
949
+ * Get the number of broad-phase proxies.
950
+ *
951
+ * @return
952
+ */
953
+ public int getProxyCount() {
954
+ return m_contactManager.m_broadPhase.getProxyCount();
955
+ }
956
+
957
+ /**
958
+ * Get the number of bodies.
959
+ *
960
+ * @return
961
+ */
962
+ public int getBodyCount() {
963
+ return m_bodyCount;
964
+ }
965
+
966
+ /**
967
+ * Get the number of joints.
968
+ *
969
+ * @return
970
+ */
971
+ public int getJointCount() {
972
+ return m_jointCount;
973
+ }
974
+
975
+ /**
976
+ * Get the number of contacts (each may have 0 or more contact points).
977
+ *
978
+ * @return
979
+ */
980
+ public int getContactCount() {
981
+ return m_contactManager.m_contactCount;
982
+ }
983
+
984
+ /**
985
+ * Gets the height of the dynamic tree
986
+ *
987
+ * @return
988
+ */
989
+ public int getTreeHeight() {
990
+ return m_contactManager.m_broadPhase.getTreeHeight();
991
+ }
992
+
993
+ /**
994
+ * Gets the balance of the dynamic tree
995
+ *
996
+ * @return
997
+ */
998
+ public int getTreeBalance() {
999
+ return m_contactManager.m_broadPhase.getTreeBalance();
1000
+ }
1001
+
1002
+ /**
1003
+ * Gets the quality of the dynamic tree
1004
+ *
1005
+ * @return
1006
+ */
1007
+ public float getTreeQuality() {
1008
+ return m_contactManager.m_broadPhase.getTreeQuality();
1009
+ }
1010
+
1011
+ /**
1012
+ * Change the global gravity vector.
1013
+ *
1014
+ * @param gravity
1015
+ */
1016
+ public void setGravity(Vec2 gravity) {
1017
+ m_gravity.set(gravity);
1018
+ }
1019
+
1020
+ /**
1021
+ * Get the global gravity vector.
1022
+ *
1023
+ * @return
1024
+ */
1025
+ public Vec2 getGravity() {
1026
+ return m_gravity;
1027
+ }
1028
+
1029
+ /**
1030
+ * Is the world locked (in the middle of a time step).
1031
+ *
1032
+ * @return
1033
+ */
1034
+ public boolean isLocked() {
1035
+ return (m_flags & LOCKED) == LOCKED;
1036
+ }
1037
+
1038
+ /**
1039
+ * Set flag to control automatic clearing of forces after each time step.
1040
+ *
1041
+ * @param flag
1042
+ */
1043
+ public void setAutoClearForces(boolean flag) {
1044
+ if (flag) {
1045
+ m_flags |= CLEAR_FORCES;
1046
+ } else {
1047
+ m_flags &= ~CLEAR_FORCES;
1048
+ }
1049
+ }
1050
+
1051
+ /**
1052
+ * Get the flag that controls automatic clearing of forces after each time
1053
+ * step.
1054
+ *
1055
+ * @return
1056
+ */
1057
+ public boolean getAutoClearForces() {
1058
+ return (m_flags & CLEAR_FORCES) == CLEAR_FORCES;
1059
+ }
1060
+
1061
+ /**
1062
+ * Get the contact manager for testing purposes
1063
+ *
1064
+ * @return
1065
+ */
1066
+ public ContactManager getContactManager() {
1067
+ return m_contactManager;
1068
+ }
1069
+
1070
+ public Profile getProfile() {
1071
+ return m_profile;
1072
+ }
1073
+
1074
+ private final Island island = new Island();
1075
+ private Body[] stack = new Body[10]; // TODO djm find a good initial stack number;
1076
+ private final Timer broadphaseTimer = new Timer();
1077
+
1078
+ private void solve(TimeStep step) {
1079
+ m_profile.solveInit.startAccum();
1080
+ m_profile.solveVelocity.startAccum();
1081
+ m_profile.solvePosition.startAccum();
1082
+
1083
+ // update previous transforms
1084
+ for (Body b = m_bodyList; b != null; b = b.m_next) {
1085
+ b.m_xf0.set(b.m_xf);
1086
+ }
1087
+
1088
+ // Size the island for the worst case.
1089
+ island.init(m_bodyCount, m_contactManager.m_contactCount, m_jointCount,
1090
+ m_contactManager.m_contactListener);
1091
+
1092
+ // Clear all the island flags.
1093
+ for (Body b = m_bodyList; b != null; b = b.m_next) {
1094
+ b.m_flags &= ~Body.E_ISLAND_FLAG;
1095
+ }
1096
+ for (Contact c = m_contactManager.m_contactList; c != null; c = c.m_next) {
1097
+ c.m_flags &= ~Contact.ISLAND_FLAG;
1098
+ }
1099
+ for (Joint j = m_jointList; j != null; j = j.m_next) {
1100
+ j.m_islandFlag = false;
1101
+ }
1102
+
1103
+ // Build and simulate all awake islands.
1104
+ int stackSize = m_bodyCount;
1105
+ if (stack.length < stackSize) {
1106
+ stack = new Body[stackSize];
1107
+ }
1108
+ for (Body seed = m_bodyList; seed != null; seed = seed.m_next) {
1109
+ if ((seed.m_flags & Body.E_ISLAND_FLAG) == Body.E_ISLAND_FLAG) {
1110
+ continue;
1111
+ }
1112
+
1113
+ if (seed.isAwake() == false || seed.isActive() == false) {
1114
+ continue;
1115
+ }
1116
+
1117
+ // The seed can be dynamic or kinematic.
1118
+ if (seed.getType() == BodyType.STATIC) {
1119
+ continue;
1120
+ }
1121
+
1122
+ // Reset island and stack.
1123
+ island.clear();
1124
+ int stackCount = 0;
1125
+ stack[stackCount++] = seed;
1126
+ seed.m_flags |= Body.E_ISLAND_FLAG;
1127
+
1128
+ // Perform a depth first search (DFS) on the constraint graph.
1129
+ while (stackCount > 0) {
1130
+ // Grab the next body off the stack and add it to the island.
1131
+ Body b = stack[--stackCount];
1132
+ assert (b.isActive() == true);
1133
+ island.add(b);
1134
+
1135
+ // Make sure the body is awake.
1136
+ b.setAwake(true);
1137
+
1138
+ // To keep islands as small as possible, we don't
1139
+ // propagate islands across static bodies.
1140
+ if (b.getType() == BodyType.STATIC) {
1141
+ continue;
1142
+ }
1143
+
1144
+ // Search all contacts connected to this body.
1145
+ for (ContactEdge ce = b.m_contactList; ce != null; ce = ce.next) {
1146
+ Contact contact = ce.contact;
1147
+
1148
+ // Has this contact already been added to an island?
1149
+ if ((contact.m_flags & Contact.ISLAND_FLAG) == Contact.ISLAND_FLAG) {
1150
+ continue;
1151
+ }
1152
+
1153
+ // Is this contact solid and touching?
1154
+ if (contact.isEnabled() == false || contact.isTouching() == false) {
1155
+ continue;
1156
+ }
1157
+
1158
+ // Skip sensors.
1159
+ boolean sensorA = contact.m_fixtureA.m_isSensor;
1160
+ boolean sensorB = contact.m_fixtureB.m_isSensor;
1161
+ if (sensorA || sensorB) {
1162
+ continue;
1163
+ }
1164
+
1165
+ island.add(contact);
1166
+ contact.m_flags |= Contact.ISLAND_FLAG;
1167
+
1168
+ Body other = ce.other;
1169
+
1170
+ // Was the other body already added to this island?
1171
+ if ((other.m_flags & Body.E_ISLAND_FLAG) == Body.E_ISLAND_FLAG) {
1172
+ continue;
1173
+ }
1174
+
1175
+ assert (stackCount < stackSize);
1176
+ stack[stackCount++] = other;
1177
+ other.m_flags |= Body.E_ISLAND_FLAG;
1178
+ }
1179
+
1180
+ // Search all joints connect to this body.
1181
+ for (JointEdge je = b.m_jointList; je != null; je = je.next) {
1182
+ if (je.joint.m_islandFlag == true) {
1183
+ continue;
1184
+ }
1185
+
1186
+ Body other = je.other;
1187
+
1188
+ // Don't simulate joints connected to inactive bodies.
1189
+ if (other.isActive() == false) {
1190
+ continue;
1191
+ }
1192
+
1193
+ island.add(je.joint);
1194
+ je.joint.m_islandFlag = true;
1195
+
1196
+ if ((other.m_flags & Body.E_ISLAND_FLAG) == Body.E_ISLAND_FLAG) {
1197
+ continue;
1198
+ }
1199
+
1200
+ assert (stackCount < stackSize);
1201
+ stack[stackCount++] = other;
1202
+ other.m_flags |= Body.E_ISLAND_FLAG;
1203
+ }
1204
+ }
1205
+ island.solve(m_profile, step, m_gravity, m_allowSleep);
1206
+
1207
+ // Post solve cleanup.
1208
+ for (int i = 0; i < island.m_bodyCount; ++i) {
1209
+ // Allow static bodies to participate in other islands.
1210
+ Body b = island.m_bodies[i];
1211
+ if (b.getType() == BodyType.STATIC) {
1212
+ b.m_flags &= ~Body.E_ISLAND_FLAG;
1213
+ }
1214
+ }
1215
+ }
1216
+ m_profile.solveInit.endAccum();
1217
+ m_profile.solveVelocity.endAccum();
1218
+ m_profile.solvePosition.endAccum();
1219
+
1220
+ broadphaseTimer.reset();
1221
+ // Synchronize fixtures, check for out of range bodies.
1222
+ for (Body b = m_bodyList; b != null; b = b.getNext()) {
1223
+ // If a body was not in an island then it did not move.
1224
+ if ((b.m_flags & Body.E_ISLAND_FLAG) == 0) {
1225
+ continue;
1226
+ }
1227
+
1228
+ if (b.getType() == BodyType.STATIC) {
1229
+ continue;
1230
+ }
1231
+
1232
+ // Update fixtures (for broad-phase).
1233
+ b.synchronizeFixtures();
1234
+ }
1235
+
1236
+ // Look for new contacts.
1237
+ m_contactManager.findNewContacts();
1238
+ m_profile.broadphase.record(broadphaseTimer.getMilliseconds());
1239
+ }
1240
+
1241
+ private final Island toiIsland = new Island();
1242
+ private final TOIInput toiInput = new TOIInput();
1243
+ private final TOIOutput toiOutput = new TOIOutput();
1244
+ private final TimeStep subStep = new TimeStep();
1245
+ private final Body[] tempBodies = new Body[2];
1246
+ private final Sweep backup1 = new Sweep();
1247
+ private final Sweep backup2 = new Sweep();
1248
+
1249
+ private void solveTOI(final TimeStep step) {
1250
+
1251
+ final Island sIsland = toiIsland;
1252
+ sIsland.init(2 * Settings.maxTOIContacts, Settings.maxTOIContacts, 0,
1253
+ m_contactManager.m_contactListener);
1254
+ if (m_stepComplete) {
1255
+ for (Body b = m_bodyList; b != null; b = b.m_next) {
1256
+ b.m_flags &= ~Body.E_ISLAND_FLAG;
1257
+ b.m_sweep.alpha0 = 0.0f;
1258
+ }
1259
+
1260
+ for (Contact c = m_contactManager.m_contactList; c != null; c = c.m_next) {
1261
+ // Invalidate TOI
1262
+ c.m_flags &= ~(Contact.TOI_FLAG | Contact.ISLAND_FLAG);
1263
+ c.m_toiCount = 0;
1264
+ c.m_toi = 1.0f;
1265
+ }
1266
+ }
1267
+
1268
+ // Find TOI events and solve them.
1269
+ for (;;) {
1270
+ // Find the first TOI.
1271
+ Contact minContact = null;
1272
+ float minAlpha = 1.0f;
1273
+
1274
+ for (Contact c = m_contactManager.m_contactList; c != null; c = c.m_next) {
1275
+ // Is this contact disabled?
1276
+ if (c.isEnabled() == false) {
1277
+ continue;
1278
+ }
1279
+
1280
+ // Prevent excessive sub-stepping.
1281
+ if (c.m_toiCount > Settings.maxSubSteps) {
1282
+ continue;
1283
+ }
1284
+
1285
+ float alpha = 1.0f;
1286
+ if ((c.m_flags & Contact.TOI_FLAG) != 0) {
1287
+ // This contact has a valid cached TOI.
1288
+ alpha = c.m_toi;
1289
+ } else {
1290
+ Fixture fA = c.getFixtureA();
1291
+ Fixture fB = c.getFixtureB();
1292
+
1293
+ // Is there a sensor?
1294
+ if (fA.isSensor() || fB.isSensor()) {
1295
+ continue;
1296
+ }
1297
+
1298
+ Body bA = fA.getBody();
1299
+ Body bB = fB.getBody();
1300
+
1301
+ BodyType typeA = bA.m_type;
1302
+ BodyType typeB = bB.m_type;
1303
+ assert (typeA == BodyType.DYNAMIC || typeB == BodyType.DYNAMIC);
1304
+
1305
+ boolean activeA = bA.isAwake() && typeA != BodyType.STATIC;
1306
+ boolean activeB = bB.isAwake() && typeB != BodyType.STATIC;
1307
+
1308
+ // Is at least one body active (awake and dynamic or kinematic)?
1309
+ if (activeA == false && activeB == false) {
1310
+ continue;
1311
+ }
1312
+
1313
+ boolean collideA = bA.isBullet() || typeA != BodyType.DYNAMIC;
1314
+ boolean collideB = bB.isBullet() || typeB != BodyType.DYNAMIC;
1315
+
1316
+ // Are these two non-bullet dynamic bodies?
1317
+ if (collideA == false && collideB == false) {
1318
+ continue;
1319
+ }
1320
+
1321
+ // Compute the TOI for this contact.
1322
+ // Put the sweeps onto the same time interval.
1323
+ float alpha0 = bA.m_sweep.alpha0;
1324
+
1325
+ if (bA.m_sweep.alpha0 < bB.m_sweep.alpha0) {
1326
+ alpha0 = bB.m_sweep.alpha0;
1327
+ bA.m_sweep.advance(alpha0);
1328
+ } else if (bB.m_sweep.alpha0 < bA.m_sweep.alpha0) {
1329
+ alpha0 = bA.m_sweep.alpha0;
1330
+ bB.m_sweep.advance(alpha0);
1331
+ }
1332
+
1333
+ assert (alpha0 < 1.0f);
1334
+
1335
+ int indexA = c.getChildIndexA();
1336
+ int indexB = c.getChildIndexB();
1337
+
1338
+ // Compute the time of impact in interval [0, minTOI]
1339
+ final TOIInput input = toiInput;
1340
+ input.proxyA.set(fA.getShape(), indexA);
1341
+ input.proxyB.set(fB.getShape(), indexB);
1342
+ input.sweepA.set(bA.m_sweep);
1343
+ input.sweepB.set(bB.m_sweep);
1344
+ input.tMax = 1.0f;
1345
+
1346
+ pool.getTimeOfImpact().timeOfImpact(toiOutput, input);
1347
+
1348
+ // Beta is the fraction of the remaining portion of the .
1349
+ float beta = toiOutput.t;
1350
+ if (toiOutput.state == TOIOutputState.TOUCHING) {
1351
+ alpha = MathUtils.min(alpha0 + (1.0f - alpha0) * beta, 1.0f);
1352
+ } else {
1353
+ alpha = 1.0f;
1354
+ }
1355
+
1356
+ c.m_toi = alpha;
1357
+ c.m_flags |= Contact.TOI_FLAG;
1358
+ }
1359
+
1360
+ if (alpha < minAlpha) {
1361
+ // This is the minimum TOI found so far.
1362
+ minContact = c;
1363
+ minAlpha = alpha;
1364
+ }
1365
+ }
1366
+
1367
+ if (minContact == null || 1.0f - 10.0f * Settings.EPSILON < minAlpha) {
1368
+ // No more TOI events. Done!
1369
+ m_stepComplete = true;
1370
+ break;
1371
+ }
1372
+
1373
+ // Advance the bodies to the TOI.
1374
+ Fixture fA = minContact.getFixtureA();
1375
+ Fixture fB = minContact.getFixtureB();
1376
+ Body bA = fA.getBody();
1377
+ Body bB = fB.getBody();
1378
+
1379
+ backup1.set(bA.m_sweep);
1380
+ backup2.set(bB.m_sweep);
1381
+
1382
+ bA.advance(minAlpha);
1383
+ bB.advance(minAlpha);
1384
+
1385
+ // The TOI contact likely has some new contact points.
1386
+ minContact.update(m_contactManager.m_contactListener);
1387
+ minContact.m_flags &= ~Contact.TOI_FLAG;
1388
+ ++minContact.m_toiCount;
1389
+
1390
+ // Is the contact solid?
1391
+ if (minContact.isEnabled() == false || minContact.isTouching() == false) {
1392
+ // Restore the sweeps.
1393
+ minContact.setEnabled(false);
1394
+ bA.m_sweep.set(backup1);
1395
+ bB.m_sweep.set(backup2);
1396
+ bA.synchronizeTransform();
1397
+ bB.synchronizeTransform();
1398
+ continue;
1399
+ }
1400
+
1401
+ bA.setAwake(true);
1402
+ bB.setAwake(true);
1403
+
1404
+ // Build the island
1405
+ sIsland.clear();
1406
+ sIsland.add(bA);
1407
+ sIsland.add(bB);
1408
+ sIsland.add(minContact);
1409
+
1410
+ bA.m_flags |= Body.E_ISLAND_FLAG;
1411
+ bB.m_flags |= Body.E_ISLAND_FLAG;
1412
+ minContact.m_flags |= Contact.ISLAND_FLAG;
1413
+
1414
+ // Get contacts on bodyA and bodyB.
1415
+ tempBodies[0] = bA;
1416
+ tempBodies[1] = bB;
1417
+ for (int i = 0; i < 2; ++i) {
1418
+ Body body = tempBodies[i];
1419
+ if (body.m_type == BodyType.DYNAMIC) {
1420
+ for (ContactEdge ce = body.m_contactList; ce != null; ce = ce.next) {
1421
+ if (sIsland.m_bodyCount == sIsland.m_bodyCapacity) {
1422
+ break;
1423
+ }
1424
+
1425
+ if (sIsland.m_contactCount == sIsland.m_contactCapacity) {
1426
+ break;
1427
+ }
1428
+
1429
+ Contact contact = ce.contact;
1430
+
1431
+ // Has this contact already been added to the island?
1432
+ if ((contact.m_flags & Contact.ISLAND_FLAG) != 0) {
1433
+ continue;
1434
+ }
1435
+
1436
+ // Only add static, kinematic, or bullet bodies.
1437
+ Body other = ce.other;
1438
+ if (other.m_type == BodyType.DYNAMIC && body.isBullet() == false
1439
+ && other.isBullet() == false) {
1440
+ continue;
1441
+ }
1442
+
1443
+ // Skip sensors.
1444
+ boolean sensorA = contact.m_fixtureA.m_isSensor;
1445
+ boolean sensorB = contact.m_fixtureB.m_isSensor;
1446
+ if (sensorA || sensorB) {
1447
+ continue;
1448
+ }
1449
+
1450
+ // Tentatively advance the body to the TOI.
1451
+ backup1.set(other.m_sweep);
1452
+ if ((other.m_flags & Body.E_ISLAND_FLAG) == 0) {
1453
+ other.advance(minAlpha);
1454
+ }
1455
+
1456
+ // Update the contact points
1457
+ contact.update(m_contactManager.m_contactListener);
1458
+
1459
+ // Was the contact disabled by the user?
1460
+ if (contact.isEnabled() == false) {
1461
+ other.m_sweep.set(backup1);
1462
+ other.synchronizeTransform();
1463
+ continue;
1464
+ }
1465
+
1466
+ // Are there contact points?
1467
+ if (contact.isTouching() == false) {
1468
+ other.m_sweep.set(backup1);
1469
+ other.synchronizeTransform();
1470
+ continue;
1471
+ }
1472
+
1473
+ // Add the contact to the island
1474
+ contact.m_flags |= Contact.ISLAND_FLAG;
1475
+ sIsland.add(contact);
1476
+
1477
+ // Has the other body already been added to the island?
1478
+ if ((other.m_flags & Body.E_ISLAND_FLAG) != 0) {
1479
+ continue;
1480
+ }
1481
+
1482
+ // Add the other body to the island.
1483
+ other.m_flags |= Body.E_ISLAND_FLAG;
1484
+
1485
+ if (other.m_type != BodyType.STATIC) {
1486
+ other.setAwake(true);
1487
+ }
1488
+
1489
+ sIsland.add(other);
1490
+ }
1491
+ }
1492
+ }
1493
+
1494
+ subStep.dt = (1.0f - minAlpha) * step.dt;
1495
+ subStep.inv_dt = 1.0f / subStep.dt;
1496
+ subStep.dtRatio = 1.0f;
1497
+ subStep.positionIterations = 20;
1498
+ subStep.velocityIterations = step.velocityIterations;
1499
+ subStep.warmStarting = false;
1500
+ sIsland.solveTOI(subStep, bA.m_islandIndex, bB.m_islandIndex);
1501
+
1502
+ // Reset island flags and synchronize broad-phase proxies.
1503
+ for (int i = 0; i < sIsland.m_bodyCount; ++i) {
1504
+ Body body = sIsland.m_bodies[i];
1505
+ body.m_flags &= ~Body.E_ISLAND_FLAG;
1506
+
1507
+ if (body.m_type != BodyType.DYNAMIC) {
1508
+ continue;
1509
+ }
1510
+
1511
+ body.synchronizeFixtures();
1512
+
1513
+ // Invalidate all contact TOIs on this displaced body.
1514
+ for (ContactEdge ce = body.m_contactList; ce != null; ce = ce.next) {
1515
+ ce.contact.m_flags &= ~(Contact.TOI_FLAG | Contact.ISLAND_FLAG);
1516
+ }
1517
+ }
1518
+
1519
+ // Commit fixture proxy movements to the broad-phase so that new contacts are created.
1520
+ // Also, some contacts can be destroyed.
1521
+ m_contactManager.findNewContacts();
1522
+
1523
+ if (m_subStepping) {
1524
+ m_stepComplete = false;
1525
+ break;
1526
+ }
1527
+ }
1528
+ }
1529
+
1530
+ private void drawJoint(Joint joint) {
1531
+ Body bodyA = joint.getBodyA();
1532
+ Body bodyB = joint.getBodyB();
1533
+ Transform xf1 = bodyA.getTransform();
1534
+ Transform xf2 = bodyB.getTransform();
1535
+ Vec2 x1 = xf1.p;
1536
+ Vec2 x2 = xf2.p;
1537
+ Vec2 p1 = pool.popVec2();
1538
+ Vec2 p2 = pool.popVec2();
1539
+ joint.getAnchorA(p1);
1540
+ joint.getAnchorB(p2);
1541
+
1542
+ color.set(0.5f, 0.8f, 0.8f);
1543
+
1544
+ switch (joint.getType()) {
1545
+ // TODO djm write after writing joints
1546
+ case DISTANCE:
1547
+ m_debugDraw.drawSegment(p1, p2, color);
1548
+ break;
1549
+
1550
+ case PULLEY: {
1551
+ PulleyJoint pulley = (PulleyJoint) joint;
1552
+ Vec2 s1 = pulley.getGroundAnchorA();
1553
+ Vec2 s2 = pulley.getGroundAnchorB();
1554
+ m_debugDraw.drawSegment(s1, p1, color);
1555
+ m_debugDraw.drawSegment(s2, p2, color);
1556
+ m_debugDraw.drawSegment(s1, s2, color);
1557
+ }
1558
+ break;
1559
+ case CONSTANT_VOLUME:
1560
+ case MOUSE:
1561
+ // don't draw this
1562
+ break;
1563
+ default:
1564
+ m_debugDraw.drawSegment(x1, p1, color);
1565
+ m_debugDraw.drawSegment(p1, p2, color);
1566
+ m_debugDraw.drawSegment(x2, p2, color);
1567
+ }
1568
+ pool.pushVec2(2);
1569
+ }
1570
+
1571
+ // NOTE this corresponds to the liquid test, so the debugdraw can draw
1572
+ // the liquid particles correctly. They should be the same.
1573
+ private static Integer LIQUID_INT = 1234598372;
1574
+ private float liquidLength = .12f;
1575
+ private float averageLinearVel = -1;
1576
+ private final Vec2 liquidOffset = new Vec2();
1577
+ private final Vec2 circCenterMoved = new Vec2();
1578
+ private final Color3f liquidColor = new Color3f(.4f, .4f, 1f);
1579
+
1580
+ private final Vec2 center = new Vec2();
1581
+ private final Vec2 axis = new Vec2();
1582
+ private final Vec2 v1 = new Vec2();
1583
+ private final Vec2 v2 = new Vec2();
1584
+ private final Vec2Array tlvertices = new Vec2Array();
1585
+
1586
+ private void drawShape(Fixture fixture, Transform xf, Color3f color, boolean wireframe) {
1587
+ switch (fixture.getType()) {
1588
+ case CIRCLE: {
1589
+ CircleShape circle = (CircleShape) fixture.getShape();
1590
+
1591
+ // Vec2 center = Mul(xf, circle.m_p);
1592
+ Transform.mulToOutUnsafe(xf, circle.m_p, center);
1593
+ float radius = circle.m_radius;
1594
+ xf.q.getXAxis(axis);
1595
+
1596
+ if (fixture.getUserData() != null && fixture.getUserData().equals(LIQUID_INT)) {
1597
+ Body b = fixture.getBody();
1598
+ liquidOffset.set(b.m_linearVelocity);
1599
+ float linVelLength = b.m_linearVelocity.length();
1600
+ if (averageLinearVel == -1) {
1601
+ averageLinearVel = linVelLength;
1602
+ } else {
1603
+ averageLinearVel = .98f * averageLinearVel + .02f * linVelLength;
1604
+ }
1605
+ liquidOffset.mulLocal(liquidLength / averageLinearVel / 2);
1606
+ circCenterMoved.set(center).addLocal(liquidOffset);
1607
+ center.subLocal(liquidOffset);
1608
+ m_debugDraw.drawSegment(center, circCenterMoved, liquidColor);
1609
+ return;
1610
+ }
1611
+ if (wireframe) {
1612
+ m_debugDraw.drawCircle(center, radius, axis, color);
1613
+ } else {
1614
+ m_debugDraw.drawSolidCircle(center, radius, axis, color);
1615
+ }
1616
+ }
1617
+ break;
1618
+
1619
+ case POLYGON: {
1620
+ PolygonShape poly = (PolygonShape) fixture.getShape();
1621
+ int vertexCount = poly.m_count;
1622
+ assert (vertexCount <= Settings.maxPolygonVertices);
1623
+ Vec2[] vertices = tlvertices.get(Settings.maxPolygonVertices);
1624
+
1625
+ for (int i = 0; i < vertexCount; ++i) {
1626
+ // vertices[i] = Mul(xf, poly.m_vertices[i]);
1627
+ Transform.mulToOutUnsafe(xf, poly.m_vertices[i], vertices[i]);
1628
+ }
1629
+ if (wireframe) {
1630
+ m_debugDraw.drawPolygon(vertices, vertexCount, color);
1631
+ } else {
1632
+ m_debugDraw.drawSolidPolygon(vertices, vertexCount, color);
1633
+ }
1634
+ }
1635
+ break;
1636
+ case EDGE: {
1637
+ EdgeShape edge = (EdgeShape) fixture.getShape();
1638
+ Transform.mulToOutUnsafe(xf, edge.m_vertex1, v1);
1639
+ Transform.mulToOutUnsafe(xf, edge.m_vertex2, v2);
1640
+ m_debugDraw.drawSegment(v1, v2, color);
1641
+ }
1642
+ break;
1643
+ case CHAIN: {
1644
+ ChainShape chain = (ChainShape) fixture.getShape();
1645
+ int count = chain.m_count;
1646
+ Vec2[] vertices = chain.m_vertices;
1647
+
1648
+ Transform.mulToOutUnsafe(xf, vertices[0], v1);
1649
+ for (int i = 1; i < count; ++i) {
1650
+ Transform.mulToOutUnsafe(xf, vertices[i], v2);
1651
+ m_debugDraw.drawSegment(v1, v2, color);
1652
+ m_debugDraw.drawCircle(v1, 0.05f, color);
1653
+ v1.set(v2);
1654
+ }
1655
+ }
1656
+ break;
1657
+ default:
1658
+ break;
1659
+ }
1660
+ }
1661
+
1662
+ private void drawParticleSystem(ParticleSystem system) {
1663
+ boolean wireframe = (m_debugDraw.getFlags() & DebugDraw.e_wireframeDrawingBit) != 0;
1664
+ int particleCount = system.getParticleCount();
1665
+ if (particleCount != 0) {
1666
+ float particleRadius = system.getParticleRadius();
1667
+ Vec2[] positionBuffer = system.getParticlePositionBuffer();
1668
+ ParticleColor[] colorBuffer = null;
1669
+ if (system.m_colorBuffer.data != null) {
1670
+ colorBuffer = system.getParticleColorBuffer();
1671
+ }
1672
+ if (wireframe) {
1673
+ m_debugDraw.drawParticlesWireframe(positionBuffer, particleRadius, colorBuffer,
1674
+ particleCount);
1675
+ } else {
1676
+ m_debugDraw.drawParticles(positionBuffer, particleRadius, colorBuffer, particleCount);
1677
+ }
1678
+ }
1679
+ }
1680
+
1681
+ /**
1682
+ * Create a particle whose properties have been defined. No reference to the
1683
+ * definition is retained. A simulation step must occur before it's possible
1684
+ * to interact with a newly created particle. For example,
1685
+ * DestroyParticleInShape() will not destroy a particle until Step() has
1686
+ * been called.
1687
+ *
1688
+ * @param def
1689
+ * @warning This function is locked during callbacks.
1690
+ * @return the index of the particle.
1691
+ */
1692
+ public int createParticle(ParticleDef def) {
1693
+ assert (isLocked() == false);
1694
+ if (isLocked()) {
1695
+ return 0;
1696
+ }
1697
+ int p = m_particleSystem.createParticle(def);
1698
+ return p;
1699
+ }
1700
+
1701
+ /**
1702
+ * Destroy a particle. The particle is removed after the next step.
1703
+ *
1704
+ * @param index
1705
+ */
1706
+ public void destroyParticle(int index) {
1707
+ destroyParticle(index, false);
1708
+ }
1709
+
1710
+ /**
1711
+ * Destroy a particle. The particle is removed after the next step.
1712
+ *
1713
+ * @param Index of the particle to destroy.
1714
+ * @param Whether to call the destruction listener just before the particle
1715
+ * is destroyed.
1716
+ */
1717
+ public void destroyParticle(int index, boolean callDestructionListener) {
1718
+ m_particleSystem.destroyParticle(index, callDestructionListener);
1719
+ }
1720
+
1721
+ /**
1722
+ * Destroy particles inside a shape without enabling the destruction
1723
+ * callback for destroyed particles. This function is locked during
1724
+ * callbacks. For more information see DestroyParticleInShape(Shape&,
1725
+ * Transform&,bool).
1726
+ *
1727
+ * @param Shape which encloses particles that should be destroyed.
1728
+ * @param Transform applied to the shape.
1729
+ * @warning This function is locked during callbacks.
1730
+ * @return Number of particles destroyed.
1731
+ */
1732
+ public int destroyParticlesInShape(Shape shape, Transform xf) {
1733
+ return destroyParticlesInShape(shape, xf, false);
1734
+ }
1735
+
1736
+ /**
1737
+ * Destroy particles inside a shape. This function is locked during
1738
+ * callbacks. In addition, this function immediately destroys particles in
1739
+ * the shape in contrast to DestroyParticle() which defers the destruction
1740
+ * until the next simulation step.
1741
+ *
1742
+ * @param shape Shape which encloses particles that should be destroyed.
1743
+ * @param xf Transform applied to the shape.
1744
+ * @param callDestructionListener boolean Whether to call the world
1745
+ * b2DestructionListener for each particle destroyed.
1746
+ * @warning This function is locked during callbacks.
1747
+ * @return Number of particles destroyed.
1748
+ */
1749
+ public int destroyParticlesInShape(Shape shape, Transform xf, boolean callDestructionListener) {
1750
+ assert (isLocked() == false);
1751
+ if (isLocked()) {
1752
+ return 0;
1753
+ }
1754
+ return m_particleSystem.destroyParticlesInShape(shape, xf, callDestructionListener);
1755
+ }
1756
+
1757
+ /**
1758
+ * Create a particle group whose properties have been defined. No reference
1759
+ * to the definition is retained.
1760
+ *
1761
+ * @param def
1762
+ * @return
1763
+ * @warning This function is locked during callbacks.
1764
+ */
1765
+ public ParticleGroup createParticleGroup(ParticleGroupDef def) {
1766
+ assert (isLocked() == false);
1767
+ if (isLocked()) {
1768
+ return null;
1769
+ }
1770
+ ParticleGroup g = m_particleSystem.createParticleGroup(def);
1771
+ return g;
1772
+ }
1773
+
1774
+ /**
1775
+ * Join two particle groups.
1776
+ *
1777
+ * @param groupA the first group. Expands to encompass the second group.
1778
+ * @param groupB the second group. It is destroyed.
1779
+ * @warning This function is locked during callbacks.
1780
+ */
1781
+ public void joinParticleGroups(ParticleGroup groupA, ParticleGroup groupB) {
1782
+ assert (isLocked() == false);
1783
+ if (isLocked()) {
1784
+ return;
1785
+ }
1786
+ m_particleSystem.joinParticleGroups(groupA, groupB);
1787
+ }
1788
+
1789
+ /**
1790
+ * Destroy particles in a group. This function is locked during callbacks.
1791
+ *
1792
+ * @param group
1793
+ * @param callDestructionListener
1794
+ * @warning This function is locked during callbacks.
1795
+ */
1796
+ public void destroyParticlesInGroup(ParticleGroup group, boolean callDestructionListener) {
1797
+ assert (isLocked() == false);
1798
+ if (isLocked()) {
1799
+ return;
1800
+ }
1801
+ m_particleSystem.destroyParticlesInGroup(group, callDestructionListener);
1802
+ }
1803
+
1804
+ /**
1805
+ * Destroy particles in a group without enabling the destruction callback
1806
+ * for destroyed particles. This function is locked during callbacks.
1807
+ *
1808
+ * @param group The particle group to destroy.
1809
+ * @warning This function is locked during callbacks.
1810
+ */
1811
+ public void destroyParticlesInGroup(ParticleGroup group) {
1812
+ destroyParticlesInGroup(group, false);
1813
+ }
1814
+
1815
+ /**
1816
+ * Get the world particle group list. With the returned group, use
1817
+ * ParticleGroup::GetNext to get the next group in the world list. A NULL
1818
+ * group indicates the end of the list.
1819
+ *
1820
+ * @return the head of the world particle group list.
1821
+ */
1822
+ public ParticleGroup[] getParticleGroupList() {
1823
+ return m_particleSystem.getParticleGroupList();
1824
+ }
1825
+
1826
+ /**
1827
+ * Get the number of particle groups.
1828
+ *
1829
+ * @return
1830
+ */
1831
+ public int getParticleGroupCount() {
1832
+ return m_particleSystem.getParticleGroupCount();
1833
+ }
1834
+
1835
+ /**
1836
+ * Get the number of particles.
1837
+ *
1838
+ * @return
1839
+ */
1840
+ public int getParticleCount() {
1841
+ return m_particleSystem.getParticleCount();
1842
+ }
1843
+
1844
+ /**
1845
+ * Get the maximum number of particles.
1846
+ *
1847
+ * @return
1848
+ */
1849
+ public int getParticleMaxCount() {
1850
+ return m_particleSystem.getParticleMaxCount();
1851
+ }
1852
+
1853
+ /**
1854
+ * Set the maximum number of particles.
1855
+ *
1856
+ * @param count
1857
+ */
1858
+ public void setParticleMaxCount(int count) {
1859
+ m_particleSystem.setParticleMaxCount(count);
1860
+ }
1861
+
1862
+ /**
1863
+ * Change the particle density.
1864
+ *
1865
+ * @param density
1866
+ */
1867
+ public void setParticleDensity(float density) {
1868
+ m_particleSystem.setParticleDensity(density);
1869
+ }
1870
+
1871
+ /**
1872
+ * Get the particle density.
1873
+ *
1874
+ * @return
1875
+ */
1876
+ public float getParticleDensity() {
1877
+ return m_particleSystem.getParticleDensity();
1878
+ }
1879
+
1880
+ /**
1881
+ * Change the particle gravity scale. Adjusts the effect of the global
1882
+ * gravity vector on particles. Default value is 1.0f.
1883
+ *
1884
+ * @param gravityScale
1885
+ */
1886
+ public void setParticleGravityScale(float gravityScale) {
1887
+ m_particleSystem.setParticleGravityScale(gravityScale);
1888
+
1889
+ }
1890
+
1891
+ /**
1892
+ * Get the particle gravity scale.
1893
+ *
1894
+ * @return
1895
+ */
1896
+ public float getParticleGravityScale() {
1897
+ return m_particleSystem.getParticleGravityScale();
1898
+ }
1899
+
1900
+ /**
1901
+ * Damping is used to reduce the velocity of particles. The damping
1902
+ * parameter can be larger than 1.0f but the damping effect becomes
1903
+ * sensitive to the time step when the damping parameter is large.
1904
+ *
1905
+ * @param damping
1906
+ */
1907
+ public void setParticleDamping(float damping) {
1908
+ m_particleSystem.setParticleDamping(damping);
1909
+ }
1910
+
1911
+ /**
1912
+ * Get damping for particles
1913
+ *
1914
+ * @return
1915
+ */
1916
+ public float getParticleDamping() {
1917
+ return m_particleSystem.getParticleDamping();
1918
+ }
1919
+
1920
+ /**
1921
+ * Change the particle radius. You should set this only once, on world
1922
+ * start. If you change the radius during execution, existing particles may
1923
+ * explode, shrink, or behave unexpectedly.
1924
+ *
1925
+ * @param radius
1926
+ */
1927
+ public void setParticleRadius(float radius) {
1928
+ m_particleSystem.setParticleRadius(radius);
1929
+ }
1930
+
1931
+ /**
1932
+ * Get the particle radius.
1933
+ *
1934
+ * @return
1935
+ */
1936
+ public float getParticleRadius() {
1937
+ return m_particleSystem.getParticleRadius();
1938
+ }
1939
+
1940
+ /**
1941
+ * Get the particle data. @return the pointer to the head of the particle
1942
+ * data.
1943
+ *
1944
+ * @return
1945
+ */
1946
+ public int[] getParticleFlagsBuffer() {
1947
+ return m_particleSystem.getParticleFlagsBuffer();
1948
+ }
1949
+
1950
+ public Vec2[] getParticlePositionBuffer() {
1951
+ return m_particleSystem.getParticlePositionBuffer();
1952
+ }
1953
+
1954
+ public Vec2[] getParticleVelocityBuffer() {
1955
+ return m_particleSystem.getParticleVelocityBuffer();
1956
+ }
1957
+
1958
+ public ParticleColor[] getParticleColorBuffer() {
1959
+ return m_particleSystem.getParticleColorBuffer();
1960
+ }
1961
+
1962
+ public ParticleGroup[] getParticleGroupBuffer() {
1963
+ return m_particleSystem.getParticleGroupBuffer();
1964
+ }
1965
+
1966
+ public Object[] getParticleUserDataBuffer() {
1967
+ return m_particleSystem.getParticleUserDataBuffer();
1968
+ }
1969
+
1970
+ /**
1971
+ * Set a buffer for particle data.
1972
+ *
1973
+ * @param buffer is a pointer to a block of memory.
1974
+ * @param capacity
1975
+ */
1976
+ public void setParticleFlagsBuffer(int[] buffer, int capacity) {
1977
+ m_particleSystem.setParticleFlagsBuffer(buffer, capacity);
1978
+ }
1979
+
1980
+ public void setParticlePositionBuffer(Vec2[] buffer, int capacity) {
1981
+ m_particleSystem.setParticlePositionBuffer(buffer, capacity);
1982
+
1983
+ }
1984
+
1985
+ public void setParticleVelocityBuffer(Vec2[] buffer, int capacity) {
1986
+ m_particleSystem.setParticleVelocityBuffer(buffer, capacity);
1987
+
1988
+ }
1989
+
1990
+ public void setParticleColorBuffer(ParticleColor[] buffer, int capacity) {
1991
+ m_particleSystem.setParticleColorBuffer(buffer, capacity);
1992
+
1993
+ }
1994
+
1995
+ public void setParticleUserDataBuffer(Object[] buffer, int capacity) {
1996
+ m_particleSystem.setParticleUserDataBuffer(buffer, capacity);
1997
+ }
1998
+
1999
+ /**
2000
+ * Get contacts between particles
2001
+ *
2002
+ * @return
2003
+ */
2004
+ public ParticleContact[] getParticleContacts() {
2005
+ return m_particleSystem.m_contactBuffer;
2006
+ }
2007
+
2008
+ public int getParticleContactCount() {
2009
+ return m_particleSystem.m_contactCount;
2010
+ }
2011
+
2012
+ /**
2013
+ * Get contacts between particles and bodies
2014
+ *
2015
+ * @return
2016
+ */
2017
+ public ParticleBodyContact[] getParticleBodyContacts() {
2018
+ return m_particleSystem.m_bodyContactBuffer;
2019
+ }
2020
+
2021
+ public int getParticleBodyContactCount() {
2022
+ return m_particleSystem.m_bodyContactCount;
2023
+ }
2024
+
2025
+ /**
2026
+ * Compute the kinetic energy that can be lost by damping force
2027
+ *
2028
+ * @return
2029
+ */
2030
+ public float computeParticleCollisionEnergy() {
2031
+ return m_particleSystem.computeParticleCollisionEnergy();
2032
+ }
2033
+ }
2034
+
2035
+ class WorldQueryWrapper implements TreeCallback {
2036
+
2037
+ @Override
2038
+ public boolean treeCallback(int nodeId) {
2039
+ FixtureProxy proxy = (FixtureProxy) broadPhase.getUserData(nodeId);
2040
+ return callback.reportFixture(proxy.fixture);
2041
+ }
2042
+
2043
+ BroadPhase broadPhase;
2044
+ QueryCallback callback;
2045
+ };
2046
+
2047
+ class WorldRayCastWrapper implements TreeRayCastCallback {
2048
+
2049
+ // djm pooling
2050
+ private final RayCastOutput output = new RayCastOutput();
2051
+ private final Vec2 temp = new Vec2();
2052
+ private final Vec2 point = new Vec2();
2053
+
2054
+ @Override
2055
+ public float raycastCallback(RayCastInput input, int nodeId) {
2056
+ Object userData = broadPhase.getUserData(nodeId);
2057
+ FixtureProxy proxy = (FixtureProxy) userData;
2058
+ Fixture fixture = proxy.fixture;
2059
+ int index = proxy.childIndex;
2060
+ boolean hit = fixture.raycast(output, input, index);
2061
+
2062
+ if (hit) {
2063
+ float fraction = output.fraction;
2064
+ // Vec2 point = (1.0f - fraction) * input.p1 + fraction * input.p2;
2065
+ temp.set(input.p2).mulLocal(fraction);
2066
+ point.set(input.p1).mulLocal(1 - fraction).addLocal(temp);
2067
+ return callback.reportFixture(fixture, point, output.normal, fraction);
2068
+ }
2069
+
2070
+ return input.maxFraction;
2071
+ }
2072
+
2073
+ BroadPhase broadPhase;
2074
+ RayCastCallback callback;
2075
+ };