pxWorld.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877
  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. // If the scene is not simulating then we have the
  366. // write lock and can safely delete it now.
  367. if ( !mIsSimulating )
  368. {
  369. mScene->releaseActor( actor );
  370. }
  371. else
  372. {
  373. mReleaseActorQueue.push_back( &actor );
  374. }
  375. }
  376. void PxWorld::releaseMaterial( NxMaterial &mat )
  377. {
  378. AssertFatal( &mat.getScene() == mScene, "PhysXWorld::releaseMaterial() - Bad scene!" );
  379. // If the scene is not simulating then we have the
  380. // write lock and can safely delete it now.
  381. if ( !mIsSimulating )
  382. mScene->releaseMaterial( mat );
  383. else
  384. mReleaseMaterialQueue.push_back( &mat );
  385. }
  386. void PxWorld::releaseHeightField( NxHeightField &heightfield )
  387. {
  388. // Always delay releasing a heightfield, for whatever reason,
  389. // it causes lots of deadlock asserts if we do it here, even if
  390. // the scene "says" its writable.
  391. //
  392. // Actually this is probably because a heightfield is owned by the "sdk" and
  393. // not an individual scene so if either the client "or" server scene are
  394. // simulating it asserts, thats just my theory.
  395. mReleaseHeightFieldQueue.push_back( &heightfield );
  396. }
  397. void PxWorld::releaseJoint( NxJoint &joint )
  398. {
  399. AssertFatal( &joint.getScene() == mScene, "PhysXWorld::releaseJoint() - Bad scene!" );
  400. AssertFatal( !mReleaseJointQueue.contains( &joint ),
  401. "PhysXWorld::releaseJoint() - Joint already exists in the release queue!" );
  402. // Clear the userdata.
  403. joint.userData = NULL;
  404. // If the scene is not simulating then we have the
  405. // write lock and can safely delete it now.
  406. if ( !mIsSimulating )
  407. mScene->releaseJoint( joint );
  408. else
  409. mReleaseJointQueue.push_back( &joint );
  410. }
  411. void PxWorld::releaseCloth( NxCloth &cloth )
  412. {
  413. AssertFatal( &cloth.getScene() == mScene, "PhysXWorld::releaseCloth() - Bad scene!" );
  414. // Clear the userdata.
  415. cloth.userData = NULL;
  416. // If the scene is not simulating then we have the
  417. // write lock and can safely delete it now.
  418. if ( !mIsSimulating )
  419. mScene->releaseCloth( cloth );
  420. else
  421. mReleaseClothQueue.push_back( &cloth );
  422. }
  423. void PxWorld::releaseFluid( NxFluid &fluid )
  424. {
  425. AssertFatal( &fluid.getScene() == mScene, "PhysXWorld::releaseFluid() - Bad scene!" );
  426. // Clear the userdata.
  427. fluid.userData = NULL;
  428. // If the scene is not simulating then we have the
  429. // write lock and can safely delete it now.
  430. if ( !mIsSimulating )
  431. mScene->releaseFluid( fluid );
  432. else
  433. mReleaseFluidQueue.push_back( &fluid );
  434. }
  435. void PxWorld::releaseClothMesh( NxClothMesh &clothMesh )
  436. {
  437. // We need the writelock to release.
  438. releaseWriteLock();
  439. gPhysicsSDK->releaseClothMesh( clothMesh );
  440. }
  441. void PxWorld::releaseController( NxController &controller )
  442. {
  443. // TODO: This isn't safe to do with actors and
  444. // joints, so we probably need a queue like we
  445. // do for them.
  446. // We need the writelock to release.
  447. releaseWriteLock();
  448. mControllerManager->releaseController( controller );
  449. }
  450. void PxWorld::_releaseQueues()
  451. {
  452. AssertFatal( mScene, "PhysXWorld::_releaseQueues() - The scene is null!" );
  453. // We release joints still pending in the queue
  454. // first as they depend on the actors.
  455. for ( S32 i = 0; i < mReleaseJointQueue.size(); i++ )
  456. {
  457. NxJoint *currJoint = mReleaseJointQueue[i];
  458. mScene->releaseJoint( *currJoint );
  459. }
  460. // All the joints should be released, clear the queue.
  461. mReleaseJointQueue.clear();
  462. // Now release any actors still pending in the queue.
  463. bool staticChanged = false;
  464. for ( S32 i = 0; i < mReleaseActorQueue.size(); i++ )
  465. {
  466. NxActor *currActor = mReleaseActorQueue[i];
  467. staticChanged |= !currActor->isDynamic();
  468. mScene->releaseActor( *currActor );
  469. }
  470. // All the actors should be released, clear the queue.
  471. mReleaseActorQueue.clear();
  472. // Now release any materials still pending in the queue.
  473. for ( S32 i = 0; i < mReleaseMaterialQueue.size(); i++ )
  474. {
  475. NxMaterial *currMat = mReleaseMaterialQueue[i];
  476. mScene->releaseMaterial( *currMat );
  477. }
  478. // All the materials should be released, clear the queue.
  479. mReleaseMaterialQueue.clear();
  480. // Now release any cloth still pending in the queue.
  481. for ( S32 i = 0; i < mReleaseClothQueue.size(); i++ )
  482. {
  483. NxCloth *currCloth = mReleaseClothQueue[i];
  484. mScene->releaseCloth( *currCloth );
  485. }
  486. // All the actors should be released, clear the queue.
  487. mReleaseClothQueue.clear();
  488. // Release heightfields that don't still have references.
  489. for ( S32 i = 0; i < mReleaseHeightFieldQueue.size(); i++ )
  490. {
  491. NxHeightField *currHeightfield = mReleaseHeightFieldQueue[i];
  492. if ( currHeightfield->getReferenceCount() == 0 )
  493. {
  494. gPhysicsSDK->releaseHeightField( *currHeightfield );
  495. mReleaseHeightFieldQueue.erase_fast( i );
  496. i--;
  497. }
  498. }
  499. // Clear fluid queue
  500. for ( S32 i = 0; i < mReleaseFluidQueue.size(); i++ )
  501. {
  502. NxFluid *currFluid = mReleaseFluidQueue[i];
  503. mScene->releaseFluid( *currFluid );
  504. }
  505. mReleaseFluidQueue.clear();
  506. if ( staticChanged )
  507. mStaticChangedSignal.trigger();
  508. }
  509. void PxWorld::setEnabled( bool enabled )
  510. {
  511. mIsEnabled = enabled;
  512. if ( !mIsEnabled )
  513. getPhysicsResults();
  514. }
  515. bool PxWorld::initWorld( bool isServer, ProcessList *processList )
  516. {
  517. /* This stuff is handled outside.
  518. PxWorld* world = PxWorld::getWorld( isServer );
  519. if ( world )
  520. {
  521. Con::errorf( "PhysXWorld::initWorld - %s world already exists!", isServer ? "Server" : "Client" );
  522. return false;
  523. }
  524. */
  525. if ( !_init( isServer, processList ) )
  526. return false;
  527. return true;
  528. }
  529. void PxWorld::destroyWorld()
  530. {
  531. //PxWorld* world = PxWorld::getWorld( serverWorld );
  532. /*
  533. if ( !world )
  534. {
  535. Con::errorf( "PhysXWorld::destroyWorld - %s world already destroyed!", serverWorld ? "Server" : "Client" );
  536. return;
  537. }
  538. */
  539. //world->_destroy();
  540. //delete world;
  541. _destroy();
  542. }
  543. bool PxWorld::castRay( const Point3F &startPnt, const Point3F &endPnt, RayInfo *ri, const Point3F &impulse )
  544. {
  545. NxRay worldRay;
  546. worldRay.orig = pxCast<NxVec3>( startPnt );
  547. worldRay.dir = pxCast<NxVec3>( endPnt - startPnt );
  548. NxF32 maxDist = worldRay.dir.magnitude();
  549. worldRay.dir.normalize();
  550. U32 groups = 0xffffffff;
  551. groups &= ~( 1<<31 ); // No trigger shapes!
  552. NxRaycastHit hitInfo;
  553. NxShape *hitShape = mScene->raycastClosestShape( worldRay, NX_ALL_SHAPES, hitInfo, groups, maxDist );
  554. if ( !hitShape )
  555. return false;
  556. //if ( hitShape->userData != NULL )
  557. // return false;
  558. NxActor &actor = hitShape->getActor();
  559. PhysicsUserData *userData = PhysicsUserData::cast( actor.userData );
  560. if ( ri )
  561. {
  562. ri->object = ( userData != NULL ) ? userData->getObject() : NULL;
  563. // If we were passed a RayInfo, we can only return true signifying a collision
  564. // if we hit an object that actually has a torque object associated with it.
  565. //
  566. // In some ways this could be considered an error, either a physx object
  567. // has raycast-collision enabled that shouldn't or someone did not set
  568. // an object in this actor's userData.
  569. //
  570. if ( ri->object == NULL )
  571. return false;
  572. ri->distance = hitInfo.distance;
  573. ri->normal = pxCast<Point3F>( hitInfo.worldNormal );
  574. ri->point = pxCast<Point3F>( hitInfo.worldImpact );
  575. ri->t = maxDist / hitInfo.distance;
  576. }
  577. if ( impulse.isZero() ||
  578. !actor.isDynamic() ||
  579. actor.readBodyFlag( NX_BF_KINEMATIC ) )
  580. return true;
  581. NxVec3 force = pxCast<NxVec3>( impulse );//worldRay.dir * forceAmt;
  582. actor.addForceAtPos( force, hitInfo.worldImpact, NX_IMPULSE );
  583. return true;
  584. }
  585. PhysicsBody* PxWorld::castRay( const Point3F &start, const Point3F &end, U32 bodyTypes )
  586. {
  587. NxRay worldRay;
  588. worldRay.orig = pxCast<NxVec3>( start );
  589. worldRay.dir = pxCast<NxVec3>( end - start );
  590. F32 maxDist = worldRay.dir.normalize();
  591. U32 groups = 0xFFFFFFFF;
  592. if ( !( bodyTypes & BT_Player ) )
  593. groups &= ~( 1<<29 );
  594. // TODO: For now always skip triggers and debris,
  595. // but we should consider how game specifc this API
  596. // should be in the future.
  597. groups &= ~( 1<<31 ); // triggers
  598. groups &= ~( 1<<30 ); // debris
  599. U32 shapesType = 0;
  600. if ( bodyTypes & BT_Static )
  601. shapesType |= NX_STATIC_SHAPES;
  602. if ( bodyTypes & BT_Dynamic )
  603. shapesType |= NX_DYNAMIC_SHAPES;
  604. NxRaycastHit hitInfo;
  605. NxShape *hitShape = mScene->raycastClosestShape( worldRay, (NxShapesType)shapesType, hitInfo, groups, maxDist );
  606. if ( !hitShape )
  607. return NULL;
  608. NxActor &actor = hitShape->getActor();
  609. PhysicsUserData *userData = PhysicsUserData::cast( actor.userData );
  610. if ( !userData )
  611. return NULL;
  612. return userData->getBody();
  613. }
  614. void PxWorld::explosion( const Point3F &pos, F32 radius, F32 forceMagnitude )
  615. {
  616. // Find Actors at the position within the radius
  617. // and apply force to them.
  618. NxVec3 nxPos = pxCast<NxVec3>( pos );
  619. NxShape **shapes = (NxShape**)NxAlloca(10*sizeof(NxShape*));
  620. NxSphere worldSphere( nxPos, radius );
  621. NxU32 numHits = mScene->overlapSphereShapes( worldSphere, NX_ALL_SHAPES, 10, shapes, NULL );
  622. for ( NxU32 i = 0; i < numHits; i++ )
  623. {
  624. NxActor &actor = shapes[i]->getActor();
  625. bool dynamic = actor.isDynamic();
  626. if ( !dynamic )
  627. continue;
  628. bool kinematic = actor.readBodyFlag( NX_BF_KINEMATIC );
  629. if ( kinematic )
  630. continue;
  631. NxVec3 force = actor.getGlobalPosition() - nxPos;
  632. force.normalize();
  633. force *= forceMagnitude;
  634. actor.addForceAtPos( force, nxPos, NX_IMPULSE, true );
  635. }
  636. }
  637. static ColorI getDebugColor( NxU32 packed )
  638. {
  639. ColorI col;
  640. col.blue = (packed)&0xff;
  641. col.green = (packed>>8)&0xff;
  642. col.red = (packed>>16)&0xff;
  643. col.alpha = 255;
  644. return col;
  645. }
  646. void PxWorld::onDebugDraw( const SceneRenderState *state )
  647. {
  648. if ( !mScene )
  649. return;
  650. // We need the write lock to be able to request
  651. // the NxDebugRenderable object.
  652. releaseWriteLock();
  653. // TODO: We need to expose the different types of visualization
  654. // options to script and add a GUI for toggling them!
  655. gPhysicsSDK->setParameter( NX_VISUALIZATION_SCALE, 1.0f );
  656. //gPhysicsSDK->setParameter( NX_VISUALIZE_BODY_MASS_AXES, 0.0f );
  657. gPhysicsSDK->setParameter( NX_VISUALIZE_BODY_AXES, 1.0f );
  658. gPhysicsSDK->setParameter( NX_VISUALIZE_COLLISION_SHAPES, 1.0f );
  659. const NxDebugRenderable *data = mScene->getDebugRenderable();
  660. if ( !data )
  661. return;
  662. // Render points
  663. {
  664. NxU32 numPoints = data->getNbPoints();
  665. const NxDebugPoint *points = data->getPoints();
  666. PrimBuild::begin( GFXPointList, numPoints );
  667. while ( numPoints-- )
  668. {
  669. PrimBuild::color( getDebugColor(points->color) );
  670. PrimBuild::vertex3fv( &points->p.x );
  671. points++;
  672. }
  673. PrimBuild::end();
  674. }
  675. // Render lines
  676. {
  677. NxU32 numLines = data->getNbLines();
  678. const NxDebugLine *lines = data->getLines();
  679. PrimBuild::begin( GFXLineList, numLines * 2 );
  680. while ( numLines-- )
  681. {
  682. PrimBuild::color( getDebugColor( lines->color ) );
  683. PrimBuild::vertex3fv( &lines->p0.x );
  684. PrimBuild::vertex3fv( &lines->p1.x );
  685. lines++;
  686. }
  687. PrimBuild::end();
  688. }
  689. // Render triangles
  690. {
  691. NxU32 numTris = data->getNbTriangles();
  692. const NxDebugTriangle *triangles = data->getTriangles();
  693. PrimBuild::begin( GFXTriangleList, numTris * 3 );
  694. while ( numTris-- )
  695. {
  696. PrimBuild::color( getDebugColor( triangles->color ) );
  697. PrimBuild::vertex3fv( &triangles->p0.x );
  698. PrimBuild::vertex3fv( &triangles->p1.x );
  699. PrimBuild::vertex3fv( &triangles->p2.x );
  700. triangles++;
  701. }
  702. PrimBuild::end();
  703. }
  704. }