pbox2d 0.6.0-java → 0.8.0-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (154) hide show
  1. checksums.yaml +4 -4
  2. data/.mvn/extensions.xml +8 -0
  3. data/.mvn/wrapper/maven-wrapper.properties +1 -0
  4. data/.travis.yml +23 -0
  5. data/CHANGELOG.md +8 -0
  6. data/README.md +7 -7
  7. data/Rakefile +1 -2
  8. data/lib/box2d.jar +0 -0
  9. data/lib/pbox2d/version.rb +1 -1
  10. data/lib/pbox2d.rb +1 -0
  11. data/pbox2d.gemspec +6 -11
  12. data/pom.rb +59 -0
  13. data/pom.xml +82 -73
  14. data/src/org/jbox2d/JBox2D.gwt.xml +12 -0
  15. data/src/org/jbox2d/callbacks/ContactAdaptor.java +27 -0
  16. data/src/org/jbox2d/callbacks/ContactFilter.java +59 -0
  17. data/src/org/jbox2d/callbacks/ContactImpulse.java +42 -0
  18. data/src/org/jbox2d/callbacks/ContactListener.java +87 -0
  19. data/src/org/jbox2d/callbacks/DebugDraw.java +297 -0
  20. data/src/org/jbox2d/callbacks/DestructionListener.java +53 -0
  21. data/src/org/jbox2d/callbacks/PairCallback.java +29 -0
  22. data/src/org/jbox2d/callbacks/ParticleDestructionListener.java +20 -0
  23. data/src/org/jbox2d/callbacks/ParticleQueryCallback.java +19 -0
  24. data/src/org/jbox2d/callbacks/ParticleRaycastCallback.java +19 -0
  25. data/src/org/jbox2d/callbacks/QueryCallback.java +45 -0
  26. data/src/org/jbox2d/callbacks/RayCastCallback.java +55 -0
  27. data/src/org/jbox2d/callbacks/TreeCallback.java +42 -0
  28. data/src/org/jbox2d/callbacks/TreeRayCastCallback.java +44 -0
  29. data/src/org/jbox2d/collision/AABB.java +338 -0
  30. data/src/org/jbox2d/collision/Collision.java +1444 -0
  31. data/src/org/jbox2d/collision/ContactID.java +106 -0
  32. data/src/org/jbox2d/collision/Distance.java +773 -0
  33. data/src/org/jbox2d/collision/DistanceInput.java +41 -0
  34. data/src/org/jbox2d/collision/DistanceOutput.java +43 -0
  35. data/src/org/jbox2d/collision/Manifold.java +116 -0
  36. data/src/org/jbox2d/collision/ManifoldPoint.java +104 -0
  37. data/src/org/jbox2d/collision/RayCastInput.java +47 -0
  38. data/src/org/jbox2d/collision/RayCastOutput.java +46 -0
  39. data/src/org/jbox2d/collision/TimeOfImpact.java +526 -0
  40. data/src/org/jbox2d/collision/WorldManifold.java +200 -0
  41. data/src/org/jbox2d/collision/broadphase/BroadPhase.java +92 -0
  42. data/src/org/jbox2d/collision/broadphase/BroadPhaseStrategy.java +88 -0
  43. data/src/org/jbox2d/collision/broadphase/DefaultBroadPhaseBuffer.java +268 -0
  44. data/src/org/jbox2d/collision/broadphase/DynamicTree.java +883 -0
  45. data/src/org/jbox2d/collision/broadphase/DynamicTreeFlatNodes.java +873 -0
  46. data/src/org/jbox2d/collision/broadphase/DynamicTreeNode.java +54 -0
  47. data/src/org/jbox2d/collision/broadphase/Pair.java +46 -0
  48. data/src/org/jbox2d/collision/shapes/ChainShape.java +264 -0
  49. data/src/org/jbox2d/collision/shapes/CircleShape.java +207 -0
  50. data/src/org/jbox2d/collision/shapes/EdgeShape.java +254 -0
  51. data/src/org/jbox2d/collision/shapes/MassData.java +105 -0
  52. data/src/org/jbox2d/collision/shapes/PolygonShape.java +718 -0
  53. data/src/org/jbox2d/collision/shapes/Shape.java +136 -0
  54. data/src/org/jbox2d/collision/shapes/ShapeType.java +32 -0
  55. data/src/org/jbox2d/common/BufferUtils.java +209 -0
  56. data/src/org/jbox2d/common/Color3f.java +88 -0
  57. data/src/org/jbox2d/common/IViewportTransform.java +133 -0
  58. data/src/org/jbox2d/common/Mat22.java +609 -0
  59. data/src/org/jbox2d/common/Mat33.java +290 -0
  60. data/src/org/jbox2d/common/MathUtils.java +335 -0
  61. data/src/org/jbox2d/common/OBBViewportTransform.java +174 -0
  62. data/src/org/jbox2d/common/PlatformMathUtils.java +46 -0
  63. data/src/org/jbox2d/common/RaycastResult.java +37 -0
  64. data/src/org/jbox2d/common/Rot.java +150 -0
  65. data/src/org/jbox2d/common/Settings.java +246 -0
  66. data/src/org/jbox2d/common/Sweep.java +116 -0
  67. data/src/org/jbox2d/common/Timer.java +46 -0
  68. data/src/org/jbox2d/common/Transform.java +203 -0
  69. data/src/org/jbox2d/common/Vec2.java +388 -0
  70. data/src/org/jbox2d/common/Vec3.java +170 -0
  71. data/src/org/jbox2d/dynamics/Body.java +1246 -0
  72. data/src/org/jbox2d/dynamics/BodyDef.java +382 -0
  73. data/src/org/jbox2d/dynamics/BodyType.java +41 -0
  74. data/src/org/jbox2d/dynamics/ContactManager.java +293 -0
  75. data/src/org/jbox2d/dynamics/Filter.java +62 -0
  76. data/src/org/jbox2d/dynamics/Fixture.java +454 -0
  77. data/src/org/jbox2d/dynamics/FixtureDef.java +214 -0
  78. data/src/org/jbox2d/dynamics/FixtureProxy.java +38 -0
  79. data/src/org/jbox2d/dynamics/Island.java +602 -0
  80. data/src/org/jbox2d/dynamics/Profile.java +97 -0
  81. data/src/org/jbox2d/dynamics/SolverData.java +33 -0
  82. data/src/org/jbox2d/dynamics/TimeStep.java +46 -0
  83. data/src/org/jbox2d/dynamics/World.java +2075 -0
  84. data/src/org/jbox2d/dynamics/contacts/ChainAndCircleContact.java +57 -0
  85. data/src/org/jbox2d/dynamics/contacts/ChainAndPolygonContact.java +57 -0
  86. data/src/org/jbox2d/dynamics/contacts/CircleContact.java +50 -0
  87. data/src/org/jbox2d/dynamics/contacts/Contact.java +365 -0
  88. data/src/org/jbox2d/dynamics/contacts/ContactCreator.java +35 -0
  89. data/src/org/jbox2d/dynamics/contacts/ContactEdge.java +56 -0
  90. data/src/org/jbox2d/dynamics/contacts/ContactPositionConstraint.java +49 -0
  91. data/src/org/jbox2d/dynamics/contacts/ContactRegister.java +31 -0
  92. data/src/org/jbox2d/dynamics/contacts/ContactSolver.java +1104 -0
  93. data/src/org/jbox2d/dynamics/contacts/ContactVelocityConstraint.java +60 -0
  94. data/src/org/jbox2d/dynamics/contacts/EdgeAndCircleContact.java +52 -0
  95. data/src/org/jbox2d/dynamics/contacts/EdgeAndPolygonContact.java +52 -0
  96. data/src/org/jbox2d/dynamics/contacts/PolygonAndCircleContact.java +51 -0
  97. data/src/org/jbox2d/dynamics/contacts/PolygonContact.java +50 -0
  98. data/src/org/jbox2d/dynamics/contacts/Position.java +31 -0
  99. data/src/org/jbox2d/dynamics/contacts/Velocity.java +31 -0
  100. data/src/org/jbox2d/dynamics/joints/ConstantVolumeJoint.java +258 -0
  101. data/src/org/jbox2d/dynamics/joints/ConstantVolumeJointDef.java +75 -0
  102. data/src/org/jbox2d/dynamics/joints/DistanceJoint.java +356 -0
  103. data/src/org/jbox2d/dynamics/joints/DistanceJointDef.java +106 -0
  104. data/src/org/jbox2d/dynamics/joints/FrictionJoint.java +294 -0
  105. data/src/org/jbox2d/dynamics/joints/FrictionJointDef.java +78 -0
  106. data/src/org/jbox2d/dynamics/joints/GearJoint.java +520 -0
  107. data/src/org/jbox2d/dynamics/joints/GearJointDef.java +58 -0
  108. data/src/org/jbox2d/dynamics/joints/Jacobian.java +32 -0
  109. data/src/org/jbox2d/dynamics/joints/Joint.java +235 -0
  110. data/src/org/jbox2d/dynamics/joints/JointDef.java +65 -0
  111. data/src/org/jbox2d/dynamics/joints/JointEdge.java +57 -0
  112. data/src/org/jbox2d/dynamics/joints/JointType.java +28 -0
  113. data/src/org/jbox2d/dynamics/joints/LimitState.java +28 -0
  114. data/src/org/jbox2d/dynamics/joints/MotorJoint.java +339 -0
  115. data/src/org/jbox2d/dynamics/joints/MotorJointDef.java +55 -0
  116. data/src/org/jbox2d/dynamics/joints/MouseJoint.java +262 -0
  117. data/src/org/jbox2d/dynamics/joints/MouseJointDef.java +62 -0
  118. data/src/org/jbox2d/dynamics/joints/PrismaticJoint.java +808 -0
  119. data/src/org/jbox2d/dynamics/joints/PrismaticJointDef.java +120 -0
  120. data/src/org/jbox2d/dynamics/joints/PulleyJoint.java +393 -0
  121. data/src/org/jbox2d/dynamics/joints/PulleyJointDef.java +105 -0
  122. data/src/org/jbox2d/dynamics/joints/RevoluteJoint.java +554 -0
  123. data/src/org/jbox2d/dynamics/joints/RevoluteJointDef.java +137 -0
  124. data/src/org/jbox2d/dynamics/joints/RopeJoint.java +276 -0
  125. data/src/org/jbox2d/dynamics/joints/RopeJointDef.java +34 -0
  126. data/src/org/jbox2d/dynamics/joints/WeldJoint.java +424 -0
  127. data/src/org/jbox2d/dynamics/joints/WeldJointDef.java +85 -0
  128. data/src/org/jbox2d/dynamics/joints/WheelJoint.java +498 -0
  129. data/src/org/jbox2d/dynamics/joints/WheelJointDef.java +98 -0
  130. data/src/org/jbox2d/particle/ParticleBodyContact.java +17 -0
  131. data/src/org/jbox2d/particle/ParticleColor.java +52 -0
  132. data/src/org/jbox2d/particle/ParticleContact.java +14 -0
  133. data/src/org/jbox2d/particle/ParticleDef.java +24 -0
  134. data/src/org/jbox2d/particle/ParticleGroup.java +154 -0
  135. data/src/org/jbox2d/particle/ParticleGroupDef.java +62 -0
  136. data/src/org/jbox2d/particle/ParticleGroupType.java +8 -0
  137. data/src/org/jbox2d/particle/ParticleSystem.java +2172 -0
  138. data/src/org/jbox2d/particle/ParticleType.java +28 -0
  139. data/src/org/jbox2d/particle/StackQueue.java +44 -0
  140. data/src/org/jbox2d/particle/VoronoiDiagram.java +209 -0
  141. data/src/org/jbox2d/pooling/IDynamicStack.java +47 -0
  142. data/src/org/jbox2d/pooling/IOrderedStack.java +57 -0
  143. data/src/org/jbox2d/pooling/IWorldPool.java +101 -0
  144. data/src/org/jbox2d/pooling/arrays/FloatArray.java +50 -0
  145. data/src/org/jbox2d/pooling/arrays/GeneratorArray.java +33 -0
  146. data/src/org/jbox2d/pooling/arrays/IntArray.java +53 -0
  147. data/src/org/jbox2d/pooling/arrays/Vec2Array.java +57 -0
  148. data/src/org/jbox2d/pooling/normal/CircleStack.java +77 -0
  149. data/src/org/jbox2d/pooling/normal/DefaultWorldPool.java +331 -0
  150. data/src/org/jbox2d/pooling/normal/MutableStack.java +72 -0
  151. data/src/org/jbox2d/pooling/normal/OrderedStack.java +73 -0
  152. data/src/org/jbox2d/pooling/stacks/DynamicIntStack.java +60 -0
  153. metadata +161 -14
  154. data/lib/jbox2d-library-2.3.1-SNAPSHOT.jar +0 -0
@@ -0,0 +1,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
+ }