2 * Copyright (c) 2010 The Desert team
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation
6 * files (the "Software"), to deal in the Software without
7 * restriction, including without limitation the rights to use,
8 * copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 * OTHER DEALINGS IN THE SOFTWARE.
26 package org
.sourceforge
.desert
;
28 import com
.bulletphysics
.collision
.broadphase
.AxisSweep3
;
29 import com
.bulletphysics
.collision
.broadphase
.BroadphaseInterface
;
30 import com
.bulletphysics
.collision
.dispatch
.CollisionDispatcher
;
31 import com
.bulletphysics
.collision
.dispatch
.CollisionObject
;
32 import com
.bulletphysics
.collision
.dispatch
.DefaultCollisionConfiguration
;
33 import com
.bulletphysics
.collision
.shapes
.CollisionShape
;
34 import com
.bulletphysics
.collision
.shapes
.SphereShape
;
35 import com
.bulletphysics
.collision
.shapes
.StaticPlaneShape
;
36 import com
.bulletphysics
.dynamics
.DiscreteDynamicsWorld
;
37 import com
.bulletphysics
.dynamics
.DynamicsWorld
;
38 import com
.bulletphysics
.dynamics
.RigidBody
;
39 import com
.bulletphysics
.dynamics
.RigidBodyConstructionInfo
;
40 import com
.bulletphysics
.dynamics
.constraintsolver
.ConstraintSolver
;
41 import com
.bulletphysics
.dynamics
.constraintsolver
.SequentialImpulseConstraintSolver
;
42 import com
.bulletphysics
.linearmath
.DefaultMotionState
;
43 import com
.bulletphysics
.linearmath
.Transform
;
44 import java
.awt
.Dimension
;
45 import java
.util
.Iterator
;
46 import java
.util
.ListIterator
;
47 import javax
.vecmath
.Vector3f
;
48 import org
.sourceforge
.desert
.Particle
.Type
;
52 * @author codistmonk (creation 2010-04-17)
54 public class ParticleEngineJBulletImplementation
implements ParticleEngine
{
56 private final DynamicsWorld dynamicsWorld
;
58 private final ParticleIterator particleIterator
;
60 private RigidBody bottomBorder
;
62 private RigidBody leftBorder
;
64 private RigidBody topBorder
;
66 private RigidBody rightBorder
;
68 public ParticleEngineJBulletImplementation() {
69 this.dynamicsWorld
= createDynamicsWorld();
70 this.particleIterator
= this.new ParticleIterator();
74 public final Dimension
getBoardSize() {
75 // FIXME this method doesn't work
76 final Transform transform
= new Transform();
77 final int bottom
= (int) this.bottomBorder
.getMotionState().getWorldTransform(transform
).origin
.y
;
78 final int left
= (int) this.leftBorder
.getMotionState().getWorldTransform(transform
).origin
.x
;
79 final int top
= (int) this.topBorder
.getMotionState().getWorldTransform(transform
).origin
.y
;
80 final int right
= (int) this.rightBorder
.getMotionState().getWorldTransform(transform
).origin
.x
;
82 return new Dimension(right
- left
, top
- bottom
);
86 public final void setBoardSize(final Dimension size
) {
87 if (this.bottomBorder
!= null) {
88 this.getDynamicsWorld().removeRigidBody(this.bottomBorder
);
89 this.getDynamicsWorld().removeRigidBody(this.leftBorder
);
90 this.getDynamicsWorld().removeRigidBody(this.topBorder
);
91 this.getDynamicsWorld().removeRigidBody(this.rightBorder
);
94 this.bottomBorder
= createPlane(new Vector3f(0F
, 1F
, 0F
), 0F
);
95 this.leftBorder
= createPlane(new Vector3f(1F
, 0F
, 0F
), 0F
);
96 this.topBorder
= createPlane(new Vector3f(0F
, -1F
, 0F
), (float) (-size
.height
));
97 this.rightBorder
= createPlane(new Vector3f(-1F
, 0F
, 0F
), (float) (-size
.width
));
99 this.getDynamicsWorld().addRigidBody(this.bottomBorder
);
100 this.getDynamicsWorld().addRigidBody(this.leftBorder
);
101 this.getDynamicsWorld().addRigidBody(this.topBorder
);
102 this.getDynamicsWorld().addRigidBody(this.rightBorder
);
106 public void addParticle(final Particle
.Type type
, final float x
, final float y
, final float speedX
, final float speedY
) {
107 final RigidBody rigidBody
= createSphere(type
.getMass(), type
.getRadius(), new Vector3f(x
, y
, 0.0F
));
109 rigidBody
.setUserPointer(type
);
110 rigidBody
.setLinearVelocity(new Vector3f(speedX
, speedY
, 0F
));
112 this.getDynamicsWorld().addRigidBody(rigidBody
);
116 public final int getParticleCount() {
117 // The 4 border planes are also collision objects, so they must be
118 // subtracted (if they are defined) to count only the particles
119 return this.dynamicsWorld
.getNumCollisionObjects() - (this.bottomBorder
== null ?
0 : 4);
123 public final void update(final float deltaTime
) {
124 this.getDynamicsWorld().stepSimulation(1000F
* deltaTime
);
128 public final Iterator
<Particle
> iterator() {
129 this.particleIterator
.reset();
131 return this.particleIterator
;
135 public final float getGravity() {
136 return (float) this.getDynamicsWorld().getGravity(new Vector3f()).y
;
140 public final void setGravity(final float gravity
) {
141 this.getDynamicsWorld().setGravity(new Vector3f(0F
, gravity
, 0F
));
144 final DynamicsWorld
getDynamicsWorld() {
145 return this.dynamicsWorld
;
149 * @author codistmonk (creation 2010-04-17)
151 private final class ParticleIterator
implements Iterator
<Particle
> {
153 private final ParticleDefaultImplementation iterationParticle
;
155 private final Transform transform
;
157 private final Vector3f linearVelocity
;
159 private ListIterator
<CollisionObject
> collisionObjectIterator
;
161 public ParticleIterator() {
162 this.iterationParticle
= new ParticleDefaultImplementation(Particle
.Type
.values()[0], 0F
, 0F
, 0F
, 0F
);
163 this.transform
= new Transform();
164 this.linearVelocity
= new Vector3f();
167 public final void reset() {
168 this.collisionObjectIterator
= ParticleEngineJBulletImplementation
.this.getDynamicsWorld().getCollisionObjectArray().listIterator();
172 public final boolean hasNext() {
173 this.ignoreNonparticles();
175 return this.collisionObjectIterator
.hasNext();
179 public final Particle
next() {
180 this.ignoreNonparticles();
182 final RigidBody particle
= (RigidBody
) this.collisionObjectIterator
.next();
183 final Type type
= (Type
) particle
.getUserPointer();
185 particle
.getWorldTransform(this.transform
);
186 particle
.getLinearVelocity(this.linearVelocity
);
188 this.iterationParticle
.setType(type
);
189 this.iterationParticle
.setX(this.transform
.origin
.x
);
190 this.iterationParticle
.setY(this.transform
.origin
.y
);
191 this.iterationParticle
.setSpeedX(this.linearVelocity
.x
);
192 this.iterationParticle
.setSpeedY(this.linearVelocity
.y
);
194 return this.iterationParticle
;
198 public final void remove() {
199 throw new UnsupportedOperationException("Not supported");
202 private final void ignoreNonparticles() {
203 CollisionObject collisionObject
= null;
205 while (this.collisionObjectIterator
.hasNext() && !((collisionObject
= this.collisionObjectIterator
.next()).getUserPointer() instanceof Type
)) {
209 if (collisionObject
!= null && collisionObject
.getUserPointer() instanceof Type
) {
210 this.collisionObjectIterator
.previous();
220 * <br>A non-null value
222 private static final DynamicsWorld
createDynamicsWorld() {
223 final DefaultCollisionConfiguration collisionConfiguration
= new DefaultCollisionConfiguration();
224 final CollisionDispatcher collisionDispatcher
= new CollisionDispatcher(collisionConfiguration
);
225 final Float size
= 10000F
;
226 final BroadphaseInterface overlappingPairCache
= new AxisSweep3(new Vector3f(-size
, -size
, -size
), new Vector3f(size
, size
, size
));
227 final ConstraintSolver solver
= new SequentialImpulseConstraintSolver();
228 final DynamicsWorld result
= new DiscreteDynamicsWorld(collisionDispatcher
, overlappingPairCache
, solver
, collisionConfiguration
);
230 result
.setGravity(new Vector3f(0F
, -10F
, 0F
));
238 * <br>Shoudl not be null
240 * <br>Should not be null
243 * <br>A non-null value
245 private static final RigidBody
createPlane(final Vector3f planeNormal
, final Float planeC
) {
246 final Float mass
= 0F
;
247 final DefaultMotionState motionState
= new DefaultMotionState(createIdentityTransform());
248 final CollisionShape collisionShape
= new StaticPlaneShape(planeNormal
, planeC
);
249 final RigidBodyConstructionInfo constructionInfo
= new RigidBodyConstructionInfo(mass
, motionState
, collisionShape
);
251 return new RigidBody(constructionInfo
);
257 * <br>Range: <code>[0 .. Float.POSITIVE_INFINITY]</code>
259 * <br>Range: <code>[0 .. Float.POSITIVE_INFINITY[</code>
261 * <br>Should not be null
264 * <br>A non-null value
266 private static final RigidBody
createSphere(final float mass
, final Float radius
, final Vector3f origin
) {
267 final CollisionShape collisionShape
= new SphereShape(radius
);
268 final Transform transform
= createIdentityTransform();
269 final float jbulletMass
= (mass
== Float
.POSITIVE_INFINITY ?
0F
: mass
);
271 if (jbulletMass
!= 0F
) {
272 collisionShape
.calculateLocalInertia(mass
, new Vector3f());
275 transform
.origin
.set(origin
);
277 final DefaultMotionState motionState
= new DefaultMotionState(transform
);
278 final RigidBodyConstructionInfo constructionInfo
= new RigidBodyConstructionInfo(mass
, motionState
, collisionShape
);
280 return new RigidBody(constructionInfo
);
287 * <br>A non-null value
289 private static final Transform
createIdentityTransform() {
290 final Transform result
= new Transform();
292 result
.setIdentity();