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.
- checksums.yaml +4 -4
- data/.mvn/extensions.xml +8 -0
- data/.mvn/wrapper/maven-wrapper.properties +1 -0
- data/.travis.yml +23 -0
- data/CHANGELOG.md +8 -0
- data/README.md +7 -7
- data/Rakefile +1 -2
- data/lib/box2d.jar +0 -0
- data/lib/pbox2d/version.rb +1 -1
- data/lib/pbox2d.rb +1 -0
- data/pbox2d.gemspec +6 -11
- data/pom.rb +59 -0
- data/pom.xml +82 -73
- data/src/org/jbox2d/JBox2D.gwt.xml +12 -0
- data/src/org/jbox2d/callbacks/ContactAdaptor.java +27 -0
- data/src/org/jbox2d/callbacks/ContactFilter.java +59 -0
- data/src/org/jbox2d/callbacks/ContactImpulse.java +42 -0
- data/src/org/jbox2d/callbacks/ContactListener.java +87 -0
- data/src/org/jbox2d/callbacks/DebugDraw.java +297 -0
- data/src/org/jbox2d/callbacks/DestructionListener.java +53 -0
- data/src/org/jbox2d/callbacks/PairCallback.java +29 -0
- data/src/org/jbox2d/callbacks/ParticleDestructionListener.java +20 -0
- data/src/org/jbox2d/callbacks/ParticleQueryCallback.java +19 -0
- data/src/org/jbox2d/callbacks/ParticleRaycastCallback.java +19 -0
- data/src/org/jbox2d/callbacks/QueryCallback.java +45 -0
- data/src/org/jbox2d/callbacks/RayCastCallback.java +55 -0
- data/src/org/jbox2d/callbacks/TreeCallback.java +42 -0
- data/src/org/jbox2d/callbacks/TreeRayCastCallback.java +44 -0
- data/src/org/jbox2d/collision/AABB.java +338 -0
- data/src/org/jbox2d/collision/Collision.java +1444 -0
- data/src/org/jbox2d/collision/ContactID.java +106 -0
- data/src/org/jbox2d/collision/Distance.java +773 -0
- data/src/org/jbox2d/collision/DistanceInput.java +41 -0
- data/src/org/jbox2d/collision/DistanceOutput.java +43 -0
- data/src/org/jbox2d/collision/Manifold.java +116 -0
- data/src/org/jbox2d/collision/ManifoldPoint.java +104 -0
- data/src/org/jbox2d/collision/RayCastInput.java +47 -0
- data/src/org/jbox2d/collision/RayCastOutput.java +46 -0
- data/src/org/jbox2d/collision/TimeOfImpact.java +526 -0
- data/src/org/jbox2d/collision/WorldManifold.java +200 -0
- data/src/org/jbox2d/collision/broadphase/BroadPhase.java +92 -0
- data/src/org/jbox2d/collision/broadphase/BroadPhaseStrategy.java +88 -0
- data/src/org/jbox2d/collision/broadphase/DefaultBroadPhaseBuffer.java +268 -0
- data/src/org/jbox2d/collision/broadphase/DynamicTree.java +883 -0
- data/src/org/jbox2d/collision/broadphase/DynamicTreeFlatNodes.java +873 -0
- data/src/org/jbox2d/collision/broadphase/DynamicTreeNode.java +54 -0
- data/src/org/jbox2d/collision/broadphase/Pair.java +46 -0
- data/src/org/jbox2d/collision/shapes/ChainShape.java +264 -0
- data/src/org/jbox2d/collision/shapes/CircleShape.java +207 -0
- data/src/org/jbox2d/collision/shapes/EdgeShape.java +254 -0
- data/src/org/jbox2d/collision/shapes/MassData.java +105 -0
- data/src/org/jbox2d/collision/shapes/PolygonShape.java +718 -0
- data/src/org/jbox2d/collision/shapes/Shape.java +136 -0
- data/src/org/jbox2d/collision/shapes/ShapeType.java +32 -0
- data/src/org/jbox2d/common/BufferUtils.java +209 -0
- data/src/org/jbox2d/common/Color3f.java +88 -0
- data/src/org/jbox2d/common/IViewportTransform.java +133 -0
- data/src/org/jbox2d/common/Mat22.java +609 -0
- data/src/org/jbox2d/common/Mat33.java +290 -0
- data/src/org/jbox2d/common/MathUtils.java +335 -0
- data/src/org/jbox2d/common/OBBViewportTransform.java +174 -0
- data/src/org/jbox2d/common/PlatformMathUtils.java +46 -0
- data/src/org/jbox2d/common/RaycastResult.java +37 -0
- data/src/org/jbox2d/common/Rot.java +150 -0
- data/src/org/jbox2d/common/Settings.java +246 -0
- data/src/org/jbox2d/common/Sweep.java +116 -0
- data/src/org/jbox2d/common/Timer.java +46 -0
- data/src/org/jbox2d/common/Transform.java +203 -0
- data/src/org/jbox2d/common/Vec2.java +388 -0
- data/src/org/jbox2d/common/Vec3.java +170 -0
- data/src/org/jbox2d/dynamics/Body.java +1246 -0
- data/src/org/jbox2d/dynamics/BodyDef.java +382 -0
- data/src/org/jbox2d/dynamics/BodyType.java +41 -0
- data/src/org/jbox2d/dynamics/ContactManager.java +293 -0
- data/src/org/jbox2d/dynamics/Filter.java +62 -0
- data/src/org/jbox2d/dynamics/Fixture.java +454 -0
- data/src/org/jbox2d/dynamics/FixtureDef.java +214 -0
- data/src/org/jbox2d/dynamics/FixtureProxy.java +38 -0
- data/src/org/jbox2d/dynamics/Island.java +602 -0
- data/src/org/jbox2d/dynamics/Profile.java +97 -0
- data/src/org/jbox2d/dynamics/SolverData.java +33 -0
- data/src/org/jbox2d/dynamics/TimeStep.java +46 -0
- data/src/org/jbox2d/dynamics/World.java +2075 -0
- data/src/org/jbox2d/dynamics/contacts/ChainAndCircleContact.java +57 -0
- data/src/org/jbox2d/dynamics/contacts/ChainAndPolygonContact.java +57 -0
- data/src/org/jbox2d/dynamics/contacts/CircleContact.java +50 -0
- data/src/org/jbox2d/dynamics/contacts/Contact.java +365 -0
- data/src/org/jbox2d/dynamics/contacts/ContactCreator.java +35 -0
- data/src/org/jbox2d/dynamics/contacts/ContactEdge.java +56 -0
- data/src/org/jbox2d/dynamics/contacts/ContactPositionConstraint.java +49 -0
- data/src/org/jbox2d/dynamics/contacts/ContactRegister.java +31 -0
- data/src/org/jbox2d/dynamics/contacts/ContactSolver.java +1104 -0
- data/src/org/jbox2d/dynamics/contacts/ContactVelocityConstraint.java +60 -0
- data/src/org/jbox2d/dynamics/contacts/EdgeAndCircleContact.java +52 -0
- data/src/org/jbox2d/dynamics/contacts/EdgeAndPolygonContact.java +52 -0
- data/src/org/jbox2d/dynamics/contacts/PolygonAndCircleContact.java +51 -0
- data/src/org/jbox2d/dynamics/contacts/PolygonContact.java +50 -0
- data/src/org/jbox2d/dynamics/contacts/Position.java +31 -0
- data/src/org/jbox2d/dynamics/contacts/Velocity.java +31 -0
- data/src/org/jbox2d/dynamics/joints/ConstantVolumeJoint.java +258 -0
- data/src/org/jbox2d/dynamics/joints/ConstantVolumeJointDef.java +75 -0
- data/src/org/jbox2d/dynamics/joints/DistanceJoint.java +356 -0
- data/src/org/jbox2d/dynamics/joints/DistanceJointDef.java +106 -0
- data/src/org/jbox2d/dynamics/joints/FrictionJoint.java +294 -0
- data/src/org/jbox2d/dynamics/joints/FrictionJointDef.java +78 -0
- data/src/org/jbox2d/dynamics/joints/GearJoint.java +520 -0
- data/src/org/jbox2d/dynamics/joints/GearJointDef.java +58 -0
- data/src/org/jbox2d/dynamics/joints/Jacobian.java +32 -0
- data/src/org/jbox2d/dynamics/joints/Joint.java +235 -0
- data/src/org/jbox2d/dynamics/joints/JointDef.java +65 -0
- data/src/org/jbox2d/dynamics/joints/JointEdge.java +57 -0
- data/src/org/jbox2d/dynamics/joints/JointType.java +28 -0
- data/src/org/jbox2d/dynamics/joints/LimitState.java +28 -0
- data/src/org/jbox2d/dynamics/joints/MotorJoint.java +339 -0
- data/src/org/jbox2d/dynamics/joints/MotorJointDef.java +55 -0
- data/src/org/jbox2d/dynamics/joints/MouseJoint.java +262 -0
- data/src/org/jbox2d/dynamics/joints/MouseJointDef.java +62 -0
- data/src/org/jbox2d/dynamics/joints/PrismaticJoint.java +808 -0
- data/src/org/jbox2d/dynamics/joints/PrismaticJointDef.java +120 -0
- data/src/org/jbox2d/dynamics/joints/PulleyJoint.java +393 -0
- data/src/org/jbox2d/dynamics/joints/PulleyJointDef.java +105 -0
- data/src/org/jbox2d/dynamics/joints/RevoluteJoint.java +554 -0
- data/src/org/jbox2d/dynamics/joints/RevoluteJointDef.java +137 -0
- data/src/org/jbox2d/dynamics/joints/RopeJoint.java +276 -0
- data/src/org/jbox2d/dynamics/joints/RopeJointDef.java +34 -0
- data/src/org/jbox2d/dynamics/joints/WeldJoint.java +424 -0
- data/src/org/jbox2d/dynamics/joints/WeldJointDef.java +85 -0
- data/src/org/jbox2d/dynamics/joints/WheelJoint.java +498 -0
- data/src/org/jbox2d/dynamics/joints/WheelJointDef.java +98 -0
- data/src/org/jbox2d/particle/ParticleBodyContact.java +17 -0
- data/src/org/jbox2d/particle/ParticleColor.java +52 -0
- data/src/org/jbox2d/particle/ParticleContact.java +14 -0
- data/src/org/jbox2d/particle/ParticleDef.java +24 -0
- data/src/org/jbox2d/particle/ParticleGroup.java +154 -0
- data/src/org/jbox2d/particle/ParticleGroupDef.java +62 -0
- data/src/org/jbox2d/particle/ParticleGroupType.java +8 -0
- data/src/org/jbox2d/particle/ParticleSystem.java +2172 -0
- data/src/org/jbox2d/particle/ParticleType.java +28 -0
- data/src/org/jbox2d/particle/StackQueue.java +44 -0
- data/src/org/jbox2d/particle/VoronoiDiagram.java +209 -0
- data/src/org/jbox2d/pooling/IDynamicStack.java +47 -0
- data/src/org/jbox2d/pooling/IOrderedStack.java +57 -0
- data/src/org/jbox2d/pooling/IWorldPool.java +101 -0
- data/src/org/jbox2d/pooling/arrays/FloatArray.java +50 -0
- data/src/org/jbox2d/pooling/arrays/GeneratorArray.java +33 -0
- data/src/org/jbox2d/pooling/arrays/IntArray.java +53 -0
- data/src/org/jbox2d/pooling/arrays/Vec2Array.java +57 -0
- data/src/org/jbox2d/pooling/normal/CircleStack.java +77 -0
- data/src/org/jbox2d/pooling/normal/DefaultWorldPool.java +331 -0
- data/src/org/jbox2d/pooling/normal/MutableStack.java +72 -0
- data/src/org/jbox2d/pooling/normal/OrderedStack.java +73 -0
- data/src/org/jbox2d/pooling/stacks/DynamicIntStack.java +60 -0
- metadata +161 -14
- 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
|
+
}
|