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,2172 @@
1
+ package org.jbox2d.particle;
2
+
3
+ import java.lang.reflect.Array;
4
+ import java.util.Arrays;
5
+
6
+ import org.jbox2d.callbacks.ParticleDestructionListener;
7
+ import org.jbox2d.callbacks.ParticleQueryCallback;
8
+ import org.jbox2d.callbacks.ParticleRaycastCallback;
9
+ import org.jbox2d.callbacks.QueryCallback;
10
+ import org.jbox2d.collision.AABB;
11
+ import org.jbox2d.collision.RayCastInput;
12
+ import org.jbox2d.collision.RayCastOutput;
13
+ import org.jbox2d.collision.shapes.Shape;
14
+ import org.jbox2d.common.BufferUtils;
15
+ import org.jbox2d.common.MathUtils;
16
+ import org.jbox2d.common.Rot;
17
+ import org.jbox2d.common.Settings;
18
+ import org.jbox2d.common.Transform;
19
+ import org.jbox2d.common.Vec2;
20
+ import org.jbox2d.dynamics.Body;
21
+ import org.jbox2d.dynamics.Fixture;
22
+ import org.jbox2d.dynamics.TimeStep;
23
+ import org.jbox2d.dynamics.World;
24
+ import org.jbox2d.particle.VoronoiDiagram.VoronoiDiagramCallback;
25
+
26
+ public class ParticleSystem {
27
+ /** All particle types that require creating pairs */
28
+ private static final int k_pairFlags = ParticleType.b2_springParticle;
29
+ /** All particle types that require creating triads */
30
+ private static final int k_triadFlags = ParticleType.b2_elasticParticle;
31
+ /** All particle types that require computing depth */
32
+ private static final int k_noPressureFlags = ParticleType.b2_powderParticle;
33
+
34
+ static final int xTruncBits = 12;
35
+ static final int yTruncBits = 12;
36
+ static final int tagBits = 8 * 4 - 1 /* sizeof(int) */;
37
+ static final long yOffset = 1 << (yTruncBits - 1);
38
+ static final int yShift = tagBits - yTruncBits;
39
+ static final int xShift = tagBits - yTruncBits - xTruncBits;
40
+ static final long xScale = 1 << xShift;
41
+ static final long xOffset = xScale * (1 << (xTruncBits - 1));
42
+ static final int xMask = (1 << xTruncBits) - 1;
43
+ static final int yMask = (1 << yTruncBits) - 1;
44
+
45
+ static long computeTag(float x, float y) {
46
+ return (((long) (y + yOffset)) << yShift) + (((long) (xScale * x)) + xOffset);
47
+ }
48
+
49
+ static long computeRelativeTag(long tag, int x, int y) {
50
+ return tag + (y << yShift) + (x << xShift);
51
+ }
52
+
53
+ static int limitCapacity(int capacity, int maxCount) {
54
+ return maxCount != 0 && capacity > maxCount ? maxCount : capacity;
55
+ }
56
+
57
+ int m_timestamp;
58
+ int m_allParticleFlags;
59
+ int m_allGroupFlags;
60
+ float m_density;
61
+ float m_inverseDensity;
62
+ float m_gravityScale;
63
+ float m_particleDiameter;
64
+ float m_inverseDiameter;
65
+ float m_squaredDiameter;
66
+
67
+ int m_count;
68
+ int m_internalAllocatedCapacity;
69
+ int m_maxCount;
70
+ ParticleBufferInt m_flagsBuffer;
71
+ ParticleBuffer<Vec2> m_positionBuffer;
72
+ ParticleBuffer<Vec2> m_velocityBuffer;
73
+ float[] m_accumulationBuffer; // temporary values
74
+ Vec2[] m_accumulation2Buffer; // temporary vector values
75
+ float[] m_depthBuffer; // distance from the surface
76
+
77
+ public ParticleBuffer<ParticleColor> m_colorBuffer;
78
+ ParticleGroup[] m_groupBuffer;
79
+ ParticleBuffer<Object> m_userDataBuffer;
80
+
81
+ int m_proxyCount;
82
+ int m_proxyCapacity;
83
+ Proxy[] m_proxyBuffer;
84
+
85
+ public int m_contactCount;
86
+ int m_contactCapacity;
87
+ public ParticleContact[] m_contactBuffer;
88
+
89
+ public int m_bodyContactCount;
90
+ int m_bodyContactCapacity;
91
+ public ParticleBodyContact[] m_bodyContactBuffer;
92
+
93
+ int m_pairCount;
94
+ int m_pairCapacity;
95
+ Pair[] m_pairBuffer;
96
+
97
+ int m_triadCount;
98
+ int m_triadCapacity;
99
+ Triad[] m_triadBuffer;
100
+
101
+ int m_groupCount;
102
+ ParticleGroup m_groupList;
103
+
104
+ float m_pressureStrength;
105
+ float m_dampingStrength;
106
+ float m_elasticStrength;
107
+ float m_springStrength;
108
+ float m_viscousStrength;
109
+ float m_surfaceTensionStrengthA;
110
+ float m_surfaceTensionStrengthB;
111
+ float m_powderStrength;
112
+ float m_ejectionStrength;
113
+ float m_colorMixingStrength;
114
+
115
+ World m_world;
116
+
117
+ public ParticleSystem(World world) {
118
+ m_world = world;
119
+ m_timestamp = 0;
120
+ m_allParticleFlags = 0;
121
+ m_allGroupFlags = 0;
122
+ m_density = 1;
123
+ m_inverseDensity = 1;
124
+ m_gravityScale = 1;
125
+ m_particleDiameter = 1;
126
+ m_inverseDiameter = 1;
127
+ m_squaredDiameter = 1;
128
+
129
+ m_count = 0;
130
+ m_internalAllocatedCapacity = 0;
131
+ m_maxCount = 0;
132
+
133
+ m_proxyCount = 0;
134
+ m_proxyCapacity = 0;
135
+
136
+ m_contactCount = 0;
137
+ m_contactCapacity = 0;
138
+
139
+ m_bodyContactCount = 0;
140
+ m_bodyContactCapacity = 0;
141
+
142
+ m_pairCount = 0;
143
+ m_pairCapacity = 0;
144
+
145
+ m_triadCount = 0;
146
+ m_triadCapacity = 0;
147
+
148
+ m_groupCount = 0;
149
+
150
+ m_pressureStrength = 0.05f;
151
+ m_dampingStrength = 1.0f;
152
+ m_elasticStrength = 0.25f;
153
+ m_springStrength = 0.25f;
154
+ m_viscousStrength = 0.25f;
155
+ m_surfaceTensionStrengthA = 0.1f;
156
+ m_surfaceTensionStrengthB = 0.2f;
157
+ m_powderStrength = 0.5f;
158
+ m_ejectionStrength = 0.5f;
159
+ m_colorMixingStrength = 0.5f;
160
+
161
+ m_flagsBuffer = new ParticleBufferInt();
162
+ m_positionBuffer = new ParticleBuffer<Vec2>(Vec2.class);
163
+ m_velocityBuffer = new ParticleBuffer<Vec2>(Vec2.class);
164
+ m_colorBuffer = new ParticleBuffer<ParticleColor>(ParticleColor.class);
165
+ m_userDataBuffer = new ParticleBuffer<Object>(Object.class);
166
+ }
167
+
168
+ // public void assertNotSamePosition() {
169
+ // for (int i = 0; i < m_count; i++) {
170
+ // Vec2 vi = m_positionBuffer.data[i];
171
+ // for (int j = i + 1; j < m_count; j++) {
172
+ // Vec2 vj = m_positionBuffer.data[j];
173
+ // assert(vi.x != vj.x || vi.y != vj.y);
174
+ // }
175
+ // }
176
+ // }
177
+
178
+ public int createParticle(ParticleDef def) {
179
+ if (m_count >= m_internalAllocatedCapacity) {
180
+ int capacity = m_count != 0 ? 2 * m_count : Settings.minParticleBufferCapacity;
181
+ capacity = limitCapacity(capacity, m_maxCount);
182
+ capacity = limitCapacity(capacity, m_flagsBuffer.userSuppliedCapacity);
183
+ capacity = limitCapacity(capacity, m_positionBuffer.userSuppliedCapacity);
184
+ capacity = limitCapacity(capacity, m_velocityBuffer.userSuppliedCapacity);
185
+ capacity = limitCapacity(capacity, m_colorBuffer.userSuppliedCapacity);
186
+ capacity = limitCapacity(capacity, m_userDataBuffer.userSuppliedCapacity);
187
+ if (m_internalAllocatedCapacity < capacity) {
188
+ m_flagsBuffer.data =
189
+ reallocateBuffer(m_flagsBuffer, m_internalAllocatedCapacity, capacity, false);
190
+ m_positionBuffer.data =
191
+ reallocateBuffer(m_positionBuffer, m_internalAllocatedCapacity, capacity, false);
192
+ m_velocityBuffer.data =
193
+ reallocateBuffer(m_velocityBuffer, m_internalAllocatedCapacity, capacity, false);
194
+ m_accumulationBuffer =
195
+ BufferUtils.reallocateBuffer(m_accumulationBuffer, 0, m_internalAllocatedCapacity,
196
+ capacity, false);
197
+ m_accumulation2Buffer =
198
+ BufferUtils.reallocateBuffer(Vec2.class, m_accumulation2Buffer, 0,
199
+ m_internalAllocatedCapacity, capacity, true);
200
+ m_depthBuffer =
201
+ BufferUtils.reallocateBuffer(m_depthBuffer, 0, m_internalAllocatedCapacity, capacity,
202
+ true);
203
+ m_colorBuffer.data =
204
+ reallocateBuffer(m_colorBuffer, m_internalAllocatedCapacity, capacity, true);
205
+ m_groupBuffer =
206
+ BufferUtils.reallocateBuffer(ParticleGroup.class, m_groupBuffer, 0,
207
+ m_internalAllocatedCapacity, capacity, false);
208
+ m_userDataBuffer.data =
209
+ reallocateBuffer(m_userDataBuffer, m_internalAllocatedCapacity, capacity, true);
210
+ m_internalAllocatedCapacity = capacity;
211
+ }
212
+ }
213
+ if (m_count >= m_internalAllocatedCapacity) {
214
+ return Settings.invalidParticleIndex;
215
+ }
216
+ int index = m_count++;
217
+ m_flagsBuffer.data[index] = def.flags;
218
+ m_positionBuffer.data[index].set(def.position);
219
+ // assertNotSamePosition();
220
+ m_velocityBuffer.data[index].set(def.velocity);
221
+ m_groupBuffer[index] = null;
222
+ if (m_depthBuffer != null) {
223
+ m_depthBuffer[index] = 0;
224
+ }
225
+ if (m_colorBuffer.data != null || def.color != null) {
226
+ m_colorBuffer.data = requestParticleBuffer(m_colorBuffer.dataClass, m_colorBuffer.data);
227
+ m_colorBuffer.data[index].set(def.color);
228
+ }
229
+ if (m_userDataBuffer.data != null || def.userData != null) {
230
+ m_userDataBuffer.data =
231
+ requestParticleBuffer(m_userDataBuffer.dataClass, m_userDataBuffer.data);
232
+ m_userDataBuffer.data[index] = def.userData;
233
+ }
234
+ if (m_proxyCount >= m_proxyCapacity) {
235
+ int oldCapacity = m_proxyCapacity;
236
+ int newCapacity = m_proxyCount != 0 ? 2 * m_proxyCount : Settings.minParticleBufferCapacity;
237
+ m_proxyBuffer =
238
+ BufferUtils.reallocateBuffer(Proxy.class, m_proxyBuffer, oldCapacity, newCapacity);
239
+ m_proxyCapacity = newCapacity;
240
+ }
241
+ m_proxyBuffer[m_proxyCount++].index = index;
242
+ return index;
243
+ }
244
+
245
+ public void destroyParticle(int index, boolean callDestructionListener) {
246
+ int flags = ParticleType.b2_zombieParticle;
247
+ if (callDestructionListener) {
248
+ flags |= ParticleType.b2_destructionListener;
249
+ }
250
+ m_flagsBuffer.data[index] |= flags;
251
+ }
252
+
253
+ private final AABB temp = new AABB();
254
+ private final DestroyParticlesInShapeCallback dpcallback = new DestroyParticlesInShapeCallback();
255
+
256
+ public int destroyParticlesInShape(Shape shape, Transform xf, boolean callDestructionListener) {
257
+ dpcallback.init(this, shape, xf, callDestructionListener);
258
+ shape.computeAABB(temp, xf, 0);
259
+ m_world.queryAABB(dpcallback, temp);
260
+ return dpcallback.destroyed;
261
+ }
262
+
263
+ public void destroyParticlesInGroup(ParticleGroup group, boolean callDestructionListener) {
264
+ for (int i = group.m_firstIndex; i < group.m_lastIndex; i++) {
265
+ destroyParticle(i, callDestructionListener);
266
+ }
267
+ }
268
+
269
+ private final AABB temp2 = new AABB();
270
+ private final Vec2 tempVec = new Vec2();
271
+ private final Transform tempTransform = new Transform();
272
+ private final Transform tempTransform2 = new Transform();
273
+ private CreateParticleGroupCallback createParticleGroupCallback =
274
+ new CreateParticleGroupCallback();
275
+ private final ParticleDef tempParticleDef = new ParticleDef();
276
+
277
+ public ParticleGroup createParticleGroup(ParticleGroupDef groupDef) {
278
+ float stride = getParticleStride();
279
+ final Transform identity = tempTransform;
280
+ identity.setIdentity();
281
+ Transform transform = tempTransform2;
282
+ transform.setIdentity();
283
+ int firstIndex = m_count;
284
+ if (groupDef.shape != null) {
285
+ final ParticleDef particleDef = tempParticleDef;
286
+ particleDef.flags = groupDef.flags;
287
+ particleDef.color = groupDef.color;
288
+ particleDef.userData = groupDef.userData;
289
+ Shape shape = groupDef.shape;
290
+ transform.set(groupDef.position, groupDef.angle);
291
+ AABB aabb = temp;
292
+ int childCount = shape.getChildCount();
293
+ for (int childIndex = 0; childIndex < childCount; childIndex++) {
294
+ if (childIndex == 0) {
295
+ shape.computeAABB(aabb, identity, childIndex);
296
+ } else {
297
+ AABB childAABB = temp2;
298
+ shape.computeAABB(childAABB, identity, childIndex);
299
+ aabb.combine(childAABB);
300
+ }
301
+ }
302
+ final float upperBoundY = aabb.upperBound.y;
303
+ final float upperBoundX = aabb.upperBound.x;
304
+ for (float y = MathUtils.floor(aabb.lowerBound.y / stride) * stride; y < upperBoundY; y +=
305
+ stride) {
306
+ for (float x = MathUtils.floor(aabb.lowerBound.x / stride) * stride; x < upperBoundX; x +=
307
+ stride) {
308
+ Vec2 p = tempVec;
309
+ p.x = x;
310
+ p.y = y;
311
+ if (shape.testPoint(identity, p)) {
312
+ Transform.mulToOut(transform, p, p);
313
+ particleDef.position.x = p.x;
314
+ particleDef.position.y = p.y;
315
+ p.subLocal(groupDef.position);
316
+ Vec2.crossToOutUnsafe(groupDef.angularVelocity, p, particleDef.velocity);
317
+ particleDef.velocity.addLocal(groupDef.linearVelocity);
318
+ createParticle(particleDef);
319
+ }
320
+ }
321
+ }
322
+ }
323
+ int lastIndex = m_count;
324
+
325
+ ParticleGroup group = new ParticleGroup();
326
+ group.m_system = this;
327
+ group.m_firstIndex = firstIndex;
328
+ group.m_lastIndex = lastIndex;
329
+ group.m_groupFlags = groupDef.groupFlags;
330
+ group.m_strength = groupDef.strength;
331
+ group.m_userData = groupDef.userData;
332
+ group.m_transform.set(transform);
333
+ group.m_destroyAutomatically = groupDef.destroyAutomatically;
334
+ group.m_prev = null;
335
+ group.m_next = m_groupList;
336
+ if (m_groupList != null) {
337
+ m_groupList.m_prev = group;
338
+ }
339
+ m_groupList = group;
340
+ ++m_groupCount;
341
+ for (int i = firstIndex; i < lastIndex; i++) {
342
+ m_groupBuffer[i] = group;
343
+ }
344
+
345
+ updateContacts(true);
346
+ if ((groupDef.flags & k_pairFlags) != 0) {
347
+ for (int k = 0; k < m_contactCount; k++) {
348
+ ParticleContact contact = m_contactBuffer[k];
349
+ int a = contact.indexA;
350
+ int b = contact.indexB;
351
+ if (a > b) {
352
+ int temp = a;
353
+ a = b;
354
+ b = temp;
355
+ }
356
+ if (firstIndex <= a && b < lastIndex) {
357
+ if (m_pairCount >= m_pairCapacity) {
358
+ int oldCapacity = m_pairCapacity;
359
+ int newCapacity =
360
+ m_pairCount != 0 ? 2 * m_pairCount : Settings.minParticleBufferCapacity;
361
+ m_pairBuffer =
362
+ BufferUtils.reallocateBuffer(Pair.class, m_pairBuffer, oldCapacity, newCapacity);
363
+ m_pairCapacity = newCapacity;
364
+ }
365
+ Pair pair = m_pairBuffer[m_pairCount];
366
+ pair.indexA = a;
367
+ pair.indexB = b;
368
+ pair.flags = contact.flags;
369
+ pair.strength = groupDef.strength;
370
+ pair.distance = MathUtils.distance(m_positionBuffer.data[a], m_positionBuffer.data[b]);
371
+ m_pairCount++;
372
+ }
373
+ }
374
+ }
375
+ if ((groupDef.flags & k_triadFlags) != 0) {
376
+ VoronoiDiagram diagram = new VoronoiDiagram(lastIndex - firstIndex);
377
+ for (int i = firstIndex; i < lastIndex; i++) {
378
+ diagram.addGenerator(m_positionBuffer.data[i], i);
379
+ }
380
+ diagram.generate(stride / 2);
381
+ createParticleGroupCallback.system = this;
382
+ createParticleGroupCallback.def = groupDef;
383
+ createParticleGroupCallback.firstIndex = firstIndex;
384
+ diagram.getNodes(createParticleGroupCallback);
385
+ }
386
+ if ((groupDef.groupFlags & ParticleGroupType.b2_solidParticleGroup) != 0) {
387
+ computeDepthForGroup(group);
388
+ }
389
+
390
+ return group;
391
+ }
392
+
393
+ public void joinParticleGroups(ParticleGroup groupA, ParticleGroup groupB) {
394
+ assert (groupA != groupB);
395
+ RotateBuffer(groupB.m_firstIndex, groupB.m_lastIndex, m_count);
396
+ assert (groupB.m_lastIndex == m_count);
397
+ RotateBuffer(groupA.m_firstIndex, groupA.m_lastIndex, groupB.m_firstIndex);
398
+ assert (groupA.m_lastIndex == groupB.m_firstIndex);
399
+
400
+ int particleFlags = 0;
401
+ for (int i = groupA.m_firstIndex; i < groupB.m_lastIndex; i++) {
402
+ particleFlags |= m_flagsBuffer.data[i];
403
+ }
404
+
405
+ updateContacts(true);
406
+ if ((particleFlags & k_pairFlags) != 0) {
407
+ for (int k = 0; k < m_contactCount; k++) {
408
+ final ParticleContact contact = m_contactBuffer[k];
409
+ int a = contact.indexA;
410
+ int b = contact.indexB;
411
+ if (a > b) {
412
+ int temp = a;
413
+ a = b;
414
+ b = temp;
415
+ }
416
+ if (groupA.m_firstIndex <= a && a < groupA.m_lastIndex && groupB.m_firstIndex <= b
417
+ && b < groupB.m_lastIndex) {
418
+ if (m_pairCount >= m_pairCapacity) {
419
+ int oldCapacity = m_pairCapacity;
420
+ int newCapacity =
421
+ m_pairCount != 0 ? 2 * m_pairCount : Settings.minParticleBufferCapacity;
422
+ m_pairBuffer =
423
+ BufferUtils.reallocateBuffer(Pair.class, m_pairBuffer, oldCapacity, newCapacity);
424
+ m_pairCapacity = newCapacity;
425
+ }
426
+ Pair pair = m_pairBuffer[m_pairCount];
427
+ pair.indexA = a;
428
+ pair.indexB = b;
429
+ pair.flags = contact.flags;
430
+ pair.strength = MathUtils.min(groupA.m_strength, groupB.m_strength);
431
+ pair.distance = MathUtils.distance(m_positionBuffer.data[a], m_positionBuffer.data[b]);
432
+ m_pairCount++;
433
+ }
434
+ }
435
+ }
436
+ if ((particleFlags & k_triadFlags) != 0) {
437
+ VoronoiDiagram diagram = new VoronoiDiagram(groupB.m_lastIndex - groupA.m_firstIndex);
438
+ for (int i = groupA.m_firstIndex; i < groupB.m_lastIndex; i++) {
439
+ if ((m_flagsBuffer.data[i] & ParticleType.b2_zombieParticle) == 0) {
440
+ diagram.addGenerator(m_positionBuffer.data[i], i);
441
+ }
442
+ }
443
+ diagram.generate(getParticleStride() / 2);
444
+ JoinParticleGroupsCallback callback = new JoinParticleGroupsCallback();
445
+ callback.system = this;
446
+ callback.groupA = groupA;
447
+ callback.groupB = groupB;
448
+ diagram.getNodes(callback);
449
+ }
450
+
451
+ for (int i = groupB.m_firstIndex; i < groupB.m_lastIndex; i++) {
452
+ m_groupBuffer[i] = groupA;
453
+ }
454
+ int groupFlags = groupA.m_groupFlags | groupB.m_groupFlags;
455
+ groupA.m_groupFlags = groupFlags;
456
+ groupA.m_lastIndex = groupB.m_lastIndex;
457
+ groupB.m_firstIndex = groupB.m_lastIndex;
458
+ destroyParticleGroup(groupB);
459
+
460
+ if ((groupFlags & ParticleGroupType.b2_solidParticleGroup) != 0) {
461
+ computeDepthForGroup(groupA);
462
+ }
463
+ }
464
+
465
+ // Only called from solveZombie() or joinParticleGroups().
466
+ void destroyParticleGroup(ParticleGroup group) {
467
+ assert (m_groupCount > 0);
468
+ assert (group != null);
469
+
470
+ if (m_world.getParticleDestructionListener() != null) {
471
+ m_world.getParticleDestructionListener().sayGoodbye(group);
472
+ }
473
+
474
+ for (int i = group.m_firstIndex; i < group.m_lastIndex; i++) {
475
+ m_groupBuffer[i] = null;
476
+ }
477
+
478
+ if (group.m_prev != null) {
479
+ group.m_prev.m_next = group.m_next;
480
+ }
481
+ if (group.m_next != null) {
482
+ group.m_next.m_prev = group.m_prev;
483
+ }
484
+ if (group == m_groupList) {
485
+ m_groupList = group.m_next;
486
+ }
487
+
488
+ --m_groupCount;
489
+ }
490
+
491
+ public void computeDepthForGroup(ParticleGroup group) {
492
+ for (int i = group.m_firstIndex; i < group.m_lastIndex; i++) {
493
+ m_accumulationBuffer[i] = 0;
494
+ }
495
+ for (int k = 0; k < m_contactCount; k++) {
496
+ final ParticleContact contact = m_contactBuffer[k];
497
+ int a = contact.indexA;
498
+ int b = contact.indexB;
499
+ if (a >= group.m_firstIndex && a < group.m_lastIndex && b >= group.m_firstIndex
500
+ && b < group.m_lastIndex) {
501
+ float w = contact.weight;
502
+ m_accumulationBuffer[a] += w;
503
+ m_accumulationBuffer[b] += w;
504
+ }
505
+ }
506
+ m_depthBuffer = requestParticleBuffer(m_depthBuffer);
507
+ for (int i = group.m_firstIndex; i < group.m_lastIndex; i++) {
508
+ float w = m_accumulationBuffer[i];
509
+ m_depthBuffer[i] = w < 0.8f ? 0 : Float.MAX_VALUE;
510
+ }
511
+ int interationCount = group.getParticleCount();
512
+ for (int t = 0; t < interationCount; t++) {
513
+ boolean updated = false;
514
+ for (int k = 0; k < m_contactCount; k++) {
515
+ final ParticleContact contact = m_contactBuffer[k];
516
+ int a = contact.indexA;
517
+ int b = contact.indexB;
518
+ if (a >= group.m_firstIndex && a < group.m_lastIndex && b >= group.m_firstIndex
519
+ && b < group.m_lastIndex) {
520
+ float r = 1 - contact.weight;
521
+ float ap0 = m_depthBuffer[a];
522
+ float bp0 = m_depthBuffer[b];
523
+ float ap1 = bp0 + r;
524
+ float bp1 = ap0 + r;
525
+ if (ap0 > ap1) {
526
+ m_depthBuffer[a] = ap1;
527
+ updated = true;
528
+ }
529
+ if (bp0 > bp1) {
530
+ m_depthBuffer[b] = bp1;
531
+ updated = true;
532
+ }
533
+ }
534
+ }
535
+ if (!updated) {
536
+ break;
537
+ }
538
+ }
539
+ for (int i = group.m_firstIndex; i < group.m_lastIndex; i++) {
540
+ float p = m_depthBuffer[i];
541
+ if (p < Float.MAX_VALUE) {
542
+ m_depthBuffer[i] *= m_particleDiameter;
543
+ } else {
544
+ m_depthBuffer[i] = 0;
545
+ }
546
+ }
547
+ }
548
+
549
+ public void addContact(int a, int b) {
550
+ assert(a != b);
551
+ Vec2 pa = m_positionBuffer.data[a];
552
+ Vec2 pb = m_positionBuffer.data[b];
553
+ float dx = pb.x - pa.x;
554
+ float dy = pb.y - pa.y;
555
+ float d2 = dx * dx + dy * dy;
556
+ // assert(d2 != 0);
557
+ if (d2 < m_squaredDiameter) {
558
+ if (m_contactCount >= m_contactCapacity) {
559
+ int oldCapacity = m_contactCapacity;
560
+ int newCapacity =
561
+ m_contactCount != 0 ? 2 * m_contactCount : Settings.minParticleBufferCapacity;
562
+ m_contactBuffer =
563
+ BufferUtils.reallocateBuffer(ParticleContact.class, m_contactBuffer, oldCapacity,
564
+ newCapacity);
565
+ m_contactCapacity = newCapacity;
566
+ }
567
+ float invD = d2 != 0 ? MathUtils.sqrt(1 / d2) : Float.MAX_VALUE;
568
+ ParticleContact contact = m_contactBuffer[m_contactCount];
569
+ contact.indexA = a;
570
+ contact.indexB = b;
571
+ contact.flags = m_flagsBuffer.data[a] | m_flagsBuffer.data[b];
572
+ contact.weight = 1 - d2 * invD * m_inverseDiameter;
573
+ contact.normal.x = invD * dx;
574
+ contact.normal.y = invD * dy;
575
+ m_contactCount++;
576
+ }
577
+ }
578
+
579
+ public void updateContacts(boolean exceptZombie) {
580
+ for (int p = 0; p < m_proxyCount; p++) {
581
+ Proxy proxy = m_proxyBuffer[p];
582
+ int i = proxy.index;
583
+ Vec2 pos = m_positionBuffer.data[i];
584
+ proxy.tag = computeTag(m_inverseDiameter * pos.x, m_inverseDiameter * pos.y);
585
+ }
586
+ Arrays.sort(m_proxyBuffer, 0, m_proxyCount);
587
+ m_contactCount = 0;
588
+ int c_index = 0;
589
+ for (int i = 0; i < m_proxyCount; i++) {
590
+ Proxy a = m_proxyBuffer[i];
591
+ long rightTag = computeRelativeTag(a.tag, 1, 0);
592
+ for (int j = i + 1; j < m_proxyCount; j++) {
593
+ Proxy b = m_proxyBuffer[j];
594
+ if (rightTag < b.tag) {
595
+ break;
596
+ }
597
+ addContact(a.index, b.index);
598
+ }
599
+ long bottomLeftTag = computeRelativeTag(a.tag, -1, 1);
600
+ for (; c_index < m_proxyCount; c_index++) {
601
+ Proxy c = m_proxyBuffer[c_index];
602
+ if (bottomLeftTag <= c.tag) {
603
+ break;
604
+ }
605
+ }
606
+ long bottomRightTag = computeRelativeTag(a.tag, 1, 1);
607
+
608
+ for (int b_index = c_index; b_index < m_proxyCount; b_index++) {
609
+ Proxy b = m_proxyBuffer[b_index];
610
+ if (bottomRightTag < b.tag) {
611
+ break;
612
+ }
613
+ addContact(a.index, b.index);
614
+ }
615
+ }
616
+ if (exceptZombie) {
617
+ int j = m_contactCount;
618
+ for (int i = 0; i < j; i++) {
619
+ if ((m_contactBuffer[i].flags & ParticleType.b2_zombieParticle) != 0) {
620
+ --j;
621
+ ParticleContact temp = m_contactBuffer[j];
622
+ m_contactBuffer[j] = m_contactBuffer[i];
623
+ m_contactBuffer[i] = temp;
624
+ --i;
625
+ }
626
+ }
627
+ m_contactCount = j;
628
+ }
629
+ }
630
+
631
+ private final UpdateBodyContactsCallback ubccallback = new UpdateBodyContactsCallback();
632
+
633
+ public void updateBodyContacts() {
634
+ final AABB aabb = temp;
635
+ aabb.lowerBound.x = Float.MAX_VALUE;
636
+ aabb.lowerBound.y = Float.MAX_VALUE;
637
+ aabb.upperBound.x = -Float.MAX_VALUE;
638
+ aabb.upperBound.y = -Float.MAX_VALUE;
639
+ for (int i = 0; i < m_count; i++) {
640
+ Vec2 p = m_positionBuffer.data[i];
641
+ Vec2.minToOut(aabb.lowerBound, p, aabb.lowerBound);
642
+ Vec2.maxToOut(aabb.upperBound, p, aabb.upperBound);
643
+ }
644
+ aabb.lowerBound.x -= m_particleDiameter;
645
+ aabb.lowerBound.y -= m_particleDiameter;
646
+ aabb.upperBound.x += m_particleDiameter;
647
+ aabb.upperBound.y += m_particleDiameter;
648
+ m_bodyContactCount = 0;
649
+
650
+ ubccallback.system = this;
651
+ m_world.queryAABB(ubccallback, aabb);
652
+ }
653
+
654
+ private SolveCollisionCallback sccallback = new SolveCollisionCallback();
655
+
656
+ public void solveCollision(TimeStep step) {
657
+ final AABB aabb = temp;
658
+ final Vec2 lowerBound = aabb.lowerBound;
659
+ final Vec2 upperBound = aabb.upperBound;
660
+ lowerBound.x = Float.MAX_VALUE;
661
+ lowerBound.y = Float.MAX_VALUE;
662
+ upperBound.x = -Float.MAX_VALUE;
663
+ upperBound.y = -Float.MAX_VALUE;
664
+ for (int i = 0; i < m_count; i++) {
665
+ final Vec2 v = m_velocityBuffer.data[i];
666
+ final Vec2 p1 = m_positionBuffer.data[i];
667
+ final float p1x = p1.x;
668
+ final float p1y = p1.y;
669
+ final float p2x = p1x + step.dt * v.x;
670
+ final float p2y = p1y + step.dt * v.y;
671
+ final float bx = p1x < p2x ? p1x : p2x;
672
+ final float by = p1y < p2y ? p1y : p2y;
673
+ lowerBound.x = lowerBound.x < bx ? lowerBound.x : bx;
674
+ lowerBound.y = lowerBound.y < by ? lowerBound.y : by;
675
+ final float b1x = p1x > p2x ? p1x : p2x;
676
+ final float b1y = p1y > p2y ? p1y : p2y;
677
+ upperBound.x = upperBound.x > b1x ? upperBound.x : b1x;
678
+ upperBound.y = upperBound.y > b1y ? upperBound.y : b1y;
679
+ }
680
+ sccallback.step = step;
681
+ sccallback.system = this;
682
+ m_world.queryAABB(sccallback, aabb);
683
+ }
684
+
685
+ public void solve(TimeStep step) {
686
+ ++m_timestamp;
687
+ if (m_count == 0) {
688
+ return;
689
+ }
690
+ m_allParticleFlags = 0;
691
+ for (int i = 0; i < m_count; i++) {
692
+ m_allParticleFlags |= m_flagsBuffer.data[i];
693
+ }
694
+ if ((m_allParticleFlags & ParticleType.b2_zombieParticle) != 0) {
695
+ solveZombie();
696
+ }
697
+ if (m_count == 0) {
698
+ return;
699
+ }
700
+ m_allGroupFlags = 0;
701
+ for (ParticleGroup group = m_groupList; group != null; group = group.getNext()) {
702
+ m_allGroupFlags |= group.m_groupFlags;
703
+ }
704
+ final float gravityx = step.dt * m_gravityScale * m_world.getGravity().x;
705
+ final float gravityy = step.dt * m_gravityScale * m_world.getGravity().y;
706
+ float criticalVelocytySquared = getCriticalVelocitySquared(step);
707
+ for (int i = 0; i < m_count; i++) {
708
+ Vec2 v = m_velocityBuffer.data[i];
709
+ v.x += gravityx;
710
+ v.y += gravityy;
711
+ float v2 = v.x * v.x + v.y * v.y;
712
+ if (v2 > criticalVelocytySquared) {
713
+ float a = v2 == 0 ? Float.MAX_VALUE : MathUtils.sqrt(criticalVelocytySquared / v2);
714
+ v.x *= a;
715
+ v.y *= a;
716
+ }
717
+ }
718
+ solveCollision(step);
719
+ if ((m_allGroupFlags & ParticleGroupType.b2_rigidParticleGroup) != 0) {
720
+ solveRigid(step);
721
+ }
722
+ if ((m_allParticleFlags & ParticleType.b2_wallParticle) != 0) {
723
+ solveWall(step);
724
+ }
725
+ for (int i = 0; i < m_count; i++) {
726
+ Vec2 pos = m_positionBuffer.data[i];
727
+ Vec2 vel = m_velocityBuffer.data[i];
728
+ pos.x += step.dt * vel.x;
729
+ pos.y += step.dt * vel.y;
730
+ }
731
+ updateBodyContacts();
732
+ updateContacts(false);
733
+ if ((m_allParticleFlags & ParticleType.b2_viscousParticle) != 0) {
734
+ solveViscous(step);
735
+ }
736
+ if ((m_allParticleFlags & ParticleType.b2_powderParticle) != 0) {
737
+ solvePowder(step);
738
+ }
739
+ if ((m_allParticleFlags & ParticleType.b2_tensileParticle) != 0) {
740
+ solveTensile(step);
741
+ }
742
+ if ((m_allParticleFlags & ParticleType.b2_elasticParticle) != 0) {
743
+ solveElastic(step);
744
+ }
745
+ if ((m_allParticleFlags & ParticleType.b2_springParticle) != 0) {
746
+ solveSpring(step);
747
+ }
748
+ if ((m_allGroupFlags & ParticleGroupType.b2_solidParticleGroup) != 0) {
749
+ solveSolid(step);
750
+ }
751
+ if ((m_allParticleFlags & ParticleType.b2_colorMixingParticle) != 0) {
752
+ solveColorMixing(step);
753
+ }
754
+ solvePressure(step);
755
+ solveDamping(step);
756
+ }
757
+
758
+ void solvePressure(TimeStep step) {
759
+ // calculates the sum of contact-weights for each particle
760
+ // that means dimensionless density
761
+ for (int i = 0; i < m_count; i++) {
762
+ m_accumulationBuffer[i] = 0;
763
+ }
764
+ for (int k = 0; k < m_bodyContactCount; k++) {
765
+ ParticleBodyContact contact = m_bodyContactBuffer[k];
766
+ int a = contact.index;
767
+ float w = contact.weight;
768
+ m_accumulationBuffer[a] += w;
769
+ }
770
+ for (int k = 0; k < m_contactCount; k++) {
771
+ ParticleContact contact = m_contactBuffer[k];
772
+ int a = contact.indexA;
773
+ int b = contact.indexB;
774
+ float w = contact.weight;
775
+ m_accumulationBuffer[a] += w;
776
+ m_accumulationBuffer[b] += w;
777
+ }
778
+ // ignores powder particles
779
+ if ((m_allParticleFlags & k_noPressureFlags) != 0) {
780
+ for (int i = 0; i < m_count; i++) {
781
+ if ((m_flagsBuffer.data[i] & k_noPressureFlags) != 0) {
782
+ m_accumulationBuffer[i] = 0;
783
+ }
784
+ }
785
+ }
786
+ // calculates pressure as a linear function of density
787
+ float pressurePerWeight = m_pressureStrength * getCriticalPressure(step);
788
+ for (int i = 0; i < m_count; i++) {
789
+ float w = m_accumulationBuffer[i];
790
+ float h =
791
+ pressurePerWeight
792
+ * MathUtils.max(0.0f, MathUtils.min(w, Settings.maxParticleWeight)
793
+ - Settings.minParticleWeight);
794
+ m_accumulationBuffer[i] = h;
795
+ }
796
+ // applies pressure between each particles in contact
797
+ float velocityPerPressure = step.dt / (m_density * m_particleDiameter);
798
+ for (int k = 0; k < m_bodyContactCount; k++) {
799
+ ParticleBodyContact contact = m_bodyContactBuffer[k];
800
+ int a = contact.index;
801
+ Body b = contact.body;
802
+ float w = contact.weight;
803
+ float m = contact.mass;
804
+ Vec2 n = contact.normal;
805
+ Vec2 p = m_positionBuffer.data[a];
806
+ float h = m_accumulationBuffer[a] + pressurePerWeight * w;
807
+ final Vec2 f = tempVec;
808
+ final float coef = velocityPerPressure * w * m * h;
809
+ f.x = coef * n.x;
810
+ f.y = coef * n.y;
811
+ final Vec2 velData = m_velocityBuffer.data[a];
812
+ final float particleInvMass = getParticleInvMass();
813
+ velData.x -= particleInvMass * f.x;
814
+ velData.y -= particleInvMass * f.y;
815
+ b.applyLinearImpulse(f, p, true);
816
+ }
817
+ for (int k = 0; k < m_contactCount; k++) {
818
+ ParticleContact contact = m_contactBuffer[k];
819
+ int a = contact.indexA;
820
+ int b = contact.indexB;
821
+ float w = contact.weight;
822
+ Vec2 n = contact.normal;
823
+ float h = m_accumulationBuffer[a] + m_accumulationBuffer[b];
824
+ final float fx = velocityPerPressure * w * h * n.x;
825
+ final float fy = velocityPerPressure * w * h * n.y;
826
+ final Vec2 velDataA = m_velocityBuffer.data[a];
827
+ final Vec2 velDataB = m_velocityBuffer.data[b];
828
+ velDataA.x -= fx;
829
+ velDataA.y -= fy;
830
+ velDataB.x += fx;
831
+ velDataB.y += fy;
832
+ }
833
+ }
834
+
835
+ void solveDamping(TimeStep step) {
836
+ // reduces normal velocity of each contact
837
+ float damping = m_dampingStrength;
838
+ for (int k = 0; k < m_bodyContactCount; k++) {
839
+ final ParticleBodyContact contact = m_bodyContactBuffer[k];
840
+ int a = contact.index;
841
+ Body b = contact.body;
842
+ float w = contact.weight;
843
+ float m = contact.mass;
844
+ Vec2 n = contact.normal;
845
+ Vec2 p = m_positionBuffer.data[a];
846
+ final float tempX = p.x - b.m_sweep.c.x;
847
+ final float tempY = p.y - b.m_sweep.c.y;
848
+ final Vec2 velA = m_velocityBuffer.data[a];
849
+ // getLinearVelocityFromWorldPointToOut, with -= velA
850
+ float vx = -b.m_angularVelocity * tempY + b.m_linearVelocity.x - velA.x;
851
+ float vy = b.m_angularVelocity * tempX + b.m_linearVelocity.y - velA.y;
852
+ // done
853
+ float vn = vx * n.x + vy * n.y;
854
+ if (vn < 0) {
855
+ final Vec2 f = tempVec;
856
+ f.x = damping * w * m * vn * n.x;
857
+ f.y = damping * w * m * vn * n.y;
858
+ final float invMass = getParticleInvMass();
859
+ velA.x += invMass * f.x;
860
+ velA.y += invMass * f.y;
861
+ f.x = -f.x;
862
+ f.y = -f.y;
863
+ b.applyLinearImpulse(f, p, true);
864
+ }
865
+ }
866
+ for (int k = 0; k < m_contactCount; k++) {
867
+ final ParticleContact contact = m_contactBuffer[k];
868
+ int a = contact.indexA;
869
+ int b = contact.indexB;
870
+ float w = contact.weight;
871
+ Vec2 n = contact.normal;
872
+ final Vec2 velA = m_velocityBuffer.data[a];
873
+ final Vec2 velB = m_velocityBuffer.data[b];
874
+ final float vx = velB.x - velA.x;
875
+ final float vy = velB.y - velA.y;
876
+ float vn = vx * n.x + vy * n.y;
877
+ if (vn < 0) {
878
+ float fx = damping * w * vn * n.x;
879
+ float fy = damping * w * vn * n.y;
880
+ velA.x += fx;
881
+ velA.y += fy;
882
+ velB.x -= fx;
883
+ velB.y -= fy;
884
+ }
885
+ }
886
+ }
887
+
888
+ public void solveWall(TimeStep step) {
889
+ for (int i = 0; i < m_count; i++) {
890
+ if ((m_flagsBuffer.data[i] & ParticleType.b2_wallParticle) != 0) {
891
+ final Vec2 r = m_velocityBuffer.data[i];
892
+ r.x = 0.0f;
893
+ r.y = 0.0f;
894
+ }
895
+ }
896
+ }
897
+
898
+ private final Vec2 tempVec2 = new Vec2();
899
+ private final Rot tempRot = new Rot();
900
+ private final Transform tempXf = new Transform();
901
+ private final Transform tempXf2 = new Transform();
902
+
903
+ void solveRigid(final TimeStep step) {
904
+ for (ParticleGroup group = m_groupList; group != null; group = group.getNext()) {
905
+ if ((group.m_groupFlags & ParticleGroupType.b2_rigidParticleGroup) != 0) {
906
+ group.updateStatistics();
907
+ Vec2 temp = tempVec;
908
+ Vec2 cross = tempVec2;
909
+ Rot rotation = tempRot;
910
+ rotation.set(step.dt * group.m_angularVelocity);
911
+ Rot.mulToOutUnsafe(rotation, group.m_center, cross);
912
+ temp.set(group.m_linearVelocity).mulLocal(step.dt).addLocal(group.m_center).subLocal(cross);
913
+ tempXf.p.set(temp);
914
+ tempXf.q.set(rotation);
915
+ Transform.mulToOut(tempXf, group.m_transform, group.m_transform);
916
+ final Transform velocityTransform = tempXf2;
917
+ velocityTransform.p.x = step.inv_dt * tempXf.p.x;
918
+ velocityTransform.p.y = step.inv_dt * tempXf.p.y;
919
+ velocityTransform.q.s = step.inv_dt * tempXf.q.s;
920
+ velocityTransform.q.c = step.inv_dt * (tempXf.q.c - 1);
921
+ for (int i = group.m_firstIndex; i < group.m_lastIndex; i++) {
922
+ Transform.mulToOutUnsafe(velocityTransform, m_positionBuffer.data[i],
923
+ m_velocityBuffer.data[i]);
924
+ }
925
+ }
926
+ }
927
+ }
928
+
929
+ void solveElastic(final TimeStep step) {
930
+ float elasticStrength = step.inv_dt * m_elasticStrength;
931
+ for (int k = 0; k < m_triadCount; k++) {
932
+ final Triad triad = m_triadBuffer[k];
933
+ if ((triad.flags & ParticleType.b2_elasticParticle) != 0) {
934
+ int a = triad.indexA;
935
+ int b = triad.indexB;
936
+ int c = triad.indexC;
937
+ final Vec2 oa = triad.pa;
938
+ final Vec2 ob = triad.pb;
939
+ final Vec2 oc = triad.pc;
940
+ final Vec2 pa = m_positionBuffer.data[a];
941
+ final Vec2 pb = m_positionBuffer.data[b];
942
+ final Vec2 pc = m_positionBuffer.data[c];
943
+ final float px = 1f / 3 * (pa.x + pb.x + pc.x);
944
+ final float py = 1f / 3 * (pa.y + pb.y + pc.y);
945
+ float rs = Vec2.cross(oa, pa) + Vec2.cross(ob, pb) + Vec2.cross(oc, pc);
946
+ float rc = Vec2.dot(oa, pa) + Vec2.dot(ob, pb) + Vec2.dot(oc, pc);
947
+ float r2 = rs * rs + rc * rc;
948
+ float invR = r2 == 0 ? Float.MAX_VALUE : MathUtils.sqrt(1f / r2);
949
+ rs *= invR;
950
+ rc *= invR;
951
+ final float strength = elasticStrength * triad.strength;
952
+ final float roax = rc * oa.x - rs * oa.y;
953
+ final float roay = rs * oa.x + rc * oa.y;
954
+ final float robx = rc * ob.x - rs * ob.y;
955
+ final float roby = rs * ob.x + rc * ob.y;
956
+ final float rocx = rc * oc.x - rs * oc.y;
957
+ final float rocy = rs * oc.x + rc * oc.y;
958
+ final Vec2 va = m_velocityBuffer.data[a];
959
+ final Vec2 vb = m_velocityBuffer.data[b];
960
+ final Vec2 vc = m_velocityBuffer.data[c];
961
+ va.x += strength * (roax - (pa.x - px));
962
+ va.y += strength * (roay - (pa.y - py));
963
+ vb.x += strength * (robx - (pb.x - px));
964
+ vb.y += strength * (roby - (pb.y - py));
965
+ vc.x += strength * (rocx - (pc.x - px));
966
+ vc.y += strength * (rocy - (pc.y - py));
967
+ }
968
+ }
969
+ }
970
+
971
+ void solveSpring(final TimeStep step) {
972
+ float springStrength = step.inv_dt * m_springStrength;
973
+ for (int k = 0; k < m_pairCount; k++) {
974
+ final Pair pair = m_pairBuffer[k];
975
+ if ((pair.flags & ParticleType.b2_springParticle) != 0) {
976
+ int a = pair.indexA;
977
+ int b = pair.indexB;
978
+ final Vec2 pa = m_positionBuffer.data[a];
979
+ final Vec2 pb = m_positionBuffer.data[b];
980
+ final float dx = pb.x - pa.x;
981
+ final float dy = pb.y - pa.y;
982
+ float r0 = pair.distance;
983
+ float r1 = MathUtils.sqrt(dx * dx + dy * dy);
984
+ if (r1 == 0) r1 = Float.MAX_VALUE;
985
+ float strength = springStrength * pair.strength;
986
+ final float fx = strength * (r0 - r1) / r1 * dx;
987
+ final float fy = strength * (r0 - r1) / r1 * dy;
988
+ final Vec2 va = m_velocityBuffer.data[a];
989
+ final Vec2 vb = m_velocityBuffer.data[b];
990
+ va.x -= fx;
991
+ va.y -= fy;
992
+ vb.x += fx;
993
+ vb.y += fy;
994
+ }
995
+ }
996
+ }
997
+
998
+ void solveTensile(final TimeStep step) {
999
+ m_accumulation2Buffer = requestParticleBuffer(Vec2.class, m_accumulation2Buffer);
1000
+ for (int i = 0; i < m_count; i++) {
1001
+ m_accumulationBuffer[i] = 0;
1002
+ m_accumulation2Buffer[i].setZero();
1003
+ }
1004
+ for (int k = 0; k < m_contactCount; k++) {
1005
+ final ParticleContact contact = m_contactBuffer[k];
1006
+ if ((contact.flags & ParticleType.b2_tensileParticle) != 0) {
1007
+ int a = contact.indexA;
1008
+ int b = contact.indexB;
1009
+ float w = contact.weight;
1010
+ Vec2 n = contact.normal;
1011
+ m_accumulationBuffer[a] += w;
1012
+ m_accumulationBuffer[b] += w;
1013
+ final Vec2 a2A = m_accumulation2Buffer[a];
1014
+ final Vec2 a2B = m_accumulation2Buffer[b];
1015
+ final float inter = (1 - w) * w;
1016
+ a2A.x -= inter * n.x;
1017
+ a2A.y -= inter * n.y;
1018
+ a2B.x += inter * n.x;
1019
+ a2B.y += inter * n.y;
1020
+ }
1021
+ }
1022
+ float strengthA = m_surfaceTensionStrengthA * getCriticalVelocity(step);
1023
+ float strengthB = m_surfaceTensionStrengthB * getCriticalVelocity(step);
1024
+ for (int k = 0; k < m_contactCount; k++) {
1025
+ final ParticleContact contact = m_contactBuffer[k];
1026
+ if ((contact.flags & ParticleType.b2_tensileParticle) != 0) {
1027
+ int a = contact.indexA;
1028
+ int b = contact.indexB;
1029
+ float w = contact.weight;
1030
+ Vec2 n = contact.normal;
1031
+ final Vec2 a2A = m_accumulation2Buffer[a];
1032
+ final Vec2 a2B = m_accumulation2Buffer[b];
1033
+ float h = m_accumulationBuffer[a] + m_accumulationBuffer[b];
1034
+ final float sx = a2B.x - a2A.x;
1035
+ final float sy = a2B.y - a2A.y;
1036
+ float fn = (strengthA * (h - 2) + strengthB * (sx * n.x + sy * n.y)) * w;
1037
+ final float fx = fn * n.x;
1038
+ final float fy = fn * n.y;
1039
+ final Vec2 va = m_velocityBuffer.data[a];
1040
+ final Vec2 vb = m_velocityBuffer.data[b];
1041
+ va.x -= fx;
1042
+ va.y -= fy;
1043
+ vb.x += fx;
1044
+ vb.y += fy;
1045
+ }
1046
+ }
1047
+ }
1048
+
1049
+ void solveViscous(final TimeStep step) {
1050
+ float viscousStrength = m_viscousStrength;
1051
+ for (int k = 0; k < m_bodyContactCount; k++) {
1052
+ final ParticleBodyContact contact = m_bodyContactBuffer[k];
1053
+ int a = contact.index;
1054
+ if ((m_flagsBuffer.data[a] & ParticleType.b2_viscousParticle) != 0) {
1055
+ Body b = contact.body;
1056
+ float w = contact.weight;
1057
+ float m = contact.mass;
1058
+ Vec2 p = m_positionBuffer.data[a];
1059
+ final Vec2 va = m_velocityBuffer.data[a];
1060
+ final float tempX = p.x - b.m_sweep.c.x;
1061
+ final float tempY = p.y - b.m_sweep.c.y;
1062
+ final float vx = -b.m_angularVelocity * tempY + b.m_linearVelocity.x - va.x;
1063
+ final float vy = b.m_angularVelocity * tempX + b.m_linearVelocity.y - va.y;
1064
+ final Vec2 f = tempVec;
1065
+ final float pInvMass = getParticleInvMass();
1066
+ f.x = viscousStrength * m * w * vx;
1067
+ f.y = viscousStrength * m * w * vy;
1068
+ va.x += pInvMass * f.x;
1069
+ va.y += pInvMass * f.y;
1070
+ f.x = -f.x;
1071
+ f.y = -f.y;
1072
+ b.applyLinearImpulse(f, p, true);
1073
+ }
1074
+ }
1075
+ for (int k = 0; k < m_contactCount; k++) {
1076
+ final ParticleContact contact = m_contactBuffer[k];
1077
+ if ((contact.flags & ParticleType.b2_viscousParticle) != 0) {
1078
+ int a = contact.indexA;
1079
+ int b = contact.indexB;
1080
+ float w = contact.weight;
1081
+ final Vec2 va = m_velocityBuffer.data[a];
1082
+ final Vec2 vb = m_velocityBuffer.data[b];
1083
+ final float vx = vb.x - va.x;
1084
+ final float vy = vb.y - va.y;
1085
+ final float fx = viscousStrength * w * vx;
1086
+ final float fy = viscousStrength * w * vy;
1087
+ va.x += fx;
1088
+ va.y += fy;
1089
+ vb.x -= fx;
1090
+ vb.y -= fy;
1091
+ }
1092
+ }
1093
+ }
1094
+
1095
+ void solvePowder(final TimeStep step) {
1096
+ float powderStrength = m_powderStrength * getCriticalVelocity(step);
1097
+ float minWeight = 1.0f - Settings.particleStride;
1098
+ for (int k = 0; k < m_bodyContactCount; k++) {
1099
+ final ParticleBodyContact contact = m_bodyContactBuffer[k];
1100
+ int a = contact.index;
1101
+ if ((m_flagsBuffer.data[a] & ParticleType.b2_powderParticle) != 0) {
1102
+ float w = contact.weight;
1103
+ if (w > minWeight) {
1104
+ Body b = contact.body;
1105
+ float m = contact.mass;
1106
+ Vec2 p = m_positionBuffer.data[a];
1107
+ Vec2 n = contact.normal;
1108
+ final Vec2 f = tempVec;
1109
+ final Vec2 va = m_velocityBuffer.data[a];
1110
+ final float inter = powderStrength * m * (w - minWeight);
1111
+ final float pInvMass = getParticleInvMass();
1112
+ f.x = inter * n.x;
1113
+ f.y = inter * n.y;
1114
+ va.x -= pInvMass * f.x;
1115
+ va.y -= pInvMass * f.y;
1116
+ b.applyLinearImpulse(f, p, true);
1117
+ }
1118
+ }
1119
+ }
1120
+ for (int k = 0; k < m_contactCount; k++) {
1121
+ final ParticleContact contact = m_contactBuffer[k];
1122
+ if ((contact.flags & ParticleType.b2_powderParticle) != 0) {
1123
+ float w = contact.weight;
1124
+ if (w > minWeight) {
1125
+ int a = contact.indexA;
1126
+ int b = contact.indexB;
1127
+ Vec2 n = contact.normal;
1128
+ final Vec2 va = m_velocityBuffer.data[a];
1129
+ final Vec2 vb = m_velocityBuffer.data[b];
1130
+ final float inter = powderStrength * (w - minWeight);
1131
+ final float fx = inter * n.x;
1132
+ final float fy = inter * n.y;
1133
+ va.x -= fx;
1134
+ va.y -= fy;
1135
+ vb.x += fx;
1136
+ vb.y += fy;
1137
+ }
1138
+ }
1139
+ }
1140
+ }
1141
+
1142
+ void solveSolid(final TimeStep step) {
1143
+ // applies extra repulsive force from solid particle groups
1144
+ m_depthBuffer = requestParticleBuffer(m_depthBuffer);
1145
+ float ejectionStrength = step.inv_dt * m_ejectionStrength;
1146
+ for (int k = 0; k < m_contactCount; k++) {
1147
+ final ParticleContact contact = m_contactBuffer[k];
1148
+ int a = contact.indexA;
1149
+ int b = contact.indexB;
1150
+ if (m_groupBuffer[a] != m_groupBuffer[b]) {
1151
+ float w = contact.weight;
1152
+ Vec2 n = contact.normal;
1153
+ float h = m_depthBuffer[a] + m_depthBuffer[b];
1154
+ final Vec2 va = m_velocityBuffer.data[a];
1155
+ final Vec2 vb = m_velocityBuffer.data[b];
1156
+ final float inter = ejectionStrength * h * w;
1157
+ final float fx = inter * n.x;
1158
+ final float fy = inter * n.y;
1159
+ va.x -= fx;
1160
+ va.y -= fy;
1161
+ vb.x += fx;
1162
+ vb.y += fy;
1163
+ }
1164
+ }
1165
+ }
1166
+
1167
+ void solveColorMixing(final TimeStep step) {
1168
+ // mixes color between contacting particles
1169
+ m_colorBuffer.data = requestParticleBuffer(ParticleColor.class, m_colorBuffer.data);
1170
+ int colorMixing256 = (int) (256 * m_colorMixingStrength);
1171
+ for (int k = 0; k < m_contactCount; k++) {
1172
+ final ParticleContact contact = m_contactBuffer[k];
1173
+ int a = contact.indexA;
1174
+ int b = contact.indexB;
1175
+ if ((m_flagsBuffer.data[a] & m_flagsBuffer.data[b] & ParticleType.b2_colorMixingParticle) != 0) {
1176
+ ParticleColor colorA = m_colorBuffer.data[a];
1177
+ ParticleColor colorB = m_colorBuffer.data[b];
1178
+ int dr = (colorMixing256 * (colorB.r - colorA.r)) >> 8;
1179
+ int dg = (colorMixing256 * (colorB.g - colorA.g)) >> 8;
1180
+ int db = (colorMixing256 * (colorB.b - colorA.b)) >> 8;
1181
+ int da = (colorMixing256 * (colorB.a - colorA.a)) >> 8;
1182
+ colorA.r += dr;
1183
+ colorA.g += dg;
1184
+ colorA.b += db;
1185
+ colorA.a += da;
1186
+ colorB.r -= dr;
1187
+ colorB.g -= dg;
1188
+ colorB.b -= db;
1189
+ colorB.a -= da;
1190
+ }
1191
+ }
1192
+ }
1193
+
1194
+ void solveZombie() {
1195
+ // removes particles with zombie flag
1196
+ int newCount = 0;
1197
+ int[] newIndices = new int[m_count];
1198
+ for (int i = 0; i < m_count; i++) {
1199
+ int flags = m_flagsBuffer.data[i];
1200
+ if ((flags & ParticleType.b2_zombieParticle) != 0) {
1201
+ ParticleDestructionListener destructionListener = m_world.getParticleDestructionListener();
1202
+ if ((flags & ParticleType.b2_destructionListener) != 0 && destructionListener != null) {
1203
+ destructionListener.sayGoodbye(i);
1204
+ }
1205
+ newIndices[i] = Settings.invalidParticleIndex;
1206
+ } else {
1207
+ newIndices[i] = newCount;
1208
+ if (i != newCount) {
1209
+ m_flagsBuffer.data[newCount] = m_flagsBuffer.data[i];
1210
+ m_positionBuffer.data[newCount].set(m_positionBuffer.data[i]);
1211
+ m_velocityBuffer.data[newCount].set(m_velocityBuffer.data[i]);
1212
+ m_groupBuffer[newCount] = m_groupBuffer[i];
1213
+ if (m_depthBuffer != null) {
1214
+ m_depthBuffer[newCount] = m_depthBuffer[i];
1215
+ }
1216
+ if (m_colorBuffer.data != null) {
1217
+ m_colorBuffer.data[newCount].set(m_colorBuffer.data[i]);
1218
+ }
1219
+ if (m_userDataBuffer.data != null) {
1220
+ m_userDataBuffer.data[newCount] = m_userDataBuffer.data[i];
1221
+ }
1222
+ }
1223
+ newCount++;
1224
+ }
1225
+ }
1226
+
1227
+ // update proxies
1228
+ for (int k = 0; k < m_proxyCount; k++) {
1229
+ Proxy proxy = m_proxyBuffer[k];
1230
+ proxy.index = newIndices[proxy.index];
1231
+ }
1232
+
1233
+ // Proxy lastProxy = std.remove_if(
1234
+ // m_proxyBuffer, m_proxyBuffer + m_proxyCount,
1235
+ // Test.IsProxyInvalid);
1236
+ // m_proxyCount = (int) (lastProxy - m_proxyBuffer);
1237
+ int j = m_proxyCount;
1238
+ for (int i = 0; i < j; i++) {
1239
+ if (Test.IsProxyInvalid(m_proxyBuffer[i])) {
1240
+ --j;
1241
+ Proxy temp = m_proxyBuffer[j];
1242
+ m_proxyBuffer[j] = m_proxyBuffer[i];
1243
+ m_proxyBuffer[i] = temp;
1244
+ --i;
1245
+ }
1246
+ }
1247
+ m_proxyCount = j;
1248
+
1249
+ // update contacts
1250
+ for (int k = 0; k < m_contactCount; k++) {
1251
+ ParticleContact contact = m_contactBuffer[k];
1252
+ contact.indexA = newIndices[contact.indexA];
1253
+ contact.indexB = newIndices[contact.indexB];
1254
+ }
1255
+ // ParticleContact lastContact = std.remove_if(
1256
+ // m_contactBuffer, m_contactBuffer + m_contactCount,
1257
+ // Test.IsContactInvalid);
1258
+ // m_contactCount = (int) (lastContact - m_contactBuffer);
1259
+ j = m_contactCount;
1260
+ for (int i = 0; i < j; i++) {
1261
+ if (Test.IsContactInvalid(m_contactBuffer[i])) {
1262
+ --j;
1263
+ ParticleContact temp = m_contactBuffer[j];
1264
+ m_contactBuffer[j] = m_contactBuffer[i];
1265
+ m_contactBuffer[i] = temp;
1266
+ --i;
1267
+ }
1268
+ }
1269
+ m_contactCount = j;
1270
+
1271
+ // update particle-body contacts
1272
+ for (int k = 0; k < m_bodyContactCount; k++) {
1273
+ ParticleBodyContact contact = m_bodyContactBuffer[k];
1274
+ contact.index = newIndices[contact.index];
1275
+ }
1276
+ // ParticleBodyContact lastBodyContact = std.remove_if(
1277
+ // m_bodyContactBuffer, m_bodyContactBuffer + m_bodyContactCount,
1278
+ // Test.IsBodyContactInvalid);
1279
+ // m_bodyContactCount = (int) (lastBodyContact - m_bodyContactBuffer);
1280
+ j = m_bodyContactCount;
1281
+ for (int i = 0; i < j; i++) {
1282
+ if (Test.IsBodyContactInvalid(m_bodyContactBuffer[i])) {
1283
+ --j;
1284
+ ParticleBodyContact temp = m_bodyContactBuffer[j];
1285
+ m_bodyContactBuffer[j] = m_bodyContactBuffer[i];
1286
+ m_bodyContactBuffer[i] = temp;
1287
+ --i;
1288
+ }
1289
+ }
1290
+ m_bodyContactCount = j;
1291
+
1292
+ // update pairs
1293
+ for (int k = 0; k < m_pairCount; k++) {
1294
+ Pair pair = m_pairBuffer[k];
1295
+ pair.indexA = newIndices[pair.indexA];
1296
+ pair.indexB = newIndices[pair.indexB];
1297
+ }
1298
+ // Pair lastPair = std.remove_if(m_pairBuffer, m_pairBuffer + m_pairCount, Test.IsPairInvalid);
1299
+ // m_pairCount = (int) (lastPair - m_pairBuffer);
1300
+ j = m_pairCount;
1301
+ for (int i = 0; i < j; i++) {
1302
+ if (Test.IsPairInvalid(m_pairBuffer[i])) {
1303
+ --j;
1304
+ Pair temp = m_pairBuffer[j];
1305
+ m_pairBuffer[j] = m_pairBuffer[i];
1306
+ m_pairBuffer[i] = temp;
1307
+ --i;
1308
+ }
1309
+ }
1310
+ m_pairCount = j;
1311
+
1312
+ // update triads
1313
+ for (int k = 0; k < m_triadCount; k++) {
1314
+ Triad triad = m_triadBuffer[k];
1315
+ triad.indexA = newIndices[triad.indexA];
1316
+ triad.indexB = newIndices[triad.indexB];
1317
+ triad.indexC = newIndices[triad.indexC];
1318
+ }
1319
+ // Triad lastTriad =
1320
+ // std.remove_if(m_triadBuffer, m_triadBuffer + m_triadCount, Test.isTriadInvalid);
1321
+ // m_triadCount = (int) (lastTriad - m_triadBuffer);
1322
+ j = m_triadCount;
1323
+ for (int i = 0; i < j; i++) {
1324
+ if (Test.IsTriadInvalid(m_triadBuffer[i])) {
1325
+ --j;
1326
+ Triad temp = m_triadBuffer[j];
1327
+ m_triadBuffer[j] = m_triadBuffer[i];
1328
+ m_triadBuffer[i] = temp;
1329
+ --i;
1330
+ }
1331
+ }
1332
+ m_triadCount = j;
1333
+
1334
+ // update groups
1335
+ for (ParticleGroup group = m_groupList; group != null; group = group.getNext()) {
1336
+ int firstIndex = newCount;
1337
+ int lastIndex = 0;
1338
+ boolean modified = false;
1339
+ for (int i = group.m_firstIndex; i < group.m_lastIndex; i++) {
1340
+ j = newIndices[i];
1341
+ if (j >= 0) {
1342
+ firstIndex = MathUtils.min(firstIndex, j);
1343
+ lastIndex = MathUtils.max(lastIndex, j + 1);
1344
+ } else {
1345
+ modified = true;
1346
+ }
1347
+ }
1348
+ if (firstIndex < lastIndex) {
1349
+ group.m_firstIndex = firstIndex;
1350
+ group.m_lastIndex = lastIndex;
1351
+ if (modified) {
1352
+ if ((group.m_groupFlags & ParticleGroupType.b2_rigidParticleGroup) != 0) {
1353
+ group.m_toBeSplit = true;
1354
+ }
1355
+ }
1356
+ } else {
1357
+ group.m_firstIndex = 0;
1358
+ group.m_lastIndex = 0;
1359
+ if (group.m_destroyAutomatically) {
1360
+ group.m_toBeDestroyed = true;
1361
+ }
1362
+ }
1363
+ }
1364
+
1365
+ // update particle count
1366
+ m_count = newCount;
1367
+ // m_world.m_stackAllocator.Free(newIndices);
1368
+
1369
+ // destroy bodies with no particles
1370
+ for (ParticleGroup group = m_groupList; group != null;) {
1371
+ ParticleGroup next = group.getNext();
1372
+ if (group.m_toBeDestroyed) {
1373
+ destroyParticleGroup(group);
1374
+ } else if (group.m_toBeSplit) {
1375
+ // TODO: split the group
1376
+ }
1377
+ group = next;
1378
+ }
1379
+ }
1380
+
1381
+ private static class NewIndices {
1382
+ int start, mid, end;
1383
+
1384
+ final int getIndex(final int i) {
1385
+ if (i < start) {
1386
+ return i;
1387
+ } else if (i < mid) {
1388
+ return i + end - mid;
1389
+ } else if (i < end) {
1390
+ return i + start - mid;
1391
+ } else {
1392
+ return i;
1393
+ }
1394
+ }
1395
+ }
1396
+
1397
+ private final NewIndices newIndices = new NewIndices();
1398
+
1399
+
1400
+ void RotateBuffer(int start, int mid, int end) {
1401
+ // move the particles assigned to the given group toward the end of array
1402
+ if (start == mid || mid == end) {
1403
+ return;
1404
+ }
1405
+ newIndices.start = start;
1406
+ newIndices.mid = mid;
1407
+ newIndices.end = end;
1408
+
1409
+ BufferUtils.rotate(m_flagsBuffer.data, start, mid, end);
1410
+ BufferUtils.rotate(m_positionBuffer.data, start, mid, end);
1411
+ BufferUtils.rotate(m_velocityBuffer.data, start, mid, end);
1412
+ BufferUtils.rotate(m_groupBuffer, start, mid, end);
1413
+ if (m_depthBuffer != null) {
1414
+ BufferUtils.rotate(m_depthBuffer, start, mid, end);
1415
+ }
1416
+ if (m_colorBuffer.data != null) {
1417
+ BufferUtils.rotate(m_colorBuffer.data, start, mid, end);
1418
+ }
1419
+ if (m_userDataBuffer.data != null) {
1420
+ BufferUtils.rotate(m_userDataBuffer.data, start, mid, end);
1421
+ }
1422
+
1423
+ // update proxies
1424
+ for (int k = 0; k < m_proxyCount; k++) {
1425
+ Proxy proxy = m_proxyBuffer[k];
1426
+ proxy.index = newIndices.getIndex(proxy.index);
1427
+ }
1428
+
1429
+ // update contacts
1430
+ for (int k = 0; k < m_contactCount; k++) {
1431
+ ParticleContact contact = m_contactBuffer[k];
1432
+ contact.indexA = newIndices.getIndex(contact.indexA);
1433
+ contact.indexB = newIndices.getIndex(contact.indexB);
1434
+ }
1435
+
1436
+ // update particle-body contacts
1437
+ for (int k = 0; k < m_bodyContactCount; k++) {
1438
+ ParticleBodyContact contact = m_bodyContactBuffer[k];
1439
+ contact.index = newIndices.getIndex(contact.index);
1440
+ }
1441
+
1442
+ // update pairs
1443
+ for (int k = 0; k < m_pairCount; k++) {
1444
+ Pair pair = m_pairBuffer[k];
1445
+ pair.indexA = newIndices.getIndex(pair.indexA);
1446
+ pair.indexB = newIndices.getIndex(pair.indexB);
1447
+ }
1448
+
1449
+ // update triads
1450
+ for (int k = 0; k < m_triadCount; k++) {
1451
+ Triad triad = m_triadBuffer[k];
1452
+ triad.indexA = newIndices.getIndex(triad.indexA);
1453
+ triad.indexB = newIndices.getIndex(triad.indexB);
1454
+ triad.indexC = newIndices.getIndex(triad.indexC);
1455
+ }
1456
+
1457
+ // update groups
1458
+ for (ParticleGroup group = m_groupList; group != null; group = group.getNext()) {
1459
+ group.m_firstIndex = newIndices.getIndex(group.m_firstIndex);
1460
+ group.m_lastIndex = newIndices.getIndex(group.m_lastIndex - 1) + 1;
1461
+ }
1462
+ }
1463
+
1464
+ public void setParticleRadius(float radius) {
1465
+ m_particleDiameter = 2 * radius;
1466
+ m_squaredDiameter = m_particleDiameter * m_particleDiameter;
1467
+ m_inverseDiameter = 1 / m_particleDiameter;
1468
+ }
1469
+
1470
+ public void setParticleDensity(float density) {
1471
+ m_density = density;
1472
+ m_inverseDensity = 1 / m_density;
1473
+ }
1474
+
1475
+ public float getParticleDensity() {
1476
+ return m_density;
1477
+ }
1478
+
1479
+ public void setParticleGravityScale(float gravityScale) {
1480
+ m_gravityScale = gravityScale;
1481
+ }
1482
+
1483
+ public float getParticleGravityScale() {
1484
+ return m_gravityScale;
1485
+ }
1486
+
1487
+ public void setParticleDamping(float damping) {
1488
+ m_dampingStrength = damping;
1489
+ }
1490
+
1491
+ public float getParticleDamping() {
1492
+ return m_dampingStrength;
1493
+ }
1494
+
1495
+ public float getParticleRadius() {
1496
+ return m_particleDiameter / 2;
1497
+ }
1498
+
1499
+ float getCriticalVelocity(final TimeStep step) {
1500
+ return m_particleDiameter * step.inv_dt;
1501
+ }
1502
+
1503
+ float getCriticalVelocitySquared(final TimeStep step) {
1504
+ float velocity = getCriticalVelocity(step);
1505
+ return velocity * velocity;
1506
+ }
1507
+
1508
+ float getCriticalPressure(final TimeStep step) {
1509
+ return m_density * getCriticalVelocitySquared(step);
1510
+ }
1511
+
1512
+ float getParticleStride() {
1513
+ return Settings.particleStride * m_particleDiameter;
1514
+ }
1515
+
1516
+ float getParticleMass() {
1517
+ float stride = getParticleStride();
1518
+ return m_density * stride * stride;
1519
+ }
1520
+
1521
+ float getParticleInvMass() {
1522
+ return 1.777777f * m_inverseDensity * m_inverseDiameter * m_inverseDiameter;
1523
+ }
1524
+
1525
+ public int[] getParticleFlagsBuffer() {
1526
+ return m_flagsBuffer.data;
1527
+ }
1528
+
1529
+ public Vec2[] getParticlePositionBuffer() {
1530
+ return m_positionBuffer.data;
1531
+ }
1532
+
1533
+ public Vec2[] getParticleVelocityBuffer() {
1534
+ return m_velocityBuffer.data;
1535
+ }
1536
+
1537
+ public ParticleColor[] getParticleColorBuffer() {
1538
+ m_colorBuffer.data = requestParticleBuffer(ParticleColor.class, m_colorBuffer.data);
1539
+ return m_colorBuffer.data;
1540
+ }
1541
+
1542
+ public Object[] getParticleUserDataBuffer() {
1543
+ m_userDataBuffer.data = requestParticleBuffer(Object.class, m_userDataBuffer.data);
1544
+ return m_userDataBuffer.data;
1545
+ }
1546
+
1547
+ public int getParticleMaxCount() {
1548
+ return m_maxCount;
1549
+ }
1550
+
1551
+ public void setParticleMaxCount(int count) {
1552
+ assert (m_count <= count);
1553
+ m_maxCount = count;
1554
+ }
1555
+
1556
+ void setParticleBuffer(ParticleBufferInt buffer, int[] newData, int newCapacity) {
1557
+ assert ((newData != null && newCapacity != 0) || (newData == null && newCapacity == 0));
1558
+ if (buffer.userSuppliedCapacity != 0) {
1559
+ // m_world.m_blockAllocator.Free(buffer.data, sizeof(T) * m_internalAllocatedCapacity);
1560
+ }
1561
+ buffer.data = newData;
1562
+ buffer.userSuppliedCapacity = newCapacity;
1563
+ }
1564
+
1565
+ <T> void setParticleBuffer(ParticleBuffer<T> buffer, T[] newData, int newCapacity) {
1566
+ assert ((newData != null && newCapacity != 0) || (newData == null && newCapacity == 0));
1567
+ if (buffer.userSuppliedCapacity != 0) {
1568
+ // m_world.m_blockAllocator.Free(buffer.data, sizeof(T) * m_internalAllocatedCapacity);
1569
+ }
1570
+ buffer.data = newData;
1571
+ buffer.userSuppliedCapacity = newCapacity;
1572
+ }
1573
+
1574
+ public void setParticleFlagsBuffer(int[] buffer, int capacity) {
1575
+ setParticleBuffer(m_flagsBuffer, buffer, capacity);
1576
+ }
1577
+
1578
+ public void setParticlePositionBuffer(Vec2[] buffer, int capacity) {
1579
+ setParticleBuffer(m_positionBuffer, buffer, capacity);
1580
+ }
1581
+
1582
+ public void setParticleVelocityBuffer(Vec2[] buffer, int capacity) {
1583
+ setParticleBuffer(m_velocityBuffer, buffer, capacity);
1584
+ }
1585
+
1586
+ public void setParticleColorBuffer(ParticleColor[] buffer, int capacity) {
1587
+ setParticleBuffer(m_colorBuffer, buffer, capacity);
1588
+ }
1589
+
1590
+ public ParticleGroup[] getParticleGroupBuffer() {
1591
+ return m_groupBuffer;
1592
+ }
1593
+
1594
+ public int getParticleGroupCount() {
1595
+ return m_groupCount;
1596
+ }
1597
+
1598
+ public ParticleGroup[] getParticleGroupList() {
1599
+ return m_groupBuffer;
1600
+ }
1601
+
1602
+ public int getParticleCount() {
1603
+ return m_count;
1604
+ }
1605
+
1606
+ public void setParticleUserDataBuffer(Object[] buffer, int capacity) {
1607
+ setParticleBuffer(m_userDataBuffer, buffer, capacity);
1608
+ }
1609
+
1610
+ private static final int lowerBound(Proxy[] ray, int length, long tag) {
1611
+ int left = 0;
1612
+ int step, curr;
1613
+ while (length > 0) {
1614
+ step = length / 2;
1615
+ curr = left + step;
1616
+ if (ray[curr].tag < tag) {
1617
+ left = curr + 1;
1618
+ length -= step + 1;
1619
+ } else {
1620
+ length = step;
1621
+ }
1622
+ }
1623
+ return left;
1624
+ }
1625
+
1626
+ private static final int upperBound(Proxy[] ray, int length, long tag) {
1627
+ int left = 0;
1628
+ int step, curr;
1629
+ while (length > 0) {
1630
+ step = length / 2;
1631
+ curr = left + step;
1632
+ if (ray[curr].tag <= tag) {
1633
+ left = curr + 1;
1634
+ length -= step + 1;
1635
+ } else {
1636
+ length = step;
1637
+ }
1638
+ }
1639
+ return left;
1640
+ }
1641
+
1642
+ public void queryAABB(ParticleQueryCallback callback, final AABB aabb) {
1643
+ if (m_proxyCount == 0) {
1644
+ return;
1645
+ }
1646
+
1647
+ final float lowerBoundX = aabb.lowerBound.x;
1648
+ final float lowerBoundY = aabb.lowerBound.y;
1649
+ final float upperBoundX = aabb.upperBound.x;
1650
+ final float upperBoundY = aabb.upperBound.y;
1651
+ int firstProxy =
1652
+ lowerBound(m_proxyBuffer, m_proxyCount,
1653
+ computeTag(m_inverseDiameter * lowerBoundX, m_inverseDiameter * lowerBoundY));
1654
+ int lastProxy =
1655
+ upperBound(m_proxyBuffer, m_proxyCount,
1656
+ computeTag(m_inverseDiameter * upperBoundX, m_inverseDiameter * upperBoundY));
1657
+ for (int proxy = firstProxy; proxy < lastProxy; ++proxy) {
1658
+ int i = m_proxyBuffer[proxy].index;
1659
+ final Vec2 p = m_positionBuffer.data[i];
1660
+ if (lowerBoundX < p.x && p.x < upperBoundX && lowerBoundY < p.y && p.y < upperBoundY) {
1661
+ if (!callback.reportParticle(i)) {
1662
+ break;
1663
+ }
1664
+ }
1665
+ }
1666
+ }
1667
+
1668
+ /**
1669
+ * @param callback
1670
+ * @param point1
1671
+ * @param point2
1672
+ */
1673
+ public void raycast(ParticleRaycastCallback callback, final Vec2 point1, final Vec2 point2) {
1674
+ if (m_proxyCount == 0) {
1675
+ return;
1676
+ }
1677
+ int firstProxy =
1678
+ lowerBound(
1679
+ m_proxyBuffer,
1680
+ m_proxyCount,
1681
+ computeTag(m_inverseDiameter * MathUtils.min(point1.x, point2.x) - 1, m_inverseDiameter
1682
+ * MathUtils.min(point1.y, point2.y) - 1));
1683
+ int lastProxy =
1684
+ upperBound(
1685
+ m_proxyBuffer,
1686
+ m_proxyCount,
1687
+ computeTag(m_inverseDiameter * MathUtils.max(point1.x, point2.x) + 1, m_inverseDiameter
1688
+ * MathUtils.max(point1.y, point2.y) + 1));
1689
+ float fraction = 1;
1690
+ // solving the following equation:
1691
+ // ((1-t)*point1+t*point2-position)^2=diameter^2
1692
+ // where t is a potential fraction
1693
+ final float vx = point2.x - point1.x;
1694
+ final float vy = point2.y - point1.y;
1695
+ float v2 = vx * vx + vy * vy;
1696
+ if (v2 == 0) v2 = Float.MAX_VALUE;
1697
+ for (int proxy = firstProxy; proxy < lastProxy; ++proxy) {
1698
+ int i = m_proxyBuffer[proxy].index;
1699
+ final Vec2 posI = m_positionBuffer.data[i];
1700
+ final float px = point1.x - posI.x;
1701
+ final float py = point1.y - posI.y;
1702
+ float pv = px * vx + py * vy;
1703
+ float p2 = px * px + py * py;
1704
+ float determinant = pv * pv - v2 * (p2 - m_squaredDiameter);
1705
+ if (determinant >= 0) {
1706
+ float sqrtDeterminant = MathUtils.sqrt(determinant);
1707
+ // find a solution between 0 and fraction
1708
+ float t = (-pv - sqrtDeterminant) / v2;
1709
+ if (t > fraction) {
1710
+ continue;
1711
+ }
1712
+ if (t < 0) {
1713
+ t = (-pv + sqrtDeterminant) / v2;
1714
+ if (t < 0 || t > fraction) {
1715
+ continue;
1716
+ }
1717
+ }
1718
+ final Vec2 n = tempVec;
1719
+ tempVec.x = px + t * vx;
1720
+ tempVec.y = py + t * vy;
1721
+ n.normalize();
1722
+ final Vec2 point = tempVec2;
1723
+ point.x = point1.x + t * vx;
1724
+ point.y = point1.y + t * vy;
1725
+ float f = callback.reportParticle(i, point, n, t);
1726
+ fraction = MathUtils.min(fraction, f);
1727
+ if (fraction <= 0) {
1728
+ break;
1729
+ }
1730
+ }
1731
+ }
1732
+ }
1733
+
1734
+ public float computeParticleCollisionEnergy() {
1735
+ float sum_v2 = 0;
1736
+ for (int k = 0; k < m_contactCount; k++) {
1737
+ final ParticleContact contact = m_contactBuffer[k];
1738
+ int a = contact.indexA;
1739
+ int b = contact.indexB;
1740
+ Vec2 n = contact.normal;
1741
+ final Vec2 va = m_velocityBuffer.data[a];
1742
+ final Vec2 vb = m_velocityBuffer.data[b];
1743
+ final float vx = vb.x - va.x;
1744
+ final float vy = vb.y - va.y;
1745
+ float vn = vx * n.x + vy * n.y;
1746
+ if (vn < 0) {
1747
+ sum_v2 += vn * vn;
1748
+ }
1749
+ }
1750
+ return 0.5f * getParticleMass() * sum_v2;
1751
+ }
1752
+
1753
+ // reallocate a buffer
1754
+ static <T> T[] reallocateBuffer(ParticleBuffer<T> buffer, int oldCapacity, int newCapacity,
1755
+ boolean deferred) {
1756
+ assert (newCapacity > oldCapacity);
1757
+ return BufferUtils.reallocateBuffer(buffer.dataClass, buffer.data, buffer.userSuppliedCapacity,
1758
+ oldCapacity, newCapacity, deferred);
1759
+ }
1760
+
1761
+ static int[] reallocateBuffer(ParticleBufferInt buffer, int oldCapacity, int newCapacity,
1762
+ boolean deferred) {
1763
+ assert (newCapacity > oldCapacity);
1764
+ return BufferUtils.reallocateBuffer(buffer.data, buffer.userSuppliedCapacity, oldCapacity,
1765
+ newCapacity, deferred);
1766
+ }
1767
+
1768
+ @SuppressWarnings("unchecked")
1769
+ <T> T[] requestParticleBuffer(Class<T> klass, T[] buffer) {
1770
+ if (buffer == null) {
1771
+ buffer = (T[]) Array.newInstance(klass, m_internalAllocatedCapacity);
1772
+ for (int i = 0; i < m_internalAllocatedCapacity; i++) {
1773
+ try {
1774
+ buffer[i] = klass.newInstance();
1775
+ } catch (Exception e) {
1776
+ throw new RuntimeException(e);
1777
+ }
1778
+ }
1779
+ }
1780
+ return buffer;
1781
+ }
1782
+
1783
+ float[] requestParticleBuffer(float[] buffer) {
1784
+ if (buffer == null) {
1785
+ buffer = new float[m_internalAllocatedCapacity];
1786
+ }
1787
+ return buffer;
1788
+ }
1789
+
1790
+ public static class ParticleBuffer<T> {
1791
+ public T[] data;
1792
+ final Class<T> dataClass;
1793
+ int userSuppliedCapacity;
1794
+
1795
+ public ParticleBuffer(Class<T> dataClass) {
1796
+ this.dataClass = dataClass;
1797
+ }
1798
+ }
1799
+ static class ParticleBufferInt {
1800
+ int[] data;
1801
+ int userSuppliedCapacity;
1802
+ }
1803
+
1804
+ /** Used for detecting particle contacts */
1805
+ public static class Proxy implements Comparable<Proxy> {
1806
+ int index;
1807
+ long tag;
1808
+
1809
+ @Override
1810
+ public int compareTo(Proxy o) {
1811
+ return (tag - o.tag) < 0 ? -1 : (o.tag == tag ? 0 : 1);
1812
+ }
1813
+
1814
+ @Override
1815
+ public boolean equals(Object obj) {
1816
+ if (this == obj) return true;
1817
+ if (obj == null) return false;
1818
+ if (getClass() != obj.getClass()) return false;
1819
+ Proxy other = (Proxy) obj;
1820
+ if (tag != other.tag) return false;
1821
+ return true;
1822
+ }
1823
+ }
1824
+
1825
+ /** Connection between two particles */
1826
+ public static class Pair {
1827
+ int indexA, indexB;
1828
+ int flags;
1829
+ float strength;
1830
+ float distance;
1831
+ }
1832
+
1833
+ /** Connection between three particles */
1834
+ public static class Triad {
1835
+ int indexA, indexB, indexC;
1836
+ int flags;
1837
+ float strength;
1838
+ final Vec2 pa = new Vec2(), pb = new Vec2(), pc = new Vec2();
1839
+ float ka, kb, kc, s;
1840
+ }
1841
+
1842
+ // Callback used with VoronoiDiagram.
1843
+ static class CreateParticleGroupCallback implements VoronoiDiagramCallback {
1844
+ public void callback(int a, int b, int c) {
1845
+ final Vec2 pa = system.m_positionBuffer.data[a];
1846
+ final Vec2 pb = system.m_positionBuffer.data[b];
1847
+ final Vec2 pc = system.m_positionBuffer.data[c];
1848
+ final float dabx = pa.x - pb.x;
1849
+ final float daby = pa.y - pb.y;
1850
+ final float dbcx = pb.x - pc.x;
1851
+ final float dbcy = pb.y - pc.y;
1852
+ final float dcax = pc.x - pa.x;
1853
+ final float dcay = pc.y - pa.y;
1854
+ float maxDistanceSquared = Settings.maxTriadDistanceSquared * system.m_squaredDiameter;
1855
+ if (dabx * dabx + daby * daby < maxDistanceSquared
1856
+ && dbcx * dbcx + dbcy * dbcy < maxDistanceSquared
1857
+ && dcax * dcax + dcay * dcay < maxDistanceSquared) {
1858
+ if (system.m_triadCount >= system.m_triadCapacity) {
1859
+ int oldCapacity = system.m_triadCapacity;
1860
+ int newCapacity =
1861
+ system.m_triadCount != 0
1862
+ ? 2 * system.m_triadCount
1863
+ : Settings.minParticleBufferCapacity;
1864
+ system.m_triadBuffer =
1865
+ BufferUtils.reallocateBuffer(Triad.class, system.m_triadBuffer, oldCapacity,
1866
+ newCapacity);
1867
+ system.m_triadCapacity = newCapacity;
1868
+ }
1869
+ Triad triad = system.m_triadBuffer[system.m_triadCount];
1870
+ triad.indexA = a;
1871
+ triad.indexB = b;
1872
+ triad.indexC = c;
1873
+ triad.flags =
1874
+ system.m_flagsBuffer.data[a] | system.m_flagsBuffer.data[b]
1875
+ | system.m_flagsBuffer.data[c];
1876
+ triad.strength = def.strength;
1877
+ final float midPointx = (float) 1 / 3 * (pa.x + pb.x + pc.x);
1878
+ final float midPointy = (float) 1 / 3 * (pa.y + pb.y + pc.y);
1879
+ triad.pa.x = pa.x - midPointx;
1880
+ triad.pa.y = pa.y - midPointy;
1881
+ triad.pb.x = pb.x - midPointx;
1882
+ triad.pb.y = pb.y - midPointy;
1883
+ triad.pc.x = pc.x - midPointx;
1884
+ triad.pc.y = pc.y - midPointy;
1885
+ triad.ka = -(dcax * dabx + dcay * daby);
1886
+ triad.kb = -(dabx * dbcx + daby * dbcy);
1887
+ triad.kc = -(dbcx * dcax + dbcy * dcay);
1888
+ triad.s = Vec2.cross(pa, pb) + Vec2.cross(pb, pc) + Vec2.cross(pc, pa);
1889
+ system.m_triadCount++;
1890
+ }
1891
+ }
1892
+
1893
+ ParticleSystem system;
1894
+ ParticleGroupDef def; // pointer
1895
+ int firstIndex;
1896
+ }
1897
+
1898
+ // Callback used with VoronoiDiagram.
1899
+ static class JoinParticleGroupsCallback implements VoronoiDiagramCallback {
1900
+ public void callback(int a, int b, int c) {
1901
+ // Create a triad if it will contain particles from both groups.
1902
+ int countA =
1903
+ ((a < groupB.m_firstIndex) ? 1 : 0) + ((b < groupB.m_firstIndex) ? 1 : 0)
1904
+ + ((c < groupB.m_firstIndex) ? 1 : 0);
1905
+ if (countA > 0 && countA < 3) {
1906
+ int af = system.m_flagsBuffer.data[a];
1907
+ int bf = system.m_flagsBuffer.data[b];
1908
+ int cf = system.m_flagsBuffer.data[c];
1909
+ if ((af & bf & cf & k_triadFlags) != 0) {
1910
+ final Vec2 pa = system.m_positionBuffer.data[a];
1911
+ final Vec2 pb = system.m_positionBuffer.data[b];
1912
+ final Vec2 pc = system.m_positionBuffer.data[c];
1913
+ final float dabx = pa.x - pb.x;
1914
+ final float daby = pa.y - pb.y;
1915
+ final float dbcx = pb.x - pc.x;
1916
+ final float dbcy = pb.y - pc.y;
1917
+ final float dcax = pc.x - pa.x;
1918
+ final float dcay = pc.y - pa.y;
1919
+ float maxDistanceSquared = Settings.maxTriadDistanceSquared * system.m_squaredDiameter;
1920
+ if (dabx * dabx + daby * daby < maxDistanceSquared
1921
+ && dbcx * dbcx + dbcy * dbcy < maxDistanceSquared
1922
+ && dcax * dcax + dcay * dcay < maxDistanceSquared) {
1923
+ if (system.m_triadCount >= system.m_triadCapacity) {
1924
+ int oldCapacity = system.m_triadCapacity;
1925
+ int newCapacity =
1926
+ system.m_triadCount != 0
1927
+ ? 2 * system.m_triadCount
1928
+ : Settings.minParticleBufferCapacity;
1929
+ system.m_triadBuffer =
1930
+ BufferUtils.reallocateBuffer(Triad.class, system.m_triadBuffer, oldCapacity,
1931
+ newCapacity);
1932
+ system.m_triadCapacity = newCapacity;
1933
+ }
1934
+ Triad triad = system.m_triadBuffer[system.m_triadCount];
1935
+ triad.indexA = a;
1936
+ triad.indexB = b;
1937
+ triad.indexC = c;
1938
+ triad.flags = af | bf | cf;
1939
+ triad.strength = MathUtils.min(groupA.m_strength, groupB.m_strength);
1940
+ final float midPointx = (float) 1 / 3 * (pa.x + pb.x + pc.x);
1941
+ final float midPointy = (float) 1 / 3 * (pa.y + pb.y + pc.y);
1942
+ triad.pa.x = pa.x - midPointx;
1943
+ triad.pa.y = pa.y - midPointy;
1944
+ triad.pb.x = pb.x - midPointx;
1945
+ triad.pb.y = pb.y - midPointy;
1946
+ triad.pc.x = pc.x - midPointx;
1947
+ triad.pc.y = pc.y - midPointy;
1948
+ triad.ka = -(dcax * dabx + dcay * daby);
1949
+ triad.kb = -(dabx * dbcx + daby * dbcy);
1950
+ triad.kc = -(dbcx * dcax + dbcy * dcay);
1951
+ triad.s = Vec2.cross(pa, pb) + Vec2.cross(pb, pc) + Vec2.cross(pc, pa);
1952
+ system.m_triadCount++;
1953
+ }
1954
+ }
1955
+ }
1956
+ }
1957
+
1958
+ ParticleSystem system;
1959
+ ParticleGroup groupA;
1960
+ ParticleGroup groupB;
1961
+ };
1962
+
1963
+ static class DestroyParticlesInShapeCallback implements ParticleQueryCallback {
1964
+ ParticleSystem system;
1965
+ Shape shape;
1966
+ Transform xf;
1967
+ boolean callDestructionListener;
1968
+ int destroyed;
1969
+
1970
+ public DestroyParticlesInShapeCallback() {
1971
+ // TODO Auto-generated constructor stub
1972
+ }
1973
+
1974
+ public void init(ParticleSystem system, Shape shape, Transform xf,
1975
+ boolean callDestructionListener) {
1976
+ this.system = system;
1977
+ this.shape = shape;
1978
+ this.xf = xf;
1979
+ this.destroyed = 0;
1980
+ this.callDestructionListener = callDestructionListener;
1981
+ }
1982
+
1983
+ @Override
1984
+ public boolean reportParticle(int index) {
1985
+ assert (index >= 0 && index < system.m_count);
1986
+ if (shape.testPoint(xf, system.m_positionBuffer.data[index])) {
1987
+ system.destroyParticle(index, callDestructionListener);
1988
+ destroyed++;
1989
+ }
1990
+ return true;
1991
+ }
1992
+ }
1993
+
1994
+ static class UpdateBodyContactsCallback implements QueryCallback {
1995
+ ParticleSystem system;
1996
+
1997
+ private final Vec2 tempVec = new Vec2();
1998
+
1999
+ @Override
2000
+ public boolean reportFixture(Fixture fixture) {
2001
+ if (fixture.isSensor()) {
2002
+ return true;
2003
+ }
2004
+ final Shape shape = fixture.getShape();
2005
+ Body b = fixture.getBody();
2006
+ Vec2 bp = b.getWorldCenter();
2007
+ float bm = b.getMass();
2008
+ float bI = b.getInertia() - bm * b.getLocalCenter().lengthSquared();
2009
+ float invBm = bm > 0 ? 1 / bm : 0;
2010
+ float invBI = bI > 0 ? 1 / bI : 0;
2011
+ int childCount = shape.getChildCount();
2012
+ for (int childIndex = 0; childIndex < childCount; childIndex++) {
2013
+ AABB aabb = fixture.getAABB(childIndex);
2014
+ final float aabblowerBoundx = aabb.lowerBound.x - system.m_particleDiameter;
2015
+ final float aabblowerBoundy = aabb.lowerBound.y - system.m_particleDiameter;
2016
+ final float aabbupperBoundx = aabb.upperBound.x + system.m_particleDiameter;
2017
+ final float aabbupperBoundy = aabb.upperBound.y + system.m_particleDiameter;
2018
+ int firstProxy =
2019
+ lowerBound(
2020
+ system.m_proxyBuffer,
2021
+ system.m_proxyCount,
2022
+ computeTag(system.m_inverseDiameter * aabblowerBoundx, system.m_inverseDiameter
2023
+ * aabblowerBoundy));
2024
+ int lastProxy =
2025
+ upperBound(
2026
+ system.m_proxyBuffer,
2027
+ system.m_proxyCount,
2028
+ computeTag(system.m_inverseDiameter * aabbupperBoundx, system.m_inverseDiameter
2029
+ * aabbupperBoundy));
2030
+
2031
+ for (int proxy = firstProxy; proxy != lastProxy; ++proxy) {
2032
+ int a = system.m_proxyBuffer[proxy].index;
2033
+ Vec2 ap = system.m_positionBuffer.data[a];
2034
+ if (aabblowerBoundx <= ap.x && ap.x <= aabbupperBoundx && aabblowerBoundy <= ap.y
2035
+ && ap.y <= aabbupperBoundy) {
2036
+ float d;
2037
+ final Vec2 n = tempVec;
2038
+ d = fixture.computeDistance(ap, childIndex, n);
2039
+ if (d < system.m_particleDiameter) {
2040
+ float invAm =
2041
+ (system.m_flagsBuffer.data[a] & ParticleType.b2_wallParticle) != 0 ? 0 : system
2042
+ .getParticleInvMass();
2043
+ final float rpx = ap.x - bp.x;
2044
+ final float rpy = ap.y - bp.y;
2045
+ float rpn = rpx * n.y - rpy * n.x;
2046
+ if (system.m_bodyContactCount >= system.m_bodyContactCapacity) {
2047
+ int oldCapacity = system.m_bodyContactCapacity;
2048
+ int newCapacity =
2049
+ system.m_bodyContactCount != 0
2050
+ ? 2 * system.m_bodyContactCount
2051
+ : Settings.minParticleBufferCapacity;
2052
+ system.m_bodyContactBuffer =
2053
+ BufferUtils.reallocateBuffer(ParticleBodyContact.class,
2054
+ system.m_bodyContactBuffer, oldCapacity, newCapacity);
2055
+ system.m_bodyContactCapacity = newCapacity;
2056
+ }
2057
+ ParticleBodyContact contact = system.m_bodyContactBuffer[system.m_bodyContactCount];
2058
+ contact.index = a;
2059
+ contact.body = b;
2060
+ contact.weight = 1 - d * system.m_inverseDiameter;
2061
+ contact.normal.x = -n.x;
2062
+ contact.normal.y = -n.y;
2063
+ contact.mass = 1 / (invAm + invBm + invBI * rpn * rpn);
2064
+ system.m_bodyContactCount++;
2065
+ }
2066
+ }
2067
+ }
2068
+ }
2069
+ return true;
2070
+ }
2071
+ }
2072
+
2073
+ static class SolveCollisionCallback implements QueryCallback {
2074
+ ParticleSystem system;
2075
+ TimeStep step;
2076
+
2077
+ private final RayCastInput input = new RayCastInput();
2078
+ private final RayCastOutput output = new RayCastOutput();
2079
+ private final Vec2 tempVec = new Vec2();
2080
+ private final Vec2 tempVec2 = new Vec2();
2081
+
2082
+ @Override
2083
+ public boolean reportFixture(Fixture fixture) {
2084
+ if (fixture.isSensor()) {
2085
+ return true;
2086
+ }
2087
+ final Shape shape = fixture.getShape();
2088
+ Body body = fixture.getBody();
2089
+ int childCount = shape.getChildCount();
2090
+ for (int childIndex = 0; childIndex < childCount; childIndex++) {
2091
+ AABB aabb = fixture.getAABB(childIndex);
2092
+ final float aabblowerBoundx = aabb.lowerBound.x - system.m_particleDiameter;
2093
+ final float aabblowerBoundy = aabb.lowerBound.y - system.m_particleDiameter;
2094
+ final float aabbupperBoundx = aabb.upperBound.x + system.m_particleDiameter;
2095
+ final float aabbupperBoundy = aabb.upperBound.y + system.m_particleDiameter;
2096
+ int firstProxy =
2097
+ lowerBound(
2098
+ system.m_proxyBuffer,
2099
+ system.m_proxyCount,
2100
+ computeTag(system.m_inverseDiameter * aabblowerBoundx, system.m_inverseDiameter
2101
+ * aabblowerBoundy));
2102
+ int lastProxy =
2103
+ upperBound(
2104
+ system.m_proxyBuffer,
2105
+ system.m_proxyCount,
2106
+ computeTag(system.m_inverseDiameter * aabbupperBoundx, system.m_inverseDiameter
2107
+ * aabbupperBoundy));
2108
+
2109
+ for (int proxy = firstProxy; proxy != lastProxy; ++proxy) {
2110
+ int a = system.m_proxyBuffer[proxy].index;
2111
+ Vec2 ap = system.m_positionBuffer.data[a];
2112
+ if (aabblowerBoundx <= ap.x && ap.x <= aabbupperBoundx && aabblowerBoundy <= ap.y
2113
+ && ap.y <= aabbupperBoundy) {
2114
+ Vec2 av = system.m_velocityBuffer.data[a];
2115
+ final Vec2 temp = tempVec;
2116
+ Transform.mulTransToOutUnsafe(body.m_xf0, ap, temp);
2117
+ Transform.mulToOutUnsafe(body.m_xf, temp, input.p1);
2118
+ input.p2.x = ap.x + step.dt * av.x;
2119
+ input.p2.y = ap.y + step.dt * av.y;
2120
+ input.maxFraction = 1;
2121
+ if (fixture.raycast(output, input, childIndex)) {
2122
+ final Vec2 p = tempVec;
2123
+ p.x =
2124
+ (1 - output.fraction) * input.p1.x + output.fraction * input.p2.x
2125
+ + Settings.linearSlop * output.normal.x;
2126
+ p.y =
2127
+ (1 - output.fraction) * input.p1.y + output.fraction * input.p2.y
2128
+ + Settings.linearSlop * output.normal.y;
2129
+
2130
+ final float vx = step.inv_dt * (p.x - ap.x);
2131
+ final float vy = step.inv_dt * (p.y - ap.y);
2132
+ av.x = vx;
2133
+ av.y = vy;
2134
+ final float particleMass = system.getParticleMass();
2135
+ final float ax = particleMass * (av.x - vx);
2136
+ final float ay = particleMass * (av.y - vy);
2137
+ Vec2 b = output.normal;
2138
+ final float fdn = ax * b.x + ay * b.y;
2139
+ final Vec2 f = tempVec2;
2140
+ f.x = fdn * b.x;
2141
+ f.y = fdn * b.y;
2142
+ body.applyLinearImpulse(f, p, true);
2143
+ }
2144
+ }
2145
+ }
2146
+ }
2147
+ return true;
2148
+ }
2149
+ }
2150
+
2151
+ static class Test {
2152
+ static boolean IsProxyInvalid(final Proxy proxy) {
2153
+ return proxy.index < 0;
2154
+ }
2155
+
2156
+ static boolean IsContactInvalid(final ParticleContact contact) {
2157
+ return contact.indexA < 0 || contact.indexB < 0;
2158
+ }
2159
+
2160
+ static boolean IsBodyContactInvalid(final ParticleBodyContact contact) {
2161
+ return contact.index < 0;
2162
+ }
2163
+
2164
+ static boolean IsPairInvalid(final Pair pair) {
2165
+ return pair.indexA < 0 || pair.indexB < 0;
2166
+ }
2167
+
2168
+ static boolean IsTriadInvalid(final Triad triad) {
2169
+ return triad.indexA < 0 || triad.indexB < 0 || triad.indexC < 0;
2170
+ }
2171
+ };
2172
+ }