1 /*
2 * Copyright (c) 2009-2010 jMonkeyEngine
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32 #include "jmePhysicsSpace.h"
33 #include "jmeBulletUtil.h"
34 #include <stdio.h>
35
36 /**
37 * Author: Normen Hansen
38 */
jmePhysicsSpace(JNIEnv * env,jobject javaSpace)39 jmePhysicsSpace::jmePhysicsSpace(JNIEnv* env, jobject javaSpace) {
40 //TODO: global ref? maybe not -> cleaning, rather callback class?
41 this->javaPhysicsSpace = env->NewWeakGlobalRef(javaSpace);
42 this->env = env;
43 env->GetJavaVM(&vm);
44 if (env->ExceptionCheck()) {
45 env->Throw(env->ExceptionOccurred());
46 return;
47 }
48 }
49
attachThread()50 void jmePhysicsSpace::attachThread() {
51 #ifdef ANDROID
52 vm->AttachCurrentThread((JNIEnv**) &env, NULL);
53 #elif defined (JNI_VERSION_1_2)
54 vm->AttachCurrentThread((void**) &env, NULL);
55 #else
56 vm->AttachCurrentThread(&env, NULL);
57 #endif
58 }
59
getEnv()60 JNIEnv* jmePhysicsSpace::getEnv() {
61 attachThread();
62 return this->env;
63 }
64
stepSimulation(jfloat tpf,jint maxSteps,jfloat accuracy)65 void jmePhysicsSpace::stepSimulation(jfloat tpf, jint maxSteps, jfloat accuracy) {
66 dynamicsWorld->stepSimulation(tpf, maxSteps, accuracy);
67 }
68
createSolverThreadSupport(int maxNumThreads)69 btThreadSupportInterface* jmePhysicsSpace::createSolverThreadSupport(int maxNumThreads) {
70 #ifdef _WIN32
71 Win32ThreadSupport::Win32ThreadConstructionInfo threadConstructionInfo("solverThreads", SolverThreadFunc, SolverlsMemoryFunc, maxNumThreads);
72 Win32ThreadSupport* threadSupport = new Win32ThreadSupport(threadConstructionInfo);
73 threadSupport->startSPU();
74 #elif defined (USE_PTHREADS)
75 PosixThreadSupport::ThreadConstructionInfo constructionInfo("collision", SolverThreadFunc,
76 SolverlsMemoryFunc, maxNumThreads);
77 PosixThreadSupport* threadSupport = new PosixThreadSupport(constructionInfo);
78 threadSupport->startSPU();
79 #else
80 SequentialThreadSupport::SequentialThreadConstructionInfo tci("solverThreads", SolverThreadFunc, SolverlsMemoryFunc);
81 SequentialThreadSupport* threadSupport = new SequentialThreadSupport(tci);
82 threadSupport->startSPU();
83 #endif
84 return threadSupport;
85 }
86
createDispatchThreadSupport(int maxNumThreads)87 btThreadSupportInterface* jmePhysicsSpace::createDispatchThreadSupport(int maxNumThreads) {
88 #ifdef _WIN32
89 Win32ThreadSupport::Win32ThreadConstructionInfo threadConstructionInfo("solverThreads", processCollisionTask, createCollisionLocalStoreMemory, maxNumThreads);
90 Win32ThreadSupport* threadSupport = new Win32ThreadSupport(threadConstructionInfo);
91 threadSupport->startSPU();
92 #elif defined (USE_PTHREADS)
93 PosixThreadSupport::ThreadConstructionInfo solverConstructionInfo("solver", processCollisionTask,
94 createCollisionLocalStoreMemory, maxNumThreads);
95 PosixThreadSupport* threadSupport = new PosixThreadSupport(solverConstructionInfo);
96 threadSupport->startSPU();
97 #else
98 SequentialThreadSupport::SequentialThreadConstructionInfo tci("solverThreads", processCollisionTask, createCollisionLocalStoreMemory);
99 SequentialThreadSupport* threadSupport = new SequentialThreadSupport(tci);
100 threadSupport->startSPU();
101 #endif
102 return threadSupport;
103 }
104
createPhysicsSpace(jfloat minX,jfloat minY,jfloat minZ,jfloat maxX,jfloat maxY,jfloat maxZ,jint broadphaseId,jboolean threading)105 void jmePhysicsSpace::createPhysicsSpace(jfloat minX, jfloat minY, jfloat minZ, jfloat maxX, jfloat maxY, jfloat maxZ, jint broadphaseId, jboolean threading) {
106 // collision configuration contains default setup for memory, collision setup
107 btDefaultCollisionConstructionInfo cci;
108 // if(threading){
109 // cci.m_defaultMaxPersistentManifoldPoolSize = 32768;
110 // }
111 btCollisionConfiguration* collisionConfiguration = new btDefaultCollisionConfiguration(cci);
112
113 btVector3 min = btVector3(minX, minY, minZ);
114 btVector3 max = btVector3(maxX, maxY, maxZ);
115
116 btBroadphaseInterface* broadphase;
117
118 switch (broadphaseId) {
119 case 0:
120 broadphase = new btSimpleBroadphase();
121 break;
122 case 1:
123 broadphase = new btAxisSweep3(min, max);
124 break;
125 case 2:
126 //TODO: 32bit!
127 broadphase = new btAxisSweep3(min, max);
128 break;
129 case 3:
130 broadphase = new btDbvtBroadphase();
131 break;
132 case 4:
133 // broadphase = new btGpu3DGridBroadphase(
134 // min, max,
135 // 20, 20, 20,
136 // 10000, 1000, 25);
137 break;
138 }
139
140 btCollisionDispatcher* dispatcher;
141 btConstraintSolver* solver;
142 // use the default collision dispatcher. For parallel processing you can use a diffent dispatcher (see Extras/BulletMultiThreaded)
143 if (threading) {
144 btThreadSupportInterface* dispatchThreads = createDispatchThreadSupport(4);
145 dispatcher = new SpuGatheringCollisionDispatcher(dispatchThreads, 4, collisionConfiguration);
146 dispatcher->setDispatcherFlags(btCollisionDispatcher::CD_DISABLE_CONTACTPOOL_DYNAMIC_ALLOCATION);
147 } else {
148 dispatcher = new btCollisionDispatcher(collisionConfiguration);
149 }
150
151 // the default constraint solver. For parallel processing you can use a different solver (see Extras/BulletMultiThreaded)
152 if (threading) {
153 btThreadSupportInterface* solverThreads = createSolverThreadSupport(4);
154 solver = new btParallelConstraintSolver(solverThreads);
155 } else {
156 solver = new btSequentialImpulseConstraintSolver;
157 }
158
159 //create dynamics world
160 btDiscreteDynamicsWorld* world = new btDiscreteDynamicsWorld(dispatcher, broadphase, solver, collisionConfiguration);
161 dynamicsWorld = world;
162 dynamicsWorld->setWorldUserInfo(this);
163
164 //parallel solver requires the contacts to be in a contiguous pool, so avoid dynamic allocation
165 if (threading) {
166 world->getSimulationIslandManager()->setSplitIslands(false);
167 world->getSolverInfo().m_numIterations = 4;
168 world->getSolverInfo().m_solverMode = SOLVER_SIMD + SOLVER_USE_WARMSTARTING; //+SOLVER_RANDMIZE_ORDER;
169 world->getDispatchInfo().m_enableSPU = true;
170 }
171
172 broadphase->getOverlappingPairCache()->setInternalGhostPairCallback(new btGhostPairCallback());
173
174 dynamicsWorld->setGravity(btVector3(0, -9.81f, 0));
175
176 struct jmeFilterCallback : public btOverlapFilterCallback {
177 // return true when pairs need collision
178
179 virtual bool needBroadphaseCollision(btBroadphaseProxy* proxy0, btBroadphaseProxy * proxy1) const {
180 // bool collides = (proxy0->m_collisionFilterGroup & proxy1->m_collisionFilterMask) != 0;
181 // collides = collides && (proxy1->m_collisionFilterGroup & proxy0->m_collisionFilterMask);
182 bool collides = (proxy0->m_collisionFilterGroup & proxy1->m_collisionFilterMask) != 0;
183 collides = collides && (proxy1->m_collisionFilterGroup & proxy0->m_collisionFilterMask);
184 if (collides) {
185 btCollisionObject* co0 = (btCollisionObject*) proxy0->m_clientObject;
186 btCollisionObject* co1 = (btCollisionObject*) proxy1->m_clientObject;
187 jmeUserPointer *up0 = (jmeUserPointer*) co0 -> getUserPointer();
188 jmeUserPointer *up1 = (jmeUserPointer*) co1 -> getUserPointer();
189 if (up0 != NULL && up1 != NULL) {
190 collides = (up0->group & up1->groups) != 0;
191 collides = collides && (up1->group & up0->groups);
192
193 //add some additional logic here that modified 'collides'
194 return collides;
195 }
196 return false;
197 }
198 return collides;
199 }
200 };
201 dynamicsWorld->getPairCache()->setOverlapFilterCallback(new jmeFilterCallback());
202 dynamicsWorld->setInternalTickCallback(&jmePhysicsSpace::preTickCallback, static_cast<void *> (this), true);
203 dynamicsWorld->setInternalTickCallback(&jmePhysicsSpace::postTickCallback, static_cast<void *> (this));
204 if (gContactProcessedCallback == NULL) {
205 gContactProcessedCallback = &jmePhysicsSpace::contactProcessedCallback;
206 }
207 }
208
preTickCallback(btDynamicsWorld * world,btScalar timeStep)209 void jmePhysicsSpace::preTickCallback(btDynamicsWorld *world, btScalar timeStep) {
210 jmePhysicsSpace* dynamicsWorld = (jmePhysicsSpace*) world->getWorldUserInfo();
211 JNIEnv* env = dynamicsWorld->getEnv();
212 jobject javaPhysicsSpace = env->NewLocalRef(dynamicsWorld->getJavaPhysicsSpace());
213 if (javaPhysicsSpace != NULL) {
214 env->CallVoidMethod(javaPhysicsSpace, jmeClasses::PhysicsSpace_preTick, timeStep);
215 env->DeleteLocalRef(javaPhysicsSpace);
216 if (env->ExceptionCheck()) {
217 env->Throw(env->ExceptionOccurred());
218 return;
219 }
220 }
221 }
222
postTickCallback(btDynamicsWorld * world,btScalar timeStep)223 void jmePhysicsSpace::postTickCallback(btDynamicsWorld *world, btScalar timeStep) {
224 jmePhysicsSpace* dynamicsWorld = (jmePhysicsSpace*) world->getWorldUserInfo();
225 JNIEnv* env = dynamicsWorld->getEnv();
226 jobject javaPhysicsSpace = env->NewLocalRef(dynamicsWorld->getJavaPhysicsSpace());
227 if (javaPhysicsSpace != NULL) {
228 env->CallVoidMethod(javaPhysicsSpace, jmeClasses::PhysicsSpace_postTick, timeStep);
229 env->DeleteLocalRef(javaPhysicsSpace);
230 if (env->ExceptionCheck()) {
231 env->Throw(env->ExceptionOccurred());
232 return;
233 }
234 }
235 }
236
contactProcessedCallback(btManifoldPoint & cp,void * body0,void * body1)237 bool jmePhysicsSpace::contactProcessedCallback(btManifoldPoint &cp, void *body0, void *body1) {
238 // printf("contactProcessedCallback %d %dn", body0, body1);
239 btCollisionObject* co0 = (btCollisionObject*) body0;
240 jmeUserPointer *up0 = (jmeUserPointer*) co0 -> getUserPointer();
241 btCollisionObject* co1 = (btCollisionObject*) body1;
242 jmeUserPointer *up1 = (jmeUserPointer*) co1 -> getUserPointer();
243 if (up0 != NULL) {
244 jmePhysicsSpace *dynamicsWorld = (jmePhysicsSpace *)up0->space;
245 if (dynamicsWorld != NULL) {
246 JNIEnv* env = dynamicsWorld->getEnv();
247 jobject javaPhysicsSpace = env->NewLocalRef(dynamicsWorld->getJavaPhysicsSpace());
248 if (javaPhysicsSpace != NULL) {
249 jobject javaCollisionObject0 = env->NewLocalRef(up0->javaCollisionObject);
250 jobject javaCollisionObject1 = env->NewLocalRef(up1->javaCollisionObject);
251 env->CallVoidMethod(javaPhysicsSpace, jmeClasses::PhysicsSpace_addCollisionEvent, javaCollisionObject0, javaCollisionObject1, (jlong) & cp);
252 env->DeleteLocalRef(javaPhysicsSpace);
253 env->DeleteLocalRef(javaCollisionObject0);
254 env->DeleteLocalRef(javaCollisionObject1);
255 if (env->ExceptionCheck()) {
256 env->Throw(env->ExceptionOccurred());
257 return true;
258 }
259 }
260 }
261 }
262 return true;
263 }
264
getDynamicsWorld()265 btDynamicsWorld* jmePhysicsSpace::getDynamicsWorld() {
266 return dynamicsWorld;
267 }
268
getJavaPhysicsSpace()269 jobject jmePhysicsSpace::getJavaPhysicsSpace() {
270 return javaPhysicsSpace;
271 }
272
~jmePhysicsSpace()273 jmePhysicsSpace::~jmePhysicsSpace() {
274 delete(dynamicsWorld);
275 }