pxWorld.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "platform/platform.h"
  23. #include "T3D/physics/physX/pxWorld.h"
  24. #include "T3D/physics/physX/px.h"
  25. #include "T3D/physics/physX/pxPlugin.h"
  26. #include "T3D/physics/physX/pxMaterial.h"
  27. #include "T3D/physics/physX/pxContactReporter.h"
  28. #include "T3D/physics/physX/pxStream.h"
  29. #include "T3D/physics/physX/pxCasts.h"
  30. #include "T3D/physics/physicsUserData.h"
  31. #include "core/stream/bitStream.h"
  32. #include "platform/profiler.h"
  33. #include "sim/netConnection.h"
  34. #include "console/console.h"
  35. #include "console/consoleTypes.h"
  36. #include "core/util/safeDelete.h"
  37. #include "T3D/tsstatic.h"
  38. #include "T3D/gameBase/gameProcess.h"
  39. #include "gfx/sim/debugDraw.h"
  40. #include "gfx/primBuilder.h"
  41. #include <NXU_helper.h>
  42. static const F32 PhysicsStepTime = (F32)TickMs / 1000.0f;
  43. static const U32 PhysicsMaxIterations = 8;
  44. static const F32 PhysicsMaxTimeStep = PhysicsStepTime / 2.0f;
  45. NxPhysicsSDK *gPhysicsSDK = NULL;
  46. NxCookingInterface *PxWorld::smCooking = NULL;
  47. PxConsoleStream *PxWorld::smConsoleStream = NULL;
  48. PxWorld::PxWorld() :
  49. mScene( NULL ),
  50. mConactReporter( NULL ),
  51. mProcessList( NULL ),
  52. mIsSimulating( false ),
  53. mErrorReport( false ),
  54. mTickCount( 0 ),
  55. mIsEnabled( false ),
  56. mEditorTimeScale( 1.0f )
  57. {
  58. if ( !CCTAllocator::mAllocator )
  59. CCTAllocator::mAllocator = new NxUserAllocatorDefault();
  60. mControllerManager = new CharacterControllerManager( CCTAllocator::mAllocator );
  61. }
  62. PxWorld::~PxWorld()
  63. {
  64. delete mControllerManager;
  65. }
  66. NxCookingInterface* PxWorld::getCooking()
  67. {
  68. if ( !smCooking )
  69. smCooking = NxGetCookingLib( NX_PHYSICS_SDK_VERSION );
  70. return smCooking;
  71. }
  72. bool PxWorld::_init( bool isServer, ProcessList *processList )
  73. {
  74. if ( !gPhysicsSDK )
  75. {
  76. Con::errorf( "PhysXWorld::init - PhysXSDK not initialized!" );
  77. return false;
  78. }
  79. // Create the scene description.
  80. NxSceneDesc sceneDesc;
  81. sceneDesc.userData = this;
  82. // Set up default gravity.
  83. sceneDesc.gravity.set( mGravity.x, mGravity.y, mGravity.z );
  84. // The master scene is always on the CPU and is used
  85. // mostly for static shapes.
  86. sceneDesc.simType = NX_SIMULATION_SW; // [9/28/2009 Pat] Why is this software? Should be software server, hardware client?
  87. // Threading... seems to improve performance.
  88. //
  89. // TODO: I was getting random crashes in debug when doing
  90. // edit and continue... lets see if i still get them with
  91. // the threading disabled.
  92. //
  93. sceneDesc.flags |= NX_SF_ENABLE_MULTITHREAD | NX_SF_DISABLE_SCENE_MUTEX;
  94. sceneDesc.threadMask = 0xfffffffe;
  95. sceneDesc.internalThreadCount = PHYSICSMGR->getThreadCount();
  96. // Create the scene.
  97. mScene = gPhysicsSDK->createScene(sceneDesc);
  98. if ( !mScene )
  99. {
  100. Con::errorf( "PhysXWorld - %s world createScene returned a null scene!", isServer ? "Server" : "Client" );
  101. return false;
  102. }
  103. /*
  104. // Make note of what we've created.
  105. String simType = sceneDesc.simType == NX_SIMULATION_SW ? "software" : "hardware";
  106. String clientOrServer = this == isServer ? "server" : "client";
  107. Con::printf( "PhysXWorld::init() - Created %s %s simulation!",
  108. clientOrServer.c_str(),
  109. simType.c_str() );
  110. */
  111. mScene->setTiming( PhysicsMaxTimeStep, PhysicsMaxIterations, NX_TIMESTEP_FIXED );
  112. // TODO: Add dummy actor with scene name!
  113. // Set the global contact reporter.
  114. mConactReporter = new PxContactReporter();
  115. mScene->setUserContactReport( mConactReporter );
  116. // Set the global PxUserNotify
  117. mUserNotify = new PxUserNotify();
  118. mScene->setUserNotify( mUserNotify );
  119. // Now create the dynamic rigid body compartment which
  120. // can reside on the hardware when hardware is present.
  121. /*
  122. NxCompartmentDesc compartmentDesc;
  123. compartmentDesc.type = NX_SCT_RIGIDBODY;
  124. compartmentDesc.deviceCode = NX_DC_PPU_AUTO_ASSIGN;
  125. mRigidCompartment = mScene->createCompartment( compartmentDesc );
  126. if ( !mRigidCompartment )
  127. {
  128. Con::errorf( "PhysXWorld - Creation of rigid body compartment failed!" );
  129. return false;
  130. }
  131. */
  132. // Hook up the tick processing signals for advancing physics.
  133. //
  134. // First an overview of how physics and the game ticks
  135. // interact with each other.
  136. //
  137. // In Torque you normally tick the server and then the client
  138. // approximately every 32ms. So before the game tick we call
  139. // getPhysicsResults() to get the new physics state and call
  140. // tickPhysics() when the game tick is done to start processing
  141. // the next physics state. This means PhysX is happily doing
  142. // physics in a separate thread while we're doing rendering,
  143. // sound, input, networking, etc.
  144. //
  145. // Because your frame rate is rarely perfectly even you can
  146. // get cases where you may tick the server or the client
  147. // several times in a row. This happens most often in debug
  148. // mode, but can also happen in release.
  149. //
  150. // The simple implementation is to do a getPhysicsResults() and
  151. // tickPhysics() for each tick. But this very bad! It forces
  152. // immediate results from PhysX which blocks the primary thread
  153. // and further slows down processing. It leads to slower and
  154. // slower frame rates as the simulation is never able to catch
  155. // up to the current tick.
  156. //
  157. // The trick is processing physics once for backlogged ticks
  158. // with the total of the elapsed tick time. This is a huge
  159. // performance gain and keeps you from blocking on PhysX.
  160. //
  161. // This does have a side effect that when it occurs you'll get
  162. // ticks where the physics state hasn't advanced, but this beats
  163. // single digit frame rates.
  164. //
  165. AssertFatal( processList, "PxWorld::init() - We need a process list to create the world!" );
  166. mProcessList = processList;
  167. mProcessList->preTickSignal().notify( this, &PxWorld::getPhysicsResults );
  168. mProcessList->postTickSignal().notify( this, &PxWorld::tickPhysics, 1000.0f );
  169. // Setup the default material.
  170. NxMaterial *dmat = mScene->getMaterialFromIndex( 0 );
  171. dmat->setRestitution( 0.2f );
  172. dmat->setStaticFriction( 0.6f );
  173. dmat->setDynamicFriction( 0.4f );
  174. // Setup dominance groups.
  175. // Group 31 is for debris and other objects which can be pushed but cannot push back.
  176. // Group 0 is for everything else.
  177. NxConstraintDominance debrisDominance( 0.0f, 1.0f );
  178. mScene->setDominanceGroupPair( 0, 31, debrisDominance );
  179. return true;
  180. }
  181. void PxWorld::_destroy()
  182. {
  183. // Make sure the simulation is stopped!
  184. getPhysicsResults();
  185. _releaseQueues();
  186. #ifdef TORQUE_DEBUG
  187. U32 actorCount = mScene->getNbActors();
  188. U32 jointCount = mScene->getNbJoints();
  189. if ( actorCount != 0 || jointCount != 0 )
  190. {
  191. // Dump the names of any actors or joints that
  192. // were not released before the destruction of
  193. // this scene.
  194. for ( U32 i=0; i < actorCount; i++ )
  195. {
  196. const NxActor *actor = mScene->getActors()[i];
  197. Con::errorf( "Orphan NxActor - '%s'!", actor->getName() );
  198. }
  199. mScene->resetJointIterator();
  200. for ( ;; )
  201. {
  202. const NxJoint *joint = mScene->getNextJoint();
  203. if ( !joint )
  204. break;
  205. Con::errorf( "Orphan NxJoint - '%s'!", joint->getName() );
  206. }
  207. AssertFatal( false, "PhysXWorld::_destroy() - Some actors and/or joints were not released!" );
  208. }
  209. #endif // TORQUE_DEBUG
  210. //NxCloseCooking();
  211. // Release the tick processing signals.
  212. if ( mProcessList )
  213. {
  214. mProcessList->preTickSignal().remove( this, &PxWorld::getPhysicsResults );
  215. mProcessList->postTickSignal().remove( this, &PxWorld::tickPhysics );
  216. mProcessList = NULL;
  217. }
  218. // Destroy the scene.
  219. if ( mScene )
  220. {
  221. // Delete the contact reporter.
  222. mScene->setUserContactReport( NULL );
  223. SAFE_DELETE( mConactReporter );
  224. // First shut down threads... this makes it
  225. // safe to release the scene.
  226. mScene->shutdownWorkerThreads();
  227. // Release the scene.
  228. gPhysicsSDK->releaseScene( *mScene );
  229. mScene = NULL;
  230. }
  231. // Try to restart the sdk if we can.
  232. //restartSDK();
  233. }
  234. bool PxWorld::restartSDK( bool destroyOnly, PxWorld *clientWorld, PxWorld *serverWorld )
  235. {
  236. // If either the client or the server still exist
  237. // then we cannot reset the SDK.
  238. if ( clientWorld || serverWorld )
  239. return false;
  240. // Destroy the existing SDK.
  241. if ( gPhysicsSDK )
  242. {
  243. NXU::releasePersistentMemory();
  244. gPhysicsSDK->release();
  245. gPhysicsSDK = NULL;
  246. smCooking = NULL;
  247. SAFE_DELETE( smConsoleStream );
  248. }
  249. // If we're not supposed to restart... return.
  250. if ( destroyOnly )
  251. return true;
  252. smConsoleStream = new PxConsoleStream();
  253. NxPhysicsSDKDesc sdkDesc;
  254. sdkDesc.flags |= NX_SDKF_NO_HARDWARE; // [9/28/2009 Pat] Why is this disabled?
  255. NxSDKCreateError error;
  256. gPhysicsSDK = NxCreatePhysicsSDK( NX_PHYSICS_SDK_VERSION,
  257. NULL,
  258. smConsoleStream,
  259. sdkDesc,
  260. &error );
  261. if ( !gPhysicsSDK )
  262. {
  263. Con::errorf( "PhysX failed to initialize! Error code: %d", error );
  264. Platform::messageBox( Con::getVariable( "$appName" ),
  265. avar("PhysX could not be started!\r\n"
  266. "Please be sure you have the latest version of PhysX installed.\r\n"
  267. "Error Code: %d", error),
  268. MBOk, MIStop );
  269. Platform::forceShutdown( -1 );
  270. // We shouldn't get here, but this shuts up
  271. // source diagnostic tools.
  272. return false;
  273. }
  274. // Set the default skin width for all actors.
  275. gPhysicsSDK->setParameter( NX_SKIN_WIDTH, 0.01f );
  276. return true;
  277. }
  278. void PxWorld::tickPhysics( U32 elapsedMs )
  279. {
  280. if ( !mScene || !mIsEnabled )
  281. return;
  282. // Did we forget to call getPhysicsResults somewhere?
  283. AssertFatal( !mIsSimulating, "PhysXWorld::tickPhysics() - Already simulating!" );
  284. // The elapsed time should be non-zero and
  285. // a multiple of TickMs!
  286. AssertFatal( elapsedMs != 0 &&
  287. ( elapsedMs % TickMs ) == 0 , "PhysXWorld::tickPhysics() - Got bad elapsed time!" );
  288. PROFILE_SCOPE(PxWorld_TickPhysics);
  289. // Convert it to seconds.
  290. const F32 elapsedSec = (F32)elapsedMs * 0.001f;
  291. // For some reason this gets reset all the time
  292. // and it must be called before the simulate.
  293. mScene->setFilterOps( NX_FILTEROP_OR,
  294. NX_FILTEROP_OR,
  295. NX_FILTEROP_AND );
  296. mScene->setFilterBool( false );
  297. NxGroupsMask zeroMask;
  298. zeroMask.bits0=zeroMask.bits1=zeroMask.bits2=zeroMask.bits3=0;
  299. mScene->setFilterConstant0( zeroMask );
  300. mScene->setFilterConstant1( zeroMask );
  301. mScene->simulate( elapsedSec * mEditorTimeScale );
  302. mScene->flushStream();
  303. mIsSimulating = true;
  304. //Con::printf( "%s PhysXWorld::tickPhysics!", this == smClientWorld ? "Client" : "Server" );
  305. }
  306. void PxWorld::releaseWriteLocks()
  307. {
  308. PxWorld *world = dynamic_cast<PxWorld*>( PHYSICSMGR->getWorld( "server" ) );
  309. if ( world )
  310. world->releaseWriteLock();
  311. world = dynamic_cast<PxWorld*>( PHYSICSMGR->getWorld( "client" ) );
  312. if ( world )
  313. world->releaseWriteLock();
  314. }
  315. void PxWorld::releaseWriteLock()
  316. {
  317. if ( !mScene || !mIsSimulating )
  318. return;
  319. PROFILE_SCOPE(PxWorld_ReleaseWriteLock);
  320. // We use checkResults here to release the write lock
  321. // but we do not change the simulation flag or increment
  322. // the tick count... we may have gotten results, but the
  323. // simulation hasn't really ticked!
  324. mScene->checkResults( NX_RIGID_BODY_FINISHED, true );
  325. AssertFatal( mScene->isWritable(), "PhysXWorld::releaseWriteLock() - We should have been writable now!" );
  326. }
  327. void PxWorld::getPhysicsResults()
  328. {
  329. if ( !mScene || !mIsSimulating )
  330. return;
  331. PROFILE_SCOPE(PxWorld_GetPhysicsResults);
  332. // Get results from scene.
  333. mScene->fetchResults( NX_RIGID_BODY_FINISHED, true );
  334. mIsSimulating = false;
  335. mTickCount++;
  336. // Release any joints/actors that were waiting
  337. // for the scene to become writable.
  338. _releaseQueues();
  339. //Con::printf( "%s PhysXWorld::getPhysicsResults!", this == smClientWorld ? "Client" : "Server" );
  340. }
  341. NxMaterial* PxWorld::createMaterial( NxMaterialDesc &material )
  342. {
  343. if ( !mScene )
  344. return NULL;
  345. // We need the writelock to create a material!
  346. releaseWriteLock();
  347. NxMaterial *mat = mScene->createMaterial( material );
  348. if ( !mat )
  349. return NULL;
  350. return mat;
  351. }
  352. NxController* PxWorld::createController( NxControllerDesc &desc )
  353. {
  354. if ( !mScene )
  355. return NULL;
  356. // We need the writelock!
  357. releaseWriteLock();
  358. return mControllerManager->createController( mScene, desc );
  359. }
  360. void PxWorld::releaseActor( NxActor &actor )
  361. {
  362. AssertFatal( &actor.getScene() == mScene, "PhysXWorld::releaseActor() - Bad scene!" );
  363. // Clear the userdata.
  364. actor.userData = NULL;
  365. // actors are one of the few objects that are stable removing this way in physx 2.8
  366. if (mScene->isWritable() )
  367. {
  368. mScene->releaseActor( actor );
  369. }
  370. else
  371. {
  372. mReleaseActorQueue.push_back( &actor );
  373. }
  374. }
  375. void PxWorld::releaseMaterial( NxMaterial &mat )
  376. {
  377. AssertFatal( &mat.getScene() == mScene, "PhysXWorld::releaseMaterial() - Bad scene!" );
  378. // If the scene is not simulating then we have the
  379. // write lock and can safely delete it now.
  380. if ( !mIsSimulating )
  381. mScene->releaseMaterial( mat );
  382. else
  383. mReleaseMaterialQueue.push_back( &mat );
  384. }
  385. void PxWorld::releaseHeightField( NxHeightField &heightfield )
  386. {
  387. // Always delay releasing a heightfield, for whatever reason,
  388. // it causes lots of deadlock asserts if we do it here, even if
  389. // the scene "says" its writable.
  390. //
  391. // Actually this is probably because a heightfield is owned by the "sdk" and
  392. // not an individual scene so if either the client "or" server scene are
  393. // simulating it asserts, thats just my theory.
  394. mReleaseHeightFieldQueue.push_back( &heightfield );
  395. }
  396. void PxWorld::releaseJoint( NxJoint &joint )
  397. {
  398. AssertFatal( &joint.getScene() == mScene, "PhysXWorld::releaseJoint() - Bad scene!" );
  399. AssertFatal( !mReleaseJointQueue.contains( &joint ),
  400. "PhysXWorld::releaseJoint() - Joint already exists in the release queue!" );
  401. // Clear the userdata.
  402. joint.userData = NULL;
  403. // If the scene is not simulating then we have the
  404. // write lock and can safely delete it now.
  405. if ( !mIsSimulating )
  406. mScene->releaseJoint( joint );
  407. else
  408. mReleaseJointQueue.push_back( &joint );
  409. }
  410. void PxWorld::releaseCloth( NxCloth &cloth )
  411. {
  412. AssertFatal( &cloth.getScene() == mScene, "PhysXWorld::releaseCloth() - Bad scene!" );
  413. // Clear the userdata.
  414. cloth.userData = NULL;
  415. // If the scene is not simulating then we have the
  416. // write lock and can safely delete it now.
  417. if ( !mIsSimulating )
  418. mScene->releaseCloth( cloth );
  419. else
  420. mReleaseClothQueue.push_back( &cloth );
  421. }
  422. void PxWorld::releaseFluid( NxFluid &fluid )
  423. {
  424. AssertFatal( &fluid.getScene() == mScene, "PhysXWorld::releaseFluid() - Bad scene!" );
  425. // Clear the userdata.
  426. fluid.userData = NULL;
  427. // If the scene is not simulating then we have the
  428. // write lock and can safely delete it now.
  429. if ( !mIsSimulating )
  430. mScene->releaseFluid( fluid );
  431. else
  432. mReleaseFluidQueue.push_back( &fluid );
  433. }
  434. void PxWorld::releaseClothMesh( NxClothMesh &clothMesh )
  435. {
  436. // We need the writelock to release.
  437. releaseWriteLock();
  438. gPhysicsSDK->releaseClothMesh( clothMesh );
  439. }
  440. void PxWorld::releaseController( NxController &controller )
  441. {
  442. // TODO: This isn't safe to do with actors and
  443. // joints, so we probably need a queue like we
  444. // do for them.
  445. // We need the writelock to release.
  446. releaseWriteLock();
  447. mControllerManager->releaseController( controller );
  448. }
  449. void PxWorld::_releaseQueues()
  450. {
  451. AssertFatal( mScene, "PhysXWorld::_releaseQueues() - The scene is null!" );
  452. // We release joints still pending in the queue
  453. // first as they depend on the actors.
  454. for ( S32 i = 0; i < mReleaseJointQueue.size(); i++ )
  455. {
  456. NxJoint *currJoint = mReleaseJointQueue[i];
  457. mScene->releaseJoint( *currJoint );
  458. }
  459. // All the joints should be released, clear the queue.
  460. mReleaseJointQueue.clear();
  461. // Now release any actors still pending in the queue.
  462. bool staticChanged = false;
  463. for ( S32 i = 0; i < mReleaseActorQueue.size(); i++ )
  464. {
  465. NxActor *currActor = mReleaseActorQueue[i];
  466. staticChanged |= !currActor->isDynamic();
  467. mScene->releaseActor( *currActor );
  468. }
  469. // All the actors should be released, clear the queue.
  470. mReleaseActorQueue.clear();
  471. // Now release any materials still pending in the queue.
  472. for ( S32 i = 0; i < mReleaseMaterialQueue.size(); i++ )
  473. {
  474. NxMaterial *currMat = mReleaseMaterialQueue[i];
  475. mScene->releaseMaterial( *currMat );
  476. }
  477. // All the materials should be released, clear the queue.
  478. mReleaseMaterialQueue.clear();
  479. // Now release any cloth still pending in the queue.
  480. for ( S32 i = 0; i < mReleaseClothQueue.size(); i++ )
  481. {
  482. NxCloth *currCloth = mReleaseClothQueue[i];
  483. mScene->releaseCloth( *currCloth );
  484. }
  485. // All the actors should be released, clear the queue.
  486. mReleaseClothQueue.clear();
  487. // Release heightfields that don't still have references.
  488. for ( S32 i = 0; i < mReleaseHeightFieldQueue.size(); i++ )
  489. {
  490. NxHeightField *currHeightfield = mReleaseHeightFieldQueue[i];
  491. if ( currHeightfield->getReferenceCount() == 0 )
  492. {
  493. gPhysicsSDK->releaseHeightField( *currHeightfield );
  494. mReleaseHeightFieldQueue.erase_fast( i );
  495. i--;
  496. }
  497. }
  498. // Clear fluid queue
  499. for ( S32 i = 0; i < mReleaseFluidQueue.size(); i++ )
  500. {
  501. NxFluid *currFluid = mReleaseFluidQueue[i];
  502. mScene->releaseFluid( *currFluid );
  503. }
  504. mReleaseFluidQueue.clear();
  505. if ( staticChanged )
  506. mStaticChangedSignal.trigger();
  507. }
  508. void PxWorld::setEnabled( bool enabled )
  509. {
  510. mIsEnabled = enabled;
  511. if ( !mIsEnabled )
  512. getPhysicsResults();
  513. }
  514. bool PxWorld::initWorld( bool isServer, ProcessList *processList )
  515. {
  516. /* This stuff is handled outside.
  517. PxWorld* world = PxWorld::getWorld( isServer );
  518. if ( world )
  519. {
  520. Con::errorf( "PhysXWorld::initWorld - %s world already exists!", isServer ? "Server" : "Client" );
  521. return false;
  522. }
  523. */
  524. if ( !_init( isServer, processList ) )
  525. return false;
  526. return true;
  527. }
  528. void PxWorld::destroyWorld()
  529. {
  530. //PxWorld* world = PxWorld::getWorld( serverWorld );
  531. /*
  532. if ( !world )
  533. {
  534. Con::errorf( "PhysXWorld::destroyWorld - %s world already destroyed!", serverWorld ? "Server" : "Client" );
  535. return;
  536. }
  537. */
  538. //world->_destroy();
  539. //delete world;
  540. _destroy();
  541. }
  542. bool PxWorld::castRay( const Point3F &startPnt, const Point3F &endPnt, RayInfo *ri, const Point3F &impulse )
  543. {
  544. NxRay worldRay;
  545. worldRay.orig = pxCast<NxVec3>( startPnt );
  546. worldRay.dir = pxCast<NxVec3>( endPnt - startPnt );
  547. NxF32 maxDist = worldRay.dir.magnitude();
  548. worldRay.dir.normalize();
  549. U32 groups = 0xffffffff;
  550. groups &= ~( 1<<31 ); // No trigger shapes!
  551. NxRaycastHit hitInfo;
  552. NxShape *hitShape = mScene->raycastClosestShape( worldRay, NX_ALL_SHAPES, hitInfo, groups, maxDist );
  553. if ( !hitShape )
  554. return false;
  555. //if ( hitShape->userData != NULL )
  556. // return false;
  557. NxActor &actor = hitShape->getActor();
  558. PhysicsUserData *userData = PhysicsUserData::cast( actor.userData );
  559. if ( ri )
  560. {
  561. ri->object = ( userData != NULL ) ? userData->getObject() : NULL;
  562. // If we were passed a RayInfo, we can only return true signifying a collision
  563. // if we hit an object that actually has a torque object associated with it.
  564. //
  565. // In some ways this could be considered an error, either a physx object
  566. // has raycast-collision enabled that shouldn't or someone did not set
  567. // an object in this actor's userData.
  568. //
  569. if ( ri->object == NULL )
  570. return false;
  571. ri->distance = hitInfo.distance;
  572. ri->normal = pxCast<Point3F>( hitInfo.worldNormal );
  573. ri->point = pxCast<Point3F>( hitInfo.worldImpact );
  574. ri->t = maxDist / hitInfo.distance;
  575. }
  576. if ( impulse.isZero() ||
  577. !actor.isDynamic() ||
  578. actor.readBodyFlag( NX_BF_KINEMATIC ) )
  579. return true;
  580. NxVec3 force = pxCast<NxVec3>( impulse );//worldRay.dir * forceAmt;
  581. actor.addForceAtPos( force, hitInfo.worldImpact, NX_IMPULSE );
  582. return true;
  583. }
  584. PhysicsBody* PxWorld::castRay( const Point3F &start, const Point3F &end, U32 bodyTypes )
  585. {
  586. NxRay worldRay;
  587. worldRay.orig = pxCast<NxVec3>( start );
  588. worldRay.dir = pxCast<NxVec3>( end - start );
  589. F32 maxDist = worldRay.dir.normalize();
  590. U32 groups = 0xFFFFFFFF;
  591. if ( !( bodyTypes & BT_Player ) )
  592. groups &= ~( 1<<29 );
  593. // TODO: For now always skip triggers and debris,
  594. // but we should consider how game specifc this API
  595. // should be in the future.
  596. groups &= ~( 1<<31 ); // triggers
  597. groups &= ~( 1<<30 ); // debris
  598. U32 shapesType = 0;
  599. if ( bodyTypes & BT_Static )
  600. shapesType |= NX_STATIC_SHAPES;
  601. if ( bodyTypes & BT_Dynamic )
  602. shapesType |= NX_DYNAMIC_SHAPES;
  603. NxRaycastHit hitInfo;
  604. NxShape *hitShape = mScene->raycastClosestShape( worldRay, (NxShapesType)shapesType, hitInfo, groups, maxDist );
  605. if ( !hitShape )
  606. return NULL;
  607. NxActor &actor = hitShape->getActor();
  608. PhysicsUserData *userData = PhysicsUserData::cast( actor.userData );
  609. if ( !userData )
  610. return NULL;
  611. return userData->getBody();
  612. }
  613. void PxWorld::explosion( const Point3F &pos, F32 radius, F32 forceMagnitude )
  614. {
  615. // Find Actors at the position within the radius
  616. // and apply force to them.
  617. NxVec3 nxPos = pxCast<NxVec3>( pos );
  618. NxShape **shapes = (NxShape**)NxAlloca(10*sizeof(NxShape*));
  619. NxSphere worldSphere( nxPos, radius );
  620. NxU32 numHits = mScene->overlapSphereShapes( worldSphere, NX_ALL_SHAPES, 10, shapes, NULL );
  621. for ( NxU32 i = 0; i < numHits; i++ )
  622. {
  623. NxActor &actor = shapes[i]->getActor();
  624. bool dynamic = actor.isDynamic();
  625. if ( !dynamic )
  626. continue;
  627. bool kinematic = actor.readBodyFlag( NX_BF_KINEMATIC );
  628. if ( kinematic )
  629. continue;
  630. NxVec3 force = actor.getGlobalPosition() - nxPos;
  631. force.normalize();
  632. force *= forceMagnitude;
  633. actor.addForceAtPos( force, nxPos, NX_IMPULSE, true );
  634. }
  635. }
  636. static ColorI getDebugColor( NxU32 packed )
  637. {
  638. ColorI col;
  639. col.blue = (packed)&0xff;
  640. col.green = (packed>>8)&0xff;
  641. col.red = (packed>>16)&0xff;
  642. col.alpha = 255;
  643. return col;
  644. }
  645. void PxWorld::onDebugDraw( const SceneRenderState *state )
  646. {
  647. if ( !mScene )
  648. return;
  649. // We need the write lock to be able to request
  650. // the NxDebugRenderable object.
  651. releaseWriteLock();
  652. // TODO: We need to expose the different types of visualization
  653. // options to script and add a GUI for toggling them!
  654. gPhysicsSDK->setParameter( NX_VISUALIZATION_SCALE, 1.0f );
  655. //gPhysicsSDK->setParameter( NX_VISUALIZE_BODY_MASS_AXES, 0.0f );
  656. gPhysicsSDK->setParameter( NX_VISUALIZE_BODY_AXES, 1.0f );
  657. gPhysicsSDK->setParameter( NX_VISUALIZE_COLLISION_SHAPES, 1.0f );
  658. const NxDebugRenderable *data = mScene->getDebugRenderable();
  659. if ( !data )
  660. return;
  661. // Render points
  662. {
  663. NxU32 numPoints = data->getNbPoints();
  664. const NxDebugPoint *points = data->getPoints();
  665. PrimBuild::begin( GFXPointList, numPoints );
  666. while ( numPoints-- )
  667. {
  668. PrimBuild::color( getDebugColor(points->color) );
  669. PrimBuild::vertex3fv( &points->p.x );
  670. points++;
  671. }
  672. PrimBuild::end();
  673. }
  674. // Render lines
  675. {
  676. NxU32 numLines = data->getNbLines();
  677. const NxDebugLine *lines = data->getLines();
  678. PrimBuild::begin( GFXLineList, numLines * 2 );
  679. while ( numLines-- )
  680. {
  681. PrimBuild::color( getDebugColor( lines->color ) );
  682. PrimBuild::vertex3fv( &lines->p0.x );
  683. PrimBuild::vertex3fv( &lines->p1.x );
  684. lines++;
  685. }
  686. PrimBuild::end();
  687. }
  688. // Render triangles
  689. {
  690. NxU32 numTris = data->getNbTriangles();
  691. const NxDebugTriangle *triangles = data->getTriangles();
  692. PrimBuild::begin( GFXTriangleList, numTris * 3 );
  693. while ( numTris-- )
  694. {
  695. PrimBuild::color( getDebugColor( triangles->color ) );
  696. PrimBuild::vertex3fv( &triangles->p0.x );
  697. PrimBuild::vertex3fv( &triangles->p1.x );
  698. PrimBuild::vertex3fv( &triangles->p2.x );
  699. triangles++;
  700. }
  701. PrimBuild::end();
  702. }
  703. }