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 */ 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 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 60 JNIEnv* jmePhysicsSpace::getEnv() { 61 attachThread(); 62 return this->env; 63 } 64 65 void jmePhysicsSpace::stepSimulation(jfloat tpf, jint maxSteps, jfloat accuracy) { 66 dynamicsWorld->stepSimulation(tpf, maxSteps, accuracy); 67 } 68 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 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 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 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 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 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 265 btDynamicsWorld* jmePhysicsSpace::getDynamicsWorld() { 266 return dynamicsWorld; 267 } 268 269 jobject jmePhysicsSpace::getJavaPhysicsSpace() { 270 return javaPhysicsSpace; 271 } 272 273 jmePhysicsSpace::~jmePhysicsSpace() { 274 delete(dynamicsWorld); 275 }