pbox2d 0.6.0-java → 0.8.0-java

Sign up to get free protection for your applications and to get access to all the features.
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
+ };