Advertisement
Guest User

Untitled

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