Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2228 lines
66 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "tier0/threadtools.h"
  9. #include "physics_constraint.h"
  10. #include "physics_spring.h"
  11. #include "physics_fluid.h"
  12. #include "physics_shadow.h"
  13. #include "physics_motioncontroller.h"
  14. #include "physics_vehicle.h"
  15. #include "physics_virtualmesh.h"
  16. #include "utlmultilist.h"
  17. #include "vphysics/constraints.h"
  18. #include "vphysics/vehicles.h"
  19. #include "vphysics/object_hash.h"
  20. #include "vphysics/performance.h"
  21. #include "vphysics/stats.h"
  22. #include "vphysics/player_controller.h"
  23. #include "vphysics_saverestore.h"
  24. #include "vphysics_internal.h"
  25. #include "ivu_linear_macros.hxx"
  26. #include "ivp_collision_filter.hxx"
  27. #include "ivp_listener_collision.hxx"
  28. #include "ivp_listener_object.hxx"
  29. #include "ivp_mindist.hxx"
  30. #include "ivp_friction.hxx"
  31. #include "ivp_anomaly_manager.hxx"
  32. #include "ivp_time.hxx"
  33. #include "ivp_listener_psi.hxx"
  34. #include "ivp_phantom.hxx"
  35. #include "ivp_range_manager.hxx"
  36. #include "ivp_clustering_visualizer.hxx"
  37. #include "ivp_mindist_intern.hxx"
  38. // memdbgon must be the last include file in a .cpp file!!!
  39. #include "tier0/memdbgon.h"
  40. IPhysicsObjectPairHash *CreateObjectPairHash();
  41. IVP_Synapse_Friction *GetOppositeSynapse( IVP_Synapse_Friction *pfriction )
  42. {
  43. IVP_Contact_Point *contact = pfriction->get_contact_point();
  44. IVP_Synapse_Friction *ptest = contact->get_synapse(0);
  45. if ( ptest == pfriction )
  46. {
  47. ptest = contact->get_synapse(1);
  48. }
  49. return ptest;
  50. }
  51. IVP_Real_Object *GetOppositeSynapseObject( IVP_Synapse_Friction *pfriction )
  52. {
  53. IVP_Synapse_Friction *opposite = GetOppositeSynapse( pfriction );
  54. return opposite->get_object();
  55. }
  56. // simple delete queue
  57. class IDeleteQueueItem
  58. {
  59. public:
  60. // Add a virtual destructor to silence the clang warning.
  61. // Note that this destructor doesn't actually do anything -- you
  62. // still have to use the Delete() then delete pattern.
  63. virtual ~IDeleteQueueItem() {}
  64. virtual void Delete() = 0;
  65. };
  66. template <typename T>
  67. class CDeleteProxy : public IDeleteQueueItem
  68. {
  69. public:
  70. CDeleteProxy(T *pItem) : m_pItem(pItem) {}
  71. virtual void Delete() { delete m_pItem; }
  72. private:
  73. T *m_pItem;
  74. };
  75. class CDeleteQueue
  76. {
  77. public:
  78. void Add( IDeleteQueueItem *pItem )
  79. {
  80. m_list.AddToTail( pItem );
  81. }
  82. template <typename T>
  83. void QueueForDelete( T *pItem )
  84. {
  85. Add( new CDeleteProxy<T>(pItem) );
  86. }
  87. void DeleteAll()
  88. {
  89. for ( int i = m_list.Count()-1; i >= 0; --i)
  90. {
  91. m_list[i]->Delete();
  92. delete m_list[i];
  93. }
  94. m_list.RemoveAll();
  95. }
  96. private:
  97. CUtlVector< IDeleteQueueItem * > m_list;
  98. };
  99. class CPhysicsCollisionData : public IPhysicsCollisionData
  100. {
  101. public:
  102. CPhysicsCollisionData( IVP_Contact_Situation *contact ) : m_pContact(contact) {}
  103. virtual void GetSurfaceNormal( Vector &out ) { ConvertDirectionToHL( m_pContact->surf_normal, out ); }
  104. virtual void GetContactPoint( Vector &out ) { ConvertPositionToHL( m_pContact->contact_point_ws, out ); }
  105. virtual void GetContactSpeed( Vector &out ) { ConvertPositionToHL( m_pContact->speed, out ); }
  106. const IVP_Contact_Situation *m_pContact;
  107. };
  108. class CPhysicsFrictionData : public IPhysicsCollisionData
  109. {
  110. public:
  111. CPhysicsFrictionData( IVP_Synapse_Friction *synapse, float sign ) : m_sign(sign)
  112. {
  113. m_pPoint = synapse->get_contact_point();
  114. m_pContact = NULL;
  115. }
  116. CPhysicsFrictionData( IVP_Event_Friction *pEvent ) : m_sign(1.0f)
  117. {
  118. m_pPoint = pEvent->friction_handle;
  119. m_pContact = pEvent->contact_situation;
  120. }
  121. virtual void GetSurfaceNormal( Vector &out )
  122. {
  123. if ( m_pContact )
  124. {
  125. ConvertDirectionToHL( m_pContact->surf_normal, out );
  126. }
  127. else
  128. {
  129. IVP_U_Float_Point normal;
  130. IVP_Contact_Point_API::get_surface_normal_ws(const_cast<IVP_Contact_Point *>(m_pPoint), &normal);
  131. ConvertDirectionToHL( normal, out );
  132. out *= m_sign;
  133. }
  134. }
  135. virtual void GetContactPoint( Vector &out )
  136. {
  137. if ( m_pContact )
  138. {
  139. ConvertPositionToHL( m_pContact->contact_point_ws, out );
  140. }
  141. else
  142. {
  143. ConvertPositionToHL( *m_pPoint->get_contact_point_ws(), out );
  144. }
  145. }
  146. virtual void GetContactSpeed( Vector &out )
  147. {
  148. if ( m_pContact )
  149. {
  150. ConvertPositionToHL( m_pContact->speed, out );
  151. }
  152. else
  153. {
  154. out.Init();
  155. }
  156. }
  157. private:
  158. const IVP_Contact_Point *m_pPoint;
  159. float m_sign;
  160. const IVP_Contact_Situation *m_pContact;
  161. };
  162. //-----------------------------------------------------------------------------
  163. // Purpose: Routes object event callbacks to game code
  164. //-----------------------------------------------------------------------------
  165. class CSleepObjects : public IVP_Listener_Object
  166. {
  167. public:
  168. CSleepObjects( void ) : IVP_Listener_Object()
  169. {
  170. m_pCallback = NULL;
  171. m_lastScrapeTime = 0.0f;
  172. }
  173. void SetHandler( IPhysicsObjectEvent *pListener )
  174. {
  175. m_pCallback = pListener;
  176. }
  177. void Remove( int index )
  178. {
  179. // fast remove preserves indices except for the last element (moved into the empty spot)
  180. m_activeObjects.FastRemove(index);
  181. // If this isn't the last element, shift its index over
  182. if ( index < m_activeObjects.Count() )
  183. {
  184. m_activeObjects[index]->SetActiveIndex( index );
  185. }
  186. }
  187. void DeleteObject( CPhysicsObject *pObject )
  188. {
  189. int index = pObject->GetActiveIndex();
  190. if ( index < m_activeObjects.Count() )
  191. {
  192. Assert( m_activeObjects[index] == pObject );
  193. Remove( index );
  194. pObject->SetActiveIndex( 0xFFFF );
  195. }
  196. else
  197. {
  198. Assert(index==0xFFFF);
  199. }
  200. }
  201. void event_object_deleted( IVP_Event_Object *pEvent )
  202. {
  203. CPhysicsObject *pObject = static_cast<CPhysicsObject *>(pEvent->real_object->client_data);
  204. if ( !pObject )
  205. return;
  206. DeleteObject(pObject);
  207. }
  208. void event_object_created( IVP_Event_Object *pEvent )
  209. {
  210. }
  211. void event_object_revived( IVP_Event_Object *pEvent )
  212. {
  213. CPhysicsObject *pObject = static_cast<CPhysicsObject *>(pEvent->real_object->client_data);
  214. if ( !pObject )
  215. return;
  216. int sleepState = pObject->GetSleepState();
  217. pObject->NotifyWake();
  218. // asleep, but already in active list
  219. if ( sleepState == OBJ_STARTSLEEP )
  220. return;
  221. // don't track static objects (like the world). That way we only track objects that will move
  222. if ( pObject->GetObject()->get_movement_state() != IVP_MT_STATIC )
  223. {
  224. Assert(pObject->GetActiveIndex()==0xFFFF);
  225. if ( pObject->GetActiveIndex()!=0xFFFF)
  226. return;
  227. int index = m_activeObjects.AddToTail( pObject );
  228. pObject->SetActiveIndex( index );
  229. }
  230. if ( m_pCallback )
  231. {
  232. m_pCallback->ObjectWake( pObject );
  233. }
  234. }
  235. void event_object_frozen( IVP_Event_Object *pEvent )
  236. {
  237. CPhysicsObject *pObject = static_cast<CPhysicsObject *>(pEvent->real_object->client_data);
  238. if ( !pObject )
  239. return;
  240. pObject->NotifySleep();
  241. if ( m_pCallback )
  242. {
  243. m_pCallback->ObjectSleep( pObject );
  244. }
  245. }
  246. //-----------------------------------------------------------------------------
  247. // Purpose: This walks the objects in the environment and generates friction events
  248. // for any scraping that is occurring.
  249. //-----------------------------------------------------------------------------
  250. void ProcessActiveObjects( IVP_Environment *pEnvironment, IPhysicsCollisionEvent *pEvent )
  251. {
  252. // FIXME: Is this correct? Shouldn't it do next PSI - lastScrape?
  253. float nextTime = pEnvironment->get_old_time_of_last_PSI().get_time();
  254. float delta = nextTime - m_lastScrapeTime;
  255. // only process if we have done a PSI
  256. if ( delta < pEnvironment->get_delta_PSI_time() )
  257. return;
  258. float t = 0.0f;
  259. if ( delta != 0.0f )
  260. {
  261. t = 1.0f / delta;
  262. }
  263. m_lastScrapeTime = nextTime;
  264. // UNDONE: This only calls friciton for one object in each pair.
  265. // UNDONE: Split energy in half and call for both objects?
  266. // UNDONE: Don't split/call if one object is static (like the world)?
  267. for ( int i = 0; i < m_activeObjects.Count(); i++ )
  268. {
  269. CPhysicsObject *pObject = m_activeObjects[i];
  270. IVP_Real_Object *ivpObject = pObject->GetObject();
  271. // no friction callbacks for this object
  272. if ( ! (pObject->CallbackFlags() & CALLBACK_GLOBAL_FRICTION) )
  273. continue;
  274. // UNDONE: IVP_Synapse_Friction is supposed to be opaque. Is there a better way
  275. // to implement this? Using the friction listener is much more work for the CPU
  276. // and considers sleeping objects.
  277. IVP_Synapse_Friction *pfriction = ivpObject->get_first_friction_synapse();
  278. while ( pfriction )
  279. {
  280. IVP_Contact_Point *contact = pfriction->get_contact_point();
  281. IVP_Synapse_Friction *pOpposite = GetOppositeSynapse( pfriction );
  282. IVP_Real_Object *pobj = pOpposite->get_object();
  283. CPhysicsObject *pScrape = (CPhysicsObject *)pobj->client_data;
  284. // friction callbacks for this object?
  285. if ( pScrape->CallbackFlags() & CALLBACK_GLOBAL_FRICTION )
  286. {
  287. float energy = IVP_Contact_Point_API::get_eliminated_energy( contact );
  288. if ( energy )
  289. {
  290. // scrape with an estimate for the energy per unit mass
  291. // This assumes that the game is interested in some measure of vibration
  292. // for sound effects. This also assumes that more massive objects require
  293. // more energy to vibrate.
  294. energy = energy * t * ivpObject->get_core()->get_inv_mass();
  295. if ( energy > 0.05f )
  296. {
  297. int hitSurface = pScrape->GetMaterialIndexInternal();
  298. int materialIndex = pOpposite->get_material_index();
  299. if ( materialIndex )
  300. {
  301. // use the per-triangle material if it has one
  302. hitSurface = physprops->RemapIVPMaterialIndex( materialIndex );
  303. }
  304. float sign = (pfriction == contact->get_synapse(0)) ? 1 : -1;
  305. CPhysicsFrictionData data(pfriction, sign);
  306. pEvent->Friction( pObject, ConvertEnergyToHL(energy), pObject->GetMaterialIndexInternal(), hitSurface, &data );
  307. }
  308. IVP_Contact_Point_API::reset_eliminated_energy( contact );
  309. }
  310. }
  311. pfriction = pfriction->get_next();
  312. }
  313. }
  314. }
  315. void DebugCheckContacts( IVP_Environment *pEnvironment )
  316. {
  317. IVP_Mindist_Manager *pManager = pEnvironment->get_mindist_manager();
  318. for( IVP_Mindist *mdist = pManager->exact_mindists; mdist != NULL; mdist = mdist->next )
  319. {
  320. IVP_Real_Object *obj[2];
  321. mdist->get_objects( obj );
  322. IVP_BOOL check = pEnvironment->get_collision_filter()->check_objects_for_collision_detection( obj[0], obj[1] );
  323. Assert(check);
  324. if ( !check )
  325. {
  326. Msg("Changed collision rules for %s vs. %s without calling recheck!\n", obj[0]->get_name(), obj[1]->get_name() );
  327. }
  328. }
  329. }
  330. int GetActiveObjectCount( void ) const
  331. {
  332. return m_activeObjects.Count();
  333. }
  334. void GetActiveObjects( IPhysicsObject **pOutputObjectList ) const
  335. {
  336. for ( int i = 0; i < m_activeObjects.Count(); i++ )
  337. {
  338. pOutputObjectList[i] = m_activeObjects[i];
  339. }
  340. }
  341. void UpdateSleepObjects( void )
  342. {
  343. int i;
  344. CUtlVector<CPhysicsObject *> sleepObjects;
  345. for ( i = 0; i < m_activeObjects.Count(); i++ )
  346. {
  347. CPhysicsObject *pObject = m_activeObjects[i];
  348. if ( pObject->GetSleepState() != OBJ_AWAKE )
  349. {
  350. sleepObjects.AddToTail( pObject );
  351. }
  352. }
  353. for ( i = sleepObjects.Count()-1; i >= 0; --i )
  354. {
  355. // put fully to sleep
  356. sleepObjects[i]->NotifySleep();
  357. // remove from the active list
  358. DeleteObject( sleepObjects[i] );
  359. }
  360. }
  361. private:
  362. CUtlVector<CPhysicsObject *> m_activeObjects;
  363. float m_lastScrapeTime;
  364. IPhysicsObjectEvent *m_pCallback;
  365. };
  366. class CEmptyCollisionListener : public IPhysicsCollisionEvent
  367. {
  368. public:
  369. virtual void PreCollision( vcollisionevent_t *pEvent ) {}
  370. virtual void PostCollision( vcollisionevent_t *pEvent ) {}
  371. // This is a scrape event. The object has scraped across another object consuming the indicated energy
  372. virtual void Friction( IPhysicsObject *pObject, float energy, int surfaceProps, int surfacePropsHit, IPhysicsCollisionData *pData ) {}
  373. virtual void StartTouch( IPhysicsObject *pObject1, IPhysicsObject *pObject2, IPhysicsCollisionData *pTouchData ) {}
  374. virtual void EndTouch( IPhysicsObject *pObject1, IPhysicsObject *pObject2, IPhysicsCollisionData *pTouchData ) {}
  375. virtual void FluidStartTouch( IPhysicsObject *pObject, IPhysicsFluidController *pFluid ) {}
  376. virtual void FluidEndTouch( IPhysicsObject *pObject, IPhysicsFluidController *pFluid ) {}
  377. virtual void ObjectEnterTrigger( IPhysicsObject *pTrigger, IPhysicsObject *pObject ) {}
  378. virtual void ObjectLeaveTrigger( IPhysicsObject *pTrigger, IPhysicsObject *pObject ) {}
  379. virtual void PostSimulationFrame() {}
  380. };
  381. CEmptyCollisionListener g_EmptyCollisionListener;
  382. #define ALL_COLLISION_FLAGS (IVP_LISTENER_COLLISION_CALLBACK_PRE_COLLISION|IVP_LISTENER_COLLISION_CALLBACK_POST_COLLISION|IVP_LISTENER_COLLISION_CALLBACK_FRICTION)
  383. //-----------------------------------------------------------------------------
  384. // Purpose: Routes collision event callbacks to game code
  385. //-----------------------------------------------------------------------------
  386. class CPhysicsListenerCollision : public IVP_Listener_Collision, public IVP_Listener_Phantom
  387. {
  388. public:
  389. CPhysicsListenerCollision();
  390. void SetHandler( IPhysicsCollisionEvent *pCallback )
  391. {
  392. m_pCallback = pCallback;
  393. }
  394. IPhysicsCollisionEvent *GetHandler() { return m_pCallback; }
  395. virtual void event_pre_collision( IVP_Event_Collision *pEvent )
  396. {
  397. m_event.isCollision = false;
  398. m_event.isShadowCollision = false;
  399. IVP_Contact_Situation *contact = pEvent->contact_situation;
  400. CPhysicsObject *pObject1 = static_cast<CPhysicsObject *>(contact->objects[0]->client_data);
  401. CPhysicsObject *pObject2 = static_cast<CPhysicsObject *>(contact->objects[1]->client_data);
  402. if ( !pObject1 || !pObject2 )
  403. return;
  404. unsigned int flags1 = pObject1->CallbackFlags();
  405. unsigned int flags2 = pObject2->CallbackFlags();
  406. m_event.isCollision = (flags1 & flags2 & CALLBACK_GLOBAL_COLLISION) ? true : false;
  407. // only call shadow collisions if one is shadow and the other isn't (hence the xor)
  408. // (if both are shadow, the collisions happen in AI - if neither, then no callback)
  409. m_event.isShadowCollision = ((flags1^flags2) & CALLBACK_SHADOW_COLLISION) ? true : false;
  410. m_event.pObjects[0] = pObject1;
  411. m_event.pObjects[1] = pObject2;
  412. m_event.deltaCollisionTime = pEvent->d_time_since_last_collision;
  413. // This timer must have been reset or something (constructor initializes time to -1000)
  414. // Fake the time to 50ms (resets happen often in rolling collisions for some reason)
  415. if ( m_event.deltaCollisionTime > 999 )
  416. {
  417. m_event.deltaCollisionTime = 1.0;
  418. }
  419. CPhysicsCollisionData data(contact);
  420. m_event.pInternalData = &data;
  421. // clear out any static object collisions unless flagged to keep them
  422. if ( contact->objects[0]->get_movement_state() == IVP_MT_STATIC )
  423. {
  424. // don't call global if disabled
  425. if ( !(flags2 & CALLBACK_GLOBAL_COLLIDE_STATIC) )
  426. {
  427. m_event.isCollision = false;
  428. }
  429. }
  430. if ( contact->objects[1]->get_movement_state() == IVP_MT_STATIC )
  431. {
  432. // don't call global if disabled
  433. if ( !(flags1 & CALLBACK_GLOBAL_COLLIDE_STATIC) )
  434. {
  435. m_event.isCollision = false;
  436. }
  437. }
  438. if ( !m_event.isCollision && !m_event.isShadowCollision )
  439. return;
  440. // look up surface props
  441. for ( int i = 0; i < 2; i++ )
  442. {
  443. m_event.surfaceProps[i] = physprops->GetIVPMaterialIndex( contact->materials[i] );
  444. if ( m_event.surfaceProps[i] < 0 )
  445. {
  446. m_event.surfaceProps[i] = m_event.pObjects[i]->GetMaterialIndex();
  447. }
  448. }
  449. m_pCallback->PreCollision( &m_event );
  450. }
  451. virtual void event_post_collision( IVP_Event_Collision *pEvent )
  452. {
  453. // didn't call preCollision, so don't call postCollision
  454. if ( !m_event.isCollision && !m_event.isShadowCollision )
  455. return;
  456. IVP_Contact_Situation *contact = pEvent->contact_situation;
  457. float collisionSpeed = contact->speed.dot_product(&contact->surf_normal);
  458. m_event.collisionSpeed = ConvertDistanceToHL( fabs(collisionSpeed) );
  459. CPhysicsCollisionData data(contact);
  460. m_event.pInternalData = &data;
  461. m_pCallback->PostCollision( &m_event );
  462. }
  463. virtual void event_collision_object_deleted( class IVP_Real_Object *)
  464. {
  465. // enable this in constructor
  466. }
  467. virtual void event_friction_created( IVP_Event_Friction *pEvent )
  468. {
  469. IVP_Contact_Situation *contact = pEvent->contact_situation;
  470. CPhysicsObject *pObject1 = static_cast<CPhysicsObject *>(contact->objects[0]->client_data);
  471. CPhysicsObject *pObject2 = static_cast<CPhysicsObject *>(contact->objects[1]->client_data);
  472. if ( !pObject1 || !pObject2 )
  473. return;
  474. unsigned int flags1 = pObject1->CallbackFlags();
  475. unsigned int flags2 = pObject2->CallbackFlags();
  476. unsigned int allflags = flags1|flags2;
  477. if ( !pObject1->IsStatic() || !pObject2->IsStatic() )
  478. {
  479. if ( !pObject1->HasTouchedDynamic() && pObject2->IsMoveable() )
  480. {
  481. pObject1->SetTouchedDynamic();
  482. }
  483. if ( !pObject2->HasTouchedDynamic() && pObject1->IsMoveable() )
  484. {
  485. pObject2->SetTouchedDynamic();
  486. }
  487. }
  488. bool calltouch = ( allflags & CALLBACK_GLOBAL_TOUCH ) ? true : false;
  489. if ( !calltouch )
  490. return;
  491. if ( pObject1->IsStatic() || pObject2->IsStatic() )
  492. {
  493. if ( !( allflags & CALLBACK_GLOBAL_TOUCH_STATIC ) )
  494. return;
  495. }
  496. CPhysicsFrictionData data(pEvent);
  497. m_pCallback->StartTouch( pObject1, pObject2, &data );
  498. }
  499. virtual void event_friction_deleted( IVP_Event_Friction *pEvent )
  500. {
  501. IVP_Contact_Situation *contact = pEvent->contact_situation;
  502. CPhysicsObject *pObject1 = static_cast<CPhysicsObject *>(contact->objects[0]->client_data);
  503. CPhysicsObject *pObject2 = static_cast<CPhysicsObject *>(contact->objects[1]->client_data);
  504. if ( !pObject1 || !pObject2 )
  505. return;
  506. unsigned int flags1 = pObject1->CallbackFlags();
  507. unsigned int flags2 = pObject2->CallbackFlags();
  508. unsigned int allflags = flags1|flags2;
  509. bool calltouch = ( allflags & CALLBACK_GLOBAL_TOUCH ) ? true : false;
  510. if ( !calltouch )
  511. return;
  512. if ( pObject1->IsStatic() || pObject2->IsStatic() )
  513. {
  514. if ( !( allflags & CALLBACK_GLOBAL_TOUCH_STATIC ) )
  515. return;
  516. }
  517. CPhysicsFrictionData data(pEvent);
  518. m_pCallback->EndTouch( pObject1, pObject2, &data );
  519. }
  520. virtual void event_friction_pair_created( class IVP_Friction_Core_Pair *pair );
  521. virtual void event_friction_pair_deleted( class IVP_Friction_Core_Pair *pair );
  522. virtual void mindist_entered_volume( class IVP_Controller_Phantom *controller,class IVP_Mindist_Base *mindist ) {}
  523. virtual void mindist_left_volume(class IVP_Controller_Phantom *controller, class IVP_Mindist_Base *mindist) {}
  524. virtual void core_entered_volume( IVP_Controller_Phantom *controller, IVP_Core *pCore )
  525. {
  526. CPhysicsFluidController *pFluid = static_cast<CPhysicsFluidController *>( controller->client_data );
  527. IVP_Real_Object *pivp = pCore->objects.element_at(0);
  528. CPhysicsObject *pObject = static_cast<CPhysicsObject *>(pivp->client_data);
  529. if ( !pObject )
  530. return;
  531. if ( pFluid )
  532. {
  533. if ( pObject && (pObject->CallbackFlags() & CALLBACK_FLUID_TOUCH) )
  534. {
  535. m_pCallback->FluidStartTouch( pObject, pFluid );
  536. }
  537. }
  538. else
  539. {
  540. // must be a trigger
  541. IVP_Real_Object *pTriggerIVP = controller->get_object();
  542. CPhysicsObject *pTrigger = static_cast<CPhysicsObject *>(pTriggerIVP->client_data);
  543. if ( pTrigger )
  544. {
  545. m_pCallback->ObjectEnterTrigger( pTrigger, pObject );
  546. }
  547. }
  548. }
  549. virtual void core_left_volume( IVP_Controller_Phantom *controller, IVP_Core *pCore )
  550. {
  551. CPhysicsFluidController *pFluid = static_cast<CPhysicsFluidController *>( controller->client_data );
  552. IVP_Real_Object *pivp = pCore->objects.element_at(0);
  553. CPhysicsObject *pObject = static_cast<CPhysicsObject *>(pivp->client_data);
  554. if ( !pObject )
  555. return;
  556. if ( pFluid )
  557. {
  558. if ( pObject && (pObject->CallbackFlags() & CALLBACK_FLUID_TOUCH) )
  559. {
  560. m_pCallback->FluidEndTouch( pObject, pFluid );
  561. }
  562. }
  563. else
  564. {
  565. // must be a trigger
  566. IVP_Real_Object *pTriggerIVP = controller->get_object();
  567. CPhysicsObject *pTrigger = static_cast<CPhysicsObject *>(pTriggerIVP->client_data);
  568. if ( pTrigger )
  569. {
  570. m_pCallback->ObjectLeaveTrigger( pTrigger, pObject );
  571. }
  572. }
  573. }
  574. void phantom_is_going_to_be_deleted_event(class IVP_Controller_Phantom *controller) {}
  575. void EventPSI( CPhysicsEnvironment *pEnvironment )
  576. {
  577. m_pCallback->PostSimulationFrame();
  578. UpdatePairListPSI( pEnvironment );
  579. }
  580. private:
  581. struct corepair_t
  582. {
  583. corepair_t() {}
  584. corepair_t( IVP_Friction_Core_Pair *pair )
  585. {
  586. int index = ( pair->objs[0] < pair->objs[1] ) ? 0 : 1;
  587. core0 = pair->objs[index];
  588. core1 = pair->objs[!index];
  589. lastImpactTime= pair->last_impact_time_pair;
  590. }
  591. IVP_Core *core0;
  592. IVP_Core *core1;
  593. IVP_Time lastImpactTime;
  594. };
  595. static bool CorePairLessFunc( const corepair_t &lhs, const corepair_t &rhs )
  596. {
  597. if ( lhs.core0 != rhs.core0 )
  598. return ( lhs.core0 < rhs.core0 );
  599. else
  600. return ( lhs.core1 < rhs.core1 );
  601. }
  602. void UpdatePairListPSI( CPhysicsEnvironment *pEnvironment )
  603. {
  604. unsigned short index = m_pairList.FirstInorder();
  605. IVP_Time currentTime = pEnvironment->GetIVPEnvironment()->get_current_time();
  606. while ( m_pairList.IsValidIndex(index) )
  607. {
  608. unsigned short next = m_pairList.NextInorder( index );
  609. corepair_t &test = m_pairList.Element(index);
  610. // only keep 1 seconds worth of data
  611. if ( (currentTime - test.lastImpactTime) > 1.0 )
  612. {
  613. m_pairList.RemoveAt( index );
  614. }
  615. index = next;
  616. }
  617. }
  618. CUtlRBTree<corepair_t> m_pairList;
  619. float m_pairListOldestTime;
  620. IPhysicsCollisionEvent *m_pCallback;
  621. vcollisionevent_t m_event;
  622. };
  623. CPhysicsListenerCollision::CPhysicsListenerCollision() : IVP_Listener_Collision( ALL_COLLISION_FLAGS ), m_pCallback(&g_EmptyCollisionListener)
  624. {
  625. m_pairList.SetLessFunc( CorePairLessFunc );
  626. }
  627. void CPhysicsListenerCollision::event_friction_pair_created( IVP_Friction_Core_Pair *pair )
  628. {
  629. corepair_t test(pair);
  630. unsigned short index = m_pairList.Find( test );
  631. if ( m_pairList.IsValidIndex( index ) )
  632. {
  633. corepair_t &save = m_pairList.Element(index);
  634. // found this one already, update the time
  635. if ( save.lastImpactTime.get_seconds() > pair->last_impact_time_pair.get_seconds() )
  636. {
  637. pair->last_impact_time_pair = save.lastImpactTime;
  638. }
  639. else
  640. {
  641. save.lastImpactTime = pair->last_impact_time_pair;
  642. }
  643. }
  644. else
  645. {
  646. if ( m_pairList.Count() < 16 )
  647. {
  648. m_pairList.Insert( test );
  649. }
  650. }
  651. }
  652. void CPhysicsListenerCollision::event_friction_pair_deleted( IVP_Friction_Core_Pair *pair )
  653. {
  654. corepair_t test(pair);
  655. unsigned short index = m_pairList.Find( test );
  656. if ( m_pairList.IsValidIndex( index ) )
  657. {
  658. corepair_t &save = m_pairList.Element(index);
  659. // found this one already, update the time
  660. if ( save.lastImpactTime.get_seconds() < pair->last_impact_time_pair.get_seconds() )
  661. {
  662. save.lastImpactTime = pair->last_impact_time_pair;
  663. }
  664. }
  665. else
  666. {
  667. if ( m_pairList.Count() < 16 )
  668. {
  669. m_pairList.Insert( test );
  670. }
  671. }
  672. }
  673. #if IVP_ENABLE_VISUALIZER
  674. class CCollisionVisualizer : public IVP_Clustering_Visualizer_Shortrange_Callback, public IVP_Clustering_Visualizer_Longrange_Callback
  675. {
  676. IVPhysicsDebugOverlay *m_pDebug;
  677. public:
  678. CCollisionVisualizer(IVPhysicsDebugOverlay *pDebug) { m_pDebug = pDebug;}
  679. void visualize_request()
  680. {
  681. Vector origin, extents;
  682. ConvertPositionToHL( center, origin );
  683. float hlradius = ConvertDistanceToHL( radius);
  684. extents.Init( hlradius, hlradius, hlradius );
  685. m_pDebug->AddBoxOverlay( origin, -extents, extents, vec3_angle, 0, 255, 0, 32, 0.5f);
  686. }
  687. virtual void devisualize_request() {}
  688. virtual void enable() {}
  689. virtual void disable() {}
  690. void visualize_request_for_node()
  691. {
  692. Vector origin, extents;
  693. ConvertPositionToHL( position, origin );
  694. ConvertPositionToHL( box_extents, extents );
  695. Vector boxOrigin, boxExtents;
  696. CPhysicsObject *pObject0 = static_cast<CPhysicsObject *>(node_object->client_data);
  697. pObject0->LocalToWorld( boxOrigin, origin );
  698. QAngle angles;
  699. pObject0->GetPosition( NULL, &angles );
  700. m_pDebug->AddBoxOverlay( boxOrigin, -extents, extents, angles, 255, 255, 0, 0, 0.5f);
  701. }
  702. void visualize_request_for_intruder_radius()
  703. {
  704. Vector origin, extents;
  705. ConvertPositionToHL( position, origin );
  706. float hlradius = ConvertDistanceToHL( sphere_radius );
  707. extents.Init( hlradius, hlradius, hlradius );
  708. m_pDebug->AddBoxOverlay( origin, -extents, extents, vec3_angle, 0, 0, 255, 32, 0.25f);
  709. }
  710. };
  711. #endif
  712. class CCollisionSolver : public IVP_Collision_Filter, public IVP_Anomaly_Manager
  713. {
  714. public:
  715. CCollisionSolver( void ) : IVP_Anomaly_Manager(IVP_FALSE) { m_pSolver = NULL; }
  716. void SetHandler( IPhysicsCollisionSolver *pSolver ) { m_pSolver = pSolver; }
  717. // IVP_Collision_Filter
  718. IVP_BOOL check_objects_for_collision_detection(IVP_Real_Object *ivp0, IVP_Real_Object *ivp1)
  719. {
  720. if ( m_pSolver )
  721. {
  722. CPhysicsObject *pObject0 = static_cast<CPhysicsObject *>(ivp0->client_data);
  723. CPhysicsObject *pObject1 = static_cast<CPhysicsObject *>(ivp1->client_data);
  724. if ( pObject0 && pObject1 )
  725. {
  726. if ( (pObject0->CallbackFlags() & CALLBACK_ENABLING_COLLISION) && (pObject1->CallbackFlags() & CALLBACK_MARKED_FOR_DELETE) )
  727. return IVP_FALSE;
  728. if ( (pObject1->CallbackFlags() & CALLBACK_ENABLING_COLLISION) && (pObject0->CallbackFlags() & CALLBACK_MARKED_FOR_DELETE) )
  729. return IVP_FALSE;
  730. if ( !m_pSolver->ShouldCollide( pObject0, pObject1, pObject0->GetGameData(), pObject1->GetGameData() ) )
  731. return IVP_FALSE;
  732. }
  733. }
  734. return IVP_TRUE;
  735. }
  736. void environment_will_be_deleted(IVP_Environment *) {}
  737. // IVP_Anomaly_Manager
  738. virtual void inter_penetration( IVP_Mindist *mindist,IVP_Real_Object *ivp0, IVP_Real_Object *ivp1, IVP_DOUBLE speedChange)
  739. {
  740. if ( m_pSolver )
  741. {
  742. // UNDONE: project current velocity onto rescue velocity instead
  743. // This will cause escapes to be slow - which is probably a good
  744. // thing. That's probably a better heuristic than only rescuing once
  745. // per PSI!
  746. CPhysicsObject *pObject0 = static_cast<CPhysicsObject *>(ivp0->client_data);
  747. CPhysicsObject *pObject1 = static_cast<CPhysicsObject *>(ivp1->client_data);
  748. if ( pObject0 && pObject1 )
  749. {
  750. if ( (pObject0->CallbackFlags() & CALLBACK_MARKED_FOR_DELETE) ||
  751. (pObject1->CallbackFlags() & CALLBACK_MARKED_FOR_DELETE) )
  752. return;
  753. // moveable object pair?
  754. if ( pObject0->IsMoveable() && pObject1->IsMoveable() )
  755. {
  756. // only push each pair apart once per PSI
  757. if ( CheckObjPair( ivp0, ivp1 ) )
  758. return;
  759. }
  760. IVP_Environment *env = ivp0->get_environment();
  761. float deltaTime = env->get_delta_PSI_time();
  762. if ( !m_pSolver->ShouldSolvePenetration( pObject0, pObject1, pObject0->GetGameData(), pObject1->GetGameData(), deltaTime ) )
  763. return;
  764. }
  765. else
  766. {
  767. return;
  768. }
  769. }
  770. IVP_Anomaly_Manager::inter_penetration( mindist, ivp0, ivp1, speedChange );
  771. }
  772. // return true if object should be temp. freezed
  773. virtual IVP_BOOL max_collisions_exceeded_check_freezing(IVP_Anomaly_Limits *, IVP_Core *pCore)
  774. {
  775. if ( m_pSolver )
  776. {
  777. CPhysicsObject *pObject = static_cast<CPhysicsObject *>(pCore->objects.element_at(0)->client_data);
  778. return m_pSolver->ShouldFreezeObject( pObject ) ? IVP_TRUE : IVP_FALSE;
  779. }
  780. return IVP_TRUE;
  781. }
  782. // return number of additional checks to do this psi
  783. virtual int max_collision_checks_exceeded( int totalChecks )
  784. {
  785. if ( m_pSolver )
  786. {
  787. return m_pSolver->AdditionalCollisionChecksThisTick( totalChecks );
  788. }
  789. return 0;
  790. }
  791. void max_velocity_exceeded(IVP_Anomaly_Limits *al, IVP_Core *pCore, IVP_U_Float_Point *velocity_in_out)
  792. {
  793. CPhysicsObject *pObject = static_cast<CPhysicsObject *>(pCore->objects.element_at(0)->client_data);
  794. if ( pObject->GetShadowController() != NULL )
  795. return;
  796. IVP_Anomaly_Manager::max_velocity_exceeded(al, pCore, velocity_in_out);
  797. }
  798. IVP_BOOL max_contacts_exceeded_check_freezing( IVP_Core **pCoreList, int coreCount )
  799. {
  800. CUtlVector<IPhysicsObject *> list;
  801. list.EnsureCapacity(coreCount);
  802. for ( int i = 0; i < coreCount; i++ )
  803. {
  804. IVP_Core *pCore = pCoreList[i];
  805. CPhysicsObject *pObject = static_cast<CPhysicsObject *>(pCore->objects.element_at(0)->client_data);
  806. list.AddToTail(pObject);
  807. }
  808. return m_pSolver->ShouldFreezeContacts( list.Base(), list.Count() ) ? IVP_TRUE : IVP_FALSE;
  809. }
  810. public:
  811. void EventPSI( CPhysicsEnvironment * )
  812. {
  813. m_rescue.RemoveAll();
  814. }
  815. private:
  816. struct realobjectpair_t
  817. {
  818. IVP_Real_Object *pObj0;
  819. IVP_Real_Object *pObj1;
  820. inline bool operator==( const realobjectpair_t &src ) const
  821. {
  822. return (pObj0 == src.pObj0) && (pObj1 == src.pObj1);
  823. }
  824. };
  825. // basically each moveable object pair gets 1 rescue per PSI
  826. // UNDONE: Add a counter to do more?
  827. bool CheckObjPair( IVP_Real_Object *pObj0, IVP_Real_Object *pObj1 )
  828. {
  829. realobjectpair_t tmp;
  830. tmp.pObj0 = pObj0 < pObj1 ? pObj0 : pObj1;
  831. tmp.pObj1 = pObj0 > pObj1 ? pObj0 : pObj1;
  832. if ( m_rescue.Find( tmp ) != m_rescue.InvalidIndex() )
  833. return true;
  834. m_rescue.AddToTail( tmp );
  835. return false;
  836. }
  837. private:
  838. IPhysicsCollisionSolver *m_pSolver;
  839. // UNDONE: Linear search? should be small, but switch to rb tree if this ever gets large
  840. CUtlVector<realobjectpair_t> m_rescue;
  841. #if IVP_ENABLE_VISUALIZER
  842. public:
  843. CCollisionVisualizer *pVisualizer;
  844. #endif
  845. };
  846. class CPhysicsListenerConstraint : public IVP_Listener_Constraint
  847. {
  848. public:
  849. CPhysicsListenerConstraint()
  850. {
  851. m_pCallback = NULL;
  852. }
  853. void SetHandler( IPhysicsConstraintEvent *pHandler )
  854. {
  855. m_pCallback = pHandler;
  856. }
  857. void event_constraint_broken( IVP_Constraint *pConstraint )
  858. {
  859. // IVP_Constraint is not allowed, something is broken
  860. Assert(0);
  861. }
  862. void event_constraint_broken( hk_Breakable_Constraint *pConstraint )
  863. {
  864. if ( m_pCallback )
  865. {
  866. IPhysicsConstraint *pObj = GetClientDataForHkConstraint( pConstraint );
  867. m_pCallback->ConstraintBroken( pObj );
  868. }
  869. }
  870. void event_constraint_broken( IPhysicsConstraint *pConstraint )
  871. {
  872. if ( m_pCallback )
  873. {
  874. m_pCallback->ConstraintBroken(pConstraint);
  875. }
  876. }
  877. private:
  878. IPhysicsConstraintEvent *m_pCallback;
  879. };
  880. #define AIR_DENSITY 2
  881. class CDragController : public IVP_Controller_Independent
  882. {
  883. public:
  884. CDragController( void )
  885. {
  886. m_airDensity = AIR_DENSITY;
  887. }
  888. virtual ~CDragController( void ) {}
  889. virtual void do_simulation_controller(IVP_Event_Sim *event,IVP_U_Vector<IVP_Core> *core_list)
  890. {
  891. int i;
  892. for( i = core_list->len()-1; i >=0; i--)
  893. {
  894. IVP_Core *pCore = core_list->element_at(i);
  895. IVP_Real_Object *pivp = pCore->objects.element_at(0);
  896. CPhysicsObject *pPhys = static_cast<CPhysicsObject *>(pivp->client_data);
  897. float dragForce = -0.5 * pPhys->GetDragInDirection( pCore->speed ) * m_airDensity * event->delta_time;
  898. if ( dragForce < -1.0f )
  899. dragForce = -1.0f;
  900. if ( dragForce < 0 )
  901. {
  902. IVP_U_Float_Point dragVelocity;
  903. dragVelocity.set_multiple( &pCore->speed, dragForce );
  904. pCore->speed.add( &dragVelocity );
  905. }
  906. float angDragForce = -pPhys->GetAngularDragInDirection( pCore->rot_speed ) * m_airDensity * event->delta_time;
  907. if ( angDragForce < -1.0f )
  908. angDragForce = -1.0f;
  909. if ( angDragForce < 0 )
  910. {
  911. IVP_U_Float_Point angDragVelocity;
  912. angDragVelocity.set_multiple( &pCore->rot_speed, angDragForce );
  913. pCore->rot_speed.add( &angDragVelocity );
  914. }
  915. }
  916. }
  917. virtual const char *get_controller_name() { return "vphysics:drag"; }
  918. virtual IVP_CONTROLLER_PRIORITY get_controller_priority()
  919. {
  920. return IVP_CP_MOTION;
  921. }
  922. float GetAirDensity() const { return m_airDensity; }
  923. void SetAirDensity( float density ) { m_airDensity = density; }
  924. private:
  925. float m_airDensity;
  926. };
  927. //
  928. // Default implementation of the debug overlay interface so that we never return NULL from GetDebugOverlay.
  929. //
  930. class CVPhysicsDebugOverlay : public IVPhysicsDebugOverlay
  931. {
  932. public:
  933. virtual void AddEntityTextOverlay(int ent_index, int line_offset, float duration, int r, int g, int b, int a, const char *format, ...) {}
  934. virtual void AddBoxOverlay(const Vector& origin, const Vector& mins, const Vector& max, QAngle const& orientation, int r, int g, int b, int a, float duration) {}
  935. virtual void AddTriangleOverlay(const Vector& p1, const Vector& p2, const Vector& p3, int r, int g, int b, int a, bool noDepthTest, float duration) {}
  936. virtual void AddLineOverlay(const Vector& origin, const Vector& dest, int r, int g, int b,bool noDepthTest, float duration) {}
  937. virtual void AddTextOverlay(const Vector& origin, float duration, const char *format, ...) {}
  938. virtual void AddTextOverlay(const Vector& origin, int line_offset, float duration, const char *format, ...) {}
  939. virtual void AddScreenTextOverlay(float flXPos, float flYPos,float flDuration, int r, int g, int b, int a, const char *text) {}
  940. virtual void AddSweptBoxOverlay(const Vector& start, const Vector& end, const Vector& mins, const Vector& max, const QAngle & angles, int r, int g, int b, int a, float flDuration) {}
  941. virtual void AddTextOverlayRGB(const Vector& origin, int line_offset, float duration, float r, float g, float b, float alpha, const char *format, ...) {}
  942. };
  943. static CVPhysicsDebugOverlay s_DefaultDebugOverlay;
  944. CPhysicsEnvironment::CPhysicsEnvironment( void )
  945. // assume that these lists will have at least one object
  946. {
  947. // set this to true to force the
  948. m_deleteQuick = false;
  949. m_queueDeleteObject = false;
  950. m_inSimulation = false;
  951. m_fixedTimestep = true; // try to simulate using fixed timesteps
  952. m_enableConstraintNotify = false;
  953. // build a default environment
  954. IVP_Environment_Manager *env_manager;
  955. env_manager = IVP_Environment_Manager::get_environment_manager();
  956. IVP_Application_Environment appl_env;
  957. m_pCollisionSolver = new CCollisionSolver;
  958. appl_env.collision_filter = m_pCollisionSolver;
  959. appl_env.material_manager = physprops->GetIVPManager();
  960. appl_env.anomaly_manager = m_pCollisionSolver;
  961. // UNDONE: This would save another 45K of RAM on xbox, test perf
  962. // if ( IsXbox() )
  963. // {
  964. // appl_env.n_cache_object = 128;
  965. // }
  966. BEGIN_IVP_ALLOCATION();
  967. m_pPhysEnv = env_manager->create_environment( &appl_env, "JAY", 0xBEEF );
  968. END_IVP_ALLOCATION();
  969. // UNDONE: Revisit brush/terrain/object shrinking and tune this number to something larger
  970. // UNDONE: Expose this to callers, also via physcollision
  971. m_pPhysEnv->set_global_collision_tolerance( ConvertDistanceToIVP( g_PhysicsUnits.globalCollisionTolerance - 1e-4f ) ); // just under 1/4 inch tolerance
  972. m_pSleepEvents = new CSleepObjects;
  973. m_pDeleteQueue = new CDeleteQueue;
  974. BEGIN_IVP_ALLOCATION();
  975. m_pPhysEnv->add_listener_object_global( m_pSleepEvents );
  976. END_IVP_ALLOCATION();
  977. m_pCollisionListener = new CPhysicsListenerCollision;
  978. BEGIN_IVP_ALLOCATION();
  979. m_pPhysEnv->add_listener_collision_global( m_pCollisionListener );
  980. END_IVP_ALLOCATION();
  981. m_pConstraintListener = new CPhysicsListenerConstraint;
  982. BEGIN_IVP_ALLOCATION();
  983. m_pPhysEnv->add_listener_constraint_global( m_pConstraintListener );
  984. END_IVP_ALLOCATION();
  985. m_pDragController = new CDragController;
  986. physics_performanceparams_t perf;
  987. perf.Defaults();
  988. SetPerformanceSettings( &perf );
  989. m_pPhysEnv->client_data = (void *)this;
  990. m_lastObjectThisTick = 0;
  991. }
  992. CPhysicsEnvironment::~CPhysicsEnvironment( void )
  993. {
  994. // no callbacks during shutdown
  995. SetCollisionSolver( NULL );
  996. m_pPhysEnv->remove_listener_object_global( m_pSleepEvents );
  997. // don't bother waking up other objects as we clear them out
  998. SetQuickDelete( true );
  999. // delete/remove the listeners
  1000. m_pPhysEnv->remove_listener_collision_global( m_pCollisionListener );
  1001. delete m_pCollisionListener;
  1002. m_pPhysEnv->remove_listener_constraint_global( m_pConstraintListener );
  1003. delete m_pConstraintListener;
  1004. // Clean out the list of physics objects
  1005. for ( int i = m_objects.Count()-1; i >= 0; --i )
  1006. {
  1007. CPhysicsObject *pObject = static_cast<CPhysicsObject *>(m_objects[i]);
  1008. PhantomRemove( pObject );
  1009. delete pObject;
  1010. }
  1011. m_objects.RemoveAll();
  1012. ClearDeadObjects();
  1013. // Clean out the list of fluids
  1014. m_fluids.PurgeAndDeleteElements();
  1015. delete m_pSleepEvents;
  1016. delete m_pDragController;
  1017. delete m_pPhysEnv;
  1018. delete m_pDeleteQueue;
  1019. // must be deleted after the environment (calls back in destructor)
  1020. delete m_pCollisionSolver;
  1021. }
  1022. IPhysicsCollisionEvent *CPhysicsEnvironment::GetCollisionEventHandler()
  1023. {
  1024. return m_pCollisionListener->GetHandler();
  1025. }
  1026. void CPhysicsEnvironment::NotifyConstraintDisabled( IPhysicsConstraint *pConstraint )
  1027. {
  1028. if ( m_enableConstraintNotify )
  1029. {
  1030. m_pConstraintListener->event_constraint_broken( pConstraint );
  1031. }
  1032. }
  1033. void CPhysicsEnvironment::DebugCheckContacts(void)
  1034. {
  1035. if ( m_pSleepEvents )
  1036. {
  1037. m_pSleepEvents->DebugCheckContacts( m_pPhysEnv );
  1038. }
  1039. }
  1040. void CPhysicsEnvironment::SetDebugOverlay( CreateInterfaceFn debugOverlayFactory )
  1041. {
  1042. m_pDebugOverlay = NULL;
  1043. if (debugOverlayFactory)
  1044. {
  1045. m_pDebugOverlay = ( IVPhysicsDebugOverlay * )debugOverlayFactory( VPHYSICS_DEBUG_OVERLAY_INTERFACE_VERSION, NULL );
  1046. }
  1047. if (!m_pDebugOverlay)
  1048. {
  1049. m_pDebugOverlay = &s_DefaultDebugOverlay;
  1050. }
  1051. #if IVP_ENABLE_VISUALIZER
  1052. m_pCollisionSolver->pVisualizer = new CCollisionVisualizer( m_pDebugOverlay );
  1053. INSTALL_SHORTRANGE_CALLBACK(m_pCollisionSolver->pVisualizer);
  1054. INSTALL_LONGRANGE_CALLBACK(m_pCollisionSolver->pVisualizer);
  1055. #endif
  1056. }
  1057. IVPhysicsDebugOverlay *CPhysicsEnvironment::GetDebugOverlay( void )
  1058. {
  1059. return m_pDebugOverlay;
  1060. }
  1061. void CPhysicsEnvironment::SetGravity( const Vector& gravityVector )
  1062. {
  1063. IVP_U_Point gravity;
  1064. ConvertPositionToIVP( gravityVector, gravity );
  1065. m_pPhysEnv->set_gravity( &gravity );
  1066. // BUGBUG: global collision tolerance has a constant that depends on gravity.
  1067. m_pPhysEnv->set_global_collision_tolerance( m_pPhysEnv->get_global_collision_tolerance(), gravity.real_length() );
  1068. DevMsg(1,"Set Gravity %.1f (%.3f tolerance)\n", gravityVector.Length(), IVP2HL(m_pPhysEnv->get_global_collision_tolerance()) );
  1069. }
  1070. void CPhysicsEnvironment::GetGravity( Vector *pGravityVector ) const
  1071. {
  1072. const IVP_U_Point *gravity = m_pPhysEnv->get_gravity();
  1073. ConvertPositionToHL( *gravity, *pGravityVector );
  1074. }
  1075. IPhysicsObject *CPhysicsEnvironment::CreatePolyObject( const CPhysCollide *pCollisionModel, int materialIndex, const Vector& position, const QAngle& angles, objectparams_t *pParams )
  1076. {
  1077. IPhysicsObject *pObject = ::CreatePhysicsObject( this, pCollisionModel, materialIndex, position, angles, pParams, false );
  1078. if ( pObject )
  1079. {
  1080. m_objects.AddToTail( pObject );
  1081. }
  1082. return pObject;
  1083. }
  1084. IPhysicsObject *CPhysicsEnvironment::CreatePolyObjectStatic( const CPhysCollide *pCollisionModel, int materialIndex, const Vector& position, const QAngle& angles, objectparams_t *pParams )
  1085. {
  1086. IPhysicsObject *pObject = ::CreatePhysicsObject( this, pCollisionModel, materialIndex, position, angles, pParams, true );
  1087. if ( pObject )
  1088. {
  1089. m_objects.AddToTail( pObject );
  1090. }
  1091. return pObject;
  1092. }
  1093. unsigned int CPhysicsEnvironment::GetObjectSerializeSize( IPhysicsObject *pObject ) const
  1094. {
  1095. return sizeof(vphysics_save_cphysicsobject_t);
  1096. }
  1097. void CPhysicsEnvironment::SerializeObjectToBuffer( IPhysicsObject *pObject, unsigned char *pBuffer, unsigned int bufferSize )
  1098. {
  1099. CPhysicsObject *pPhysics = static_cast<CPhysicsObject *>(pObject);
  1100. if ( bufferSize >= sizeof(vphysics_save_cphysicsobject_t))
  1101. {
  1102. vphysics_save_cphysicsobject_t *pTemplate = reinterpret_cast<vphysics_save_cphysicsobject_t *>(pBuffer);
  1103. pPhysics->WriteToTemplate( *pTemplate );
  1104. }
  1105. }
  1106. IPhysicsObject *CPhysicsEnvironment::UnserializeObjectFromBuffer( void *pGameData, unsigned char *pBuffer, unsigned int bufferSize, bool enableCollisions )
  1107. {
  1108. IPhysicsObject *pObject = ::CreateObjectFromBuffer( this, pGameData, pBuffer, bufferSize, enableCollisions );
  1109. if ( pObject )
  1110. {
  1111. m_objects.AddToTail( pObject );
  1112. }
  1113. return pObject;
  1114. }
  1115. const IPhysicsObject **CPhysicsEnvironment::GetObjectList( int *pOutputObjectCount ) const
  1116. {
  1117. int iCount = m_objects.Count();
  1118. if( pOutputObjectCount )
  1119. *pOutputObjectCount = iCount;
  1120. if( iCount )
  1121. return (const IPhysicsObject **)m_objects.Base();
  1122. else
  1123. return NULL;
  1124. }
  1125. extern void ControlPhysicsShadowControllerAttachment_Silent( IPhysicsShadowController *pController, IVP_Real_Object *pivp, bool bAttach );
  1126. extern void ControlPhysicsPlayerControllerAttachment_Silent( IPhysicsPlayerController *pController, IVP_Real_Object *pivp, bool bAttach );
  1127. bool CPhysicsEnvironment::TransferObject( IPhysicsObject *pObject, IPhysicsEnvironment *pDestinationEnvironment )
  1128. {
  1129. int iIndex = m_objects.Find( pObject );
  1130. if( iIndex == -1 || (pObject->GetCallbackFlags() & CALLBACK_MARKED_FOR_DELETE ) )
  1131. return false;
  1132. CPhysicsObject *pPhysics = static_cast<CPhysicsObject *>(pObject);
  1133. //pPhysics->Wake();
  1134. //pPhysics->NotifyWake();
  1135. void *pGameData = pObject->GetGameData();
  1136. //Find any controllers attached to this object
  1137. IPhysicsShadowController *pController = pObject->GetShadowController();
  1138. IPhysicsPlayerController *pPlayerController = NULL;
  1139. if( (pObject->GetCallbackFlags() & CALLBACK_IS_PLAYER_CONTROLLER) != 0 )
  1140. {
  1141. pPlayerController = FindPlayerController( pObject );
  1142. }
  1143. //temporarily (and silently) detach any physics controllers we found because destroying the object would destroy them
  1144. if( pController )
  1145. {
  1146. //detach the controller from the object
  1147. ((CPhysicsObject *)pObject)->m_pShadow = NULL;
  1148. IVP_Real_Object *pivp = ((CPhysicsObject *)pObject)->GetObject();
  1149. ControlPhysicsShadowControllerAttachment_Silent( pController, pivp, false );
  1150. }
  1151. else if( pPlayerController )
  1152. {
  1153. RemovePlayerController( pPlayerController );
  1154. pObject->SetCallbackFlags( pObject->GetCallbackFlags() & ~CALLBACK_IS_PLAYER_CONTROLLER );
  1155. IVP_Real_Object *pivp = ((CPhysicsObject *)pObject)->GetObject();
  1156. ControlPhysicsPlayerControllerAttachment_Silent( pPlayerController, pivp, false );
  1157. }
  1158. //templatize the object
  1159. vphysics_save_cphysicsobject_t objectTemplate;
  1160. memset( &objectTemplate, 0, sizeof( vphysics_save_cphysicsobject_t ) );
  1161. pPhysics->WriteToTemplate( objectTemplate );
  1162. //these should be detached already
  1163. Assert( objectTemplate.pShadow == NULL );
  1164. Assert( objectTemplate.hasShadowController == false );
  1165. //destroy the existing version of the object
  1166. m_objects.FastRemove( iIndex );
  1167. pPhysics->ForceSilentDelete();
  1168. m_pSleepEvents->DeleteObject( pPhysics );
  1169. pPhysics->CPhysicsObject::~CPhysicsObject();
  1170. //now recreate in place in the destination environment
  1171. CPhysicsEnvironment *pDest = static_cast<CPhysicsEnvironment *>(pDestinationEnvironment);
  1172. CreateObjectFromBuffer_UseExistingMemory( pDest, pGameData, (unsigned char *)&objectTemplate, sizeof(objectTemplate), pPhysics );
  1173. pDest->m_objects.AddToTail( pObject );
  1174. //even if this is going to sleep in a second, put it active right away to fix some object hitching problems
  1175. pPhysics->Wake();
  1176. pPhysics->NotifyWake();
  1177. /*int iActiveIndex = pDest->m_pSleepEvents->m_activeObjects.AddToTail( pPhysics );
  1178. pPhysics->SetActiveIndex( iActiveIndex );*/
  1179. pDest->m_pPhysEnv->force_psi_on_next_simulation(); //avoids an object pause
  1180. if( pController )
  1181. {
  1182. //re-attach the controller to the new object
  1183. ((CPhysicsObject *)pObject)->m_pShadow = pController;
  1184. IVP_Real_Object *pivp = ((CPhysicsObject *)pObject)->GetObject();
  1185. ControlPhysicsShadowControllerAttachment_Silent( pController, pivp, true );
  1186. }
  1187. else if( pPlayerController )
  1188. {
  1189. IVP_Real_Object *pivp = ((CPhysicsObject *)pObject)->GetObject();
  1190. pObject->SetCallbackFlags( pObject->GetCallbackFlags() | CALLBACK_IS_PLAYER_CONTROLLER );
  1191. ControlPhysicsPlayerControllerAttachment_Silent( pPlayerController, pivp, true );
  1192. pDest->AddPlayerController( pPlayerController );
  1193. }
  1194. return true;
  1195. }
  1196. IPhysicsSpring *CPhysicsEnvironment::CreateSpring( IPhysicsObject *pObjectStart, IPhysicsObject *pObjectEnd, springparams_t *pParams )
  1197. {
  1198. return ::CreateSpring( m_pPhysEnv, static_cast<CPhysicsObject *>(pObjectStart), static_cast<CPhysicsObject *>(pObjectEnd), pParams );
  1199. }
  1200. IPhysicsFluidController *CPhysicsEnvironment::CreateFluidController( IPhysicsObject *pFluidObject, fluidparams_t *pParams )
  1201. {
  1202. CPhysicsFluidController *pFluid = ::CreateFluidController( m_pPhysEnv, static_cast<CPhysicsObject *>(pFluidObject), pParams );
  1203. m_fluids.AddToTail( pFluid );
  1204. return pFluid;
  1205. }
  1206. IPhysicsConstraint *CPhysicsEnvironment::CreateRagdollConstraint( IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_ragdollparams_t &ragdoll )
  1207. {
  1208. return ::CreateRagdollConstraint( m_pPhysEnv, (CPhysicsObject *)pReferenceObject, (CPhysicsObject *)pAttachedObject, pGroup, ragdoll );
  1209. }
  1210. IPhysicsConstraint *CPhysicsEnvironment::CreateHingeConstraint( IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_hingeparams_t &hinge )
  1211. {
  1212. constraint_limitedhingeparams_t limitedhinge(hinge);
  1213. return ::CreateHingeConstraint( m_pPhysEnv, (CPhysicsObject *)pReferenceObject, (CPhysicsObject *)pAttachedObject, pGroup, limitedhinge );
  1214. }
  1215. IPhysicsConstraint *CPhysicsEnvironment::CreateLimitedHingeConstraint( IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_limitedhingeparams_t &hinge )
  1216. {
  1217. return ::CreateHingeConstraint( m_pPhysEnv, (CPhysicsObject *)pReferenceObject, (CPhysicsObject *)pAttachedObject, pGroup, hinge );
  1218. }
  1219. IPhysicsConstraint *CPhysicsEnvironment::CreateFixedConstraint( IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_fixedparams_t &fixed )
  1220. {
  1221. return ::CreateFixedConstraint( m_pPhysEnv, (CPhysicsObject *)pReferenceObject, (CPhysicsObject *)pAttachedObject, pGroup, fixed );
  1222. }
  1223. IPhysicsConstraint *CPhysicsEnvironment::CreateSlidingConstraint( IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_slidingparams_t &sliding )
  1224. {
  1225. return ::CreateSlidingConstraint( m_pPhysEnv, (CPhysicsObject *)pReferenceObject, (CPhysicsObject *)pAttachedObject, pGroup, sliding );
  1226. }
  1227. IPhysicsConstraint *CPhysicsEnvironment::CreateBallsocketConstraint( IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_ballsocketparams_t &ballsocket )
  1228. {
  1229. return ::CreateBallsocketConstraint( m_pPhysEnv, (CPhysicsObject *)pReferenceObject, (CPhysicsObject *)pAttachedObject, pGroup, ballsocket );
  1230. }
  1231. IPhysicsConstraint *CPhysicsEnvironment::CreatePulleyConstraint( IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_pulleyparams_t &pulley )
  1232. {
  1233. return ::CreatePulleyConstraint( m_pPhysEnv, (CPhysicsObject *)pReferenceObject, (CPhysicsObject *)pAttachedObject, pGroup, pulley );
  1234. }
  1235. IPhysicsConstraint *CPhysicsEnvironment::CreateLengthConstraint( IPhysicsObject *pReferenceObject, IPhysicsObject *pAttachedObject, IPhysicsConstraintGroup *pGroup, const constraint_lengthparams_t &length )
  1236. {
  1237. return ::CreateLengthConstraint( m_pPhysEnv, (CPhysicsObject *)pReferenceObject, (CPhysicsObject *)pAttachedObject, pGroup, length );
  1238. }
  1239. IPhysicsConstraintGroup *CPhysicsEnvironment::CreateConstraintGroup( const constraint_groupparams_t &group )
  1240. {
  1241. return CreatePhysicsConstraintGroup( m_pPhysEnv, group );
  1242. }
  1243. void CPhysicsEnvironment::Simulate( float deltaTime )
  1244. {
  1245. LOCAL_THREAD_LOCK();
  1246. if ( !m_pPhysEnv )
  1247. return;
  1248. ClearDeadObjects();
  1249. #if DEBUG_CHECK_CONTATCTS_AUTO
  1250. m_pSleepEvents->DebugCheckContacts( m_pPhysEnv );
  1251. #endif
  1252. // save this to catch objects deleted without being simulated
  1253. m_lastObjectThisTick = m_objects.Count()-1;
  1254. // stop updating objects that went to sleep during the previous frame.
  1255. m_pSleepEvents->UpdateSleepObjects();
  1256. // Trap interrupts and clock changes
  1257. // don't simulate less than .1 ms
  1258. if ( deltaTime <= 1.0 && deltaTime > 0.0001 )
  1259. {
  1260. if ( deltaTime > 0.1 )
  1261. {
  1262. deltaTime = 0.1f;
  1263. }
  1264. m_pCollisionSolver->EventPSI( this );
  1265. m_pCollisionListener->EventPSI( this );
  1266. m_inSimulation = true;
  1267. BEGIN_IVP_ALLOCATION();
  1268. if ( !m_fixedTimestep || deltaTime != m_pPhysEnv->get_delta_PSI_time() )
  1269. {
  1270. m_fixedTimestep = false;
  1271. m_pPhysEnv->simulate_dtime( deltaTime );
  1272. }
  1273. else
  1274. {
  1275. m_pPhysEnv->simulate_time_step();
  1276. }
  1277. END_IVP_ALLOCATION();
  1278. m_inSimulation = false;
  1279. }
  1280. // If the queue is disabled, it's only used during simulation.
  1281. // Flush it as soon as possible (which is now)
  1282. if ( !m_queueDeleteObject )
  1283. {
  1284. ClearDeadObjects();
  1285. }
  1286. if ( m_pCollisionListener->GetHandler() )
  1287. {
  1288. m_pSleepEvents->ProcessActiveObjects( m_pPhysEnv, m_pCollisionListener->GetHandler() );
  1289. }
  1290. VISUALIZE_COLLISIONS();
  1291. VirtualMeshPSI();
  1292. GetNextFrameTime();
  1293. }
  1294. void CPhysicsEnvironment::ResetSimulationClock()
  1295. {
  1296. // UNDONE: You'd think that all of this would make the system deterministic, but
  1297. // it doesn't.
  1298. extern void SeedRandomGenerators();
  1299. m_pPhysEnv->reset_time();
  1300. m_pPhysEnv->get_time_manager()->env_set_current_time( m_pPhysEnv, IVP_Time(0) );
  1301. m_pPhysEnv->reset_time();
  1302. m_fixedTimestep = true;
  1303. SeedRandomGenerators();
  1304. }
  1305. float CPhysicsEnvironment::GetSimulationTimestep( void ) const
  1306. {
  1307. return m_pPhysEnv->get_delta_PSI_time();
  1308. }
  1309. void CPhysicsEnvironment::SetSimulationTimestep( float timestep )
  1310. {
  1311. m_pPhysEnv->set_delta_PSI_time( timestep );
  1312. }
  1313. float CPhysicsEnvironment::GetSimulationTime( void ) const
  1314. {
  1315. return (float)m_pPhysEnv->get_current_time().get_time();
  1316. }
  1317. float CPhysicsEnvironment::GetNextFrameTime( void ) const
  1318. {
  1319. return (float)m_pPhysEnv->get_next_PSI_time().get_time();
  1320. }
  1321. // true if currently running the simulator (i.e. in a callback during physenv->Simulate())
  1322. bool CPhysicsEnvironment::IsInSimulation( void ) const
  1323. {
  1324. return m_inSimulation;
  1325. }
  1326. void CPhysicsEnvironment::DestroyObject( IPhysicsObject *pObject )
  1327. {
  1328. if ( !pObject )
  1329. {
  1330. DevMsg("Deleted NULL vphysics object\n");
  1331. return;
  1332. }
  1333. // search from the end because we usually delete the most recent objects during run time
  1334. int index = -1;
  1335. for ( int i = m_objects.Count(); --i >= 0; )
  1336. {
  1337. if ( m_objects[i] == pObject )
  1338. {
  1339. index = i;
  1340. break;
  1341. }
  1342. }
  1343. if ( index != -1 )
  1344. {
  1345. m_objects.FastRemove( index );
  1346. }
  1347. else
  1348. {
  1349. DevMsg(1,"error deleting physics object\n");
  1350. CPhysicsObject *pPhysics = static_cast<CPhysicsObject *>(pObject);
  1351. if ( pPhysics->GetCallbackFlags() & CALLBACK_MARKED_FOR_DELETE )
  1352. {
  1353. // deleted twice
  1354. Assert(0);
  1355. return;
  1356. }
  1357. // bad ptr?
  1358. Assert(0);
  1359. return;
  1360. }
  1361. CPhysicsObject *pPhysics = static_cast<CPhysicsObject *>(pObject);
  1362. // add this flag so we can optimize some cases
  1363. pPhysics->AddCallbackFlags( CALLBACK_MARKED_FOR_DELETE );
  1364. // was created/destroyed without simulating. No need to wake the neighbors!
  1365. if ( index > m_lastObjectThisTick )
  1366. {
  1367. pPhysics->ForceSilentDelete();
  1368. }
  1369. if ( m_inSimulation || m_queueDeleteObject )
  1370. {
  1371. // don't delete while simulating
  1372. m_deadObjects.AddToTail( pObject );
  1373. }
  1374. else
  1375. {
  1376. m_pSleepEvents->DeleteObject( pPhysics );
  1377. delete pObject;
  1378. }
  1379. }
  1380. void CPhysicsEnvironment::DestroySpring( IPhysicsSpring *pSpring )
  1381. {
  1382. delete pSpring;
  1383. }
  1384. void CPhysicsEnvironment::DestroyFluidController( IPhysicsFluidController *pFluid )
  1385. {
  1386. m_fluids.FindAndRemove( (CPhysicsFluidController *)pFluid );
  1387. delete pFluid;
  1388. }
  1389. void CPhysicsEnvironment::DestroyConstraint( IPhysicsConstraint *pConstraint )
  1390. {
  1391. if ( !m_deleteQuick && pConstraint )
  1392. {
  1393. IPhysicsObject *pObj0 = pConstraint->GetReferenceObject();
  1394. if ( pObj0 )
  1395. {
  1396. pObj0->Wake();
  1397. }
  1398. IPhysicsObject *pObj1 = pConstraint->GetAttachedObject();
  1399. if ( pObj1 )
  1400. {
  1401. pObj1->Wake();
  1402. }
  1403. }
  1404. if ( m_inSimulation )
  1405. {
  1406. pConstraint->Deactivate();
  1407. m_pDeleteQueue->QueueForDelete( pConstraint );
  1408. }
  1409. else
  1410. {
  1411. delete pConstraint;
  1412. }
  1413. }
  1414. void CPhysicsEnvironment::DestroyConstraintGroup( IPhysicsConstraintGroup *pGroup )
  1415. {
  1416. delete pGroup;
  1417. }
  1418. void CPhysicsEnvironment::TraceBox( trace_t *ptr, const Vector &mins, const Vector &maxs, const Vector &start, const Vector &end )
  1419. {
  1420. // UNDONE: Need this?
  1421. }
  1422. void CPhysicsEnvironment::SetCollisionSolver( IPhysicsCollisionSolver *pSolver )
  1423. {
  1424. m_pCollisionSolver->SetHandler( pSolver );
  1425. }
  1426. void CPhysicsEnvironment::ClearDeadObjects( void )
  1427. {
  1428. for ( int i = 0; i < m_deadObjects.Count(); i++ )
  1429. {
  1430. CPhysicsObject *pObject = (CPhysicsObject *)m_deadObjects.Element(i);
  1431. m_pSleepEvents->DeleteObject( pObject );
  1432. delete pObject;
  1433. }
  1434. m_deadObjects.Purge();
  1435. m_pDeleteQueue->DeleteAll();
  1436. }
  1437. void CPhysicsEnvironment::AddPlayerController( IPhysicsPlayerController *pController )
  1438. {
  1439. if ( m_playerControllers.Find(pController) != -1 )
  1440. {
  1441. Assert(0);
  1442. return;
  1443. }
  1444. m_playerControllers.AddToTail( pController );
  1445. }
  1446. void CPhysicsEnvironment::RemovePlayerController( IPhysicsPlayerController *pController )
  1447. {
  1448. m_playerControllers.FindAndRemove( pController );
  1449. }
  1450. IPhysicsPlayerController *CPhysicsEnvironment::FindPlayerController( IPhysicsObject *pPhysicsObject )
  1451. {
  1452. for ( int i = m_playerControllers.Count()-1; i >= 0; --i )
  1453. {
  1454. if ( m_playerControllers[i]->GetObject() == pPhysicsObject )
  1455. return m_playerControllers[i];
  1456. }
  1457. return NULL;
  1458. }
  1459. void CPhysicsEnvironment::SetCollisionEventHandler( IPhysicsCollisionEvent *pCollisionEvents )
  1460. {
  1461. m_pCollisionListener->SetHandler( pCollisionEvents );
  1462. }
  1463. void CPhysicsEnvironment::SetObjectEventHandler( IPhysicsObjectEvent *pObjectEvents )
  1464. {
  1465. m_pSleepEvents->SetHandler( pObjectEvents );
  1466. }
  1467. void CPhysicsEnvironment::SetConstraintEventHandler( IPhysicsConstraintEvent *pConstraintEvents )
  1468. {
  1469. m_pConstraintListener->SetHandler( pConstraintEvents );
  1470. }
  1471. IPhysicsShadowController *CPhysicsEnvironment::CreateShadowController( IPhysicsObject *pObject, bool allowTranslation, bool allowRotation )
  1472. {
  1473. return ::CreateShadowController( static_cast<CPhysicsObject*>(pObject), allowTranslation, allowRotation );
  1474. }
  1475. void CPhysicsEnvironment::DestroyShadowController( IPhysicsShadowController *pController )
  1476. {
  1477. delete pController;
  1478. }
  1479. IPhysicsPlayerController *CPhysicsEnvironment::CreatePlayerController( IPhysicsObject *pObject )
  1480. {
  1481. IPhysicsPlayerController *pController = ::CreatePlayerController( static_cast<CPhysicsObject*>(pObject) );
  1482. AddPlayerController( pController );
  1483. return pController;
  1484. }
  1485. void CPhysicsEnvironment::DestroyPlayerController( IPhysicsPlayerController *pController )
  1486. {
  1487. RemovePlayerController( pController );
  1488. ::DestroyPlayerController( pController );
  1489. }
  1490. IPhysicsMotionController *CPhysicsEnvironment::CreateMotionController( IMotionEvent *pHandler )
  1491. {
  1492. return ::CreateMotionController( this, pHandler );
  1493. }
  1494. void CPhysicsEnvironment::DestroyMotionController( IPhysicsMotionController *pController )
  1495. {
  1496. delete pController;
  1497. }
  1498. IPhysicsVehicleController *CPhysicsEnvironment::CreateVehicleController( IPhysicsObject *pVehicleBodyObject, const vehicleparams_t &params, unsigned int nVehicleType, IPhysicsGameTrace *pGameTrace )
  1499. {
  1500. return ::CreateVehicleController( this, static_cast<CPhysicsObject*>(pVehicleBodyObject), params, nVehicleType, pGameTrace );
  1501. }
  1502. void CPhysicsEnvironment::DestroyVehicleController( IPhysicsVehicleController *pController )
  1503. {
  1504. delete pController;
  1505. }
  1506. int CPhysicsEnvironment::GetActiveObjectCount( void ) const
  1507. {
  1508. return m_pSleepEvents->GetActiveObjectCount();
  1509. }
  1510. void CPhysicsEnvironment::GetActiveObjects( IPhysicsObject **pOutputObjectList ) const
  1511. {
  1512. m_pSleepEvents->GetActiveObjects( pOutputObjectList );
  1513. }
  1514. void CPhysicsEnvironment::SetAirDensity( float density )
  1515. {
  1516. CDragController *pDrag = ((CDragController *)m_pDragController);
  1517. if ( pDrag )
  1518. {
  1519. pDrag->SetAirDensity( density );
  1520. }
  1521. }
  1522. float CPhysicsEnvironment::GetAirDensity( void ) const
  1523. {
  1524. const CDragController *pDrag = ((CDragController *)m_pDragController);
  1525. if ( pDrag )
  1526. {
  1527. return pDrag->GetAirDensity();
  1528. }
  1529. return 0;
  1530. }
  1531. void CPhysicsEnvironment::CleanupDeleteList()
  1532. {
  1533. ClearDeadObjects();
  1534. }
  1535. bool CPhysicsEnvironment::IsCollisionModelUsed( CPhysCollide *pCollide ) const
  1536. {
  1537. int i;
  1538. for ( i = m_deadObjects.Count()-1; i >= 0; --i )
  1539. {
  1540. if ( m_deadObjects[i]->GetCollide() == pCollide )
  1541. return true;
  1542. }
  1543. for ( i = m_objects.Count()-1; i >= 0; --i )
  1544. {
  1545. if ( m_objects[i]->GetCollide() == pCollide )
  1546. return true;
  1547. }
  1548. return false;
  1549. }
  1550. // manage phantoms
  1551. void CPhysicsEnvironment::PhantomAdd( CPhysicsObject *pObject )
  1552. {
  1553. IVP_Controller_Phantom *pPhantom = pObject->GetObject()->get_controller_phantom();
  1554. if ( pPhantom )
  1555. {
  1556. pPhantom->add_listener_phantom( m_pCollisionListener );
  1557. }
  1558. }
  1559. void CPhysicsEnvironment::PhantomRemove( CPhysicsObject *pObject )
  1560. {
  1561. IVP_Controller_Phantom *pPhantom = pObject->GetObject()->get_controller_phantom();
  1562. if ( pPhantom )
  1563. {
  1564. pPhantom->remove_listener_phantom( m_pCollisionListener );
  1565. }
  1566. }
  1567. //-------------------------------------
  1568. IPhysicsObject *CPhysicsEnvironment::CreateSphereObject( float radius, int materialIndex, const Vector& position, const QAngle& angles, objectparams_t *pParams, bool isStatic )
  1569. {
  1570. IPhysicsObject *pObject = ::CreatePhysicsSphere( this, radius, materialIndex, position, angles, pParams, isStatic );
  1571. m_objects.AddToTail( pObject );
  1572. return pObject;
  1573. }
  1574. void CPhysicsEnvironment::TraceRay( const Ray_t &ray, unsigned int fMask, IPhysicsTraceFilter *pTraceFilter, trace_t *pTrace )
  1575. {
  1576. }
  1577. void CPhysicsEnvironment::SweepCollideable( const CPhysCollide *pCollide, const Vector &vecAbsStart, const Vector &vecAbsEnd,
  1578. const QAngle &vecAngles, unsigned int fMask, IPhysicsTraceFilter *pTraceFilter, trace_t *pTrace )
  1579. {
  1580. }
  1581. void CPhysicsEnvironment::GetPerformanceSettings( physics_performanceparams_t *pOutput ) const
  1582. {
  1583. if ( !pOutput )
  1584. return;
  1585. IVP_Anomaly_Limits *limits = m_pPhysEnv->get_anomaly_limits();
  1586. if ( limits )
  1587. {
  1588. // UNDONE: Expose these values for tuning
  1589. pOutput->maxVelocity = ConvertDistanceToHL( limits->max_velocity );
  1590. pOutput->maxAngularVelocity = ConvertAngleToHL(limits->max_angular_velocity_per_psi) * m_pPhysEnv->get_inv_delta_PSI_time();
  1591. pOutput->maxCollisionsPerObjectPerTimestep = limits->max_collisions_per_psi;
  1592. pOutput->maxCollisionChecksPerTimestep = limits->max_collision_checks_per_psi;
  1593. pOutput->minFrictionMass = limits->min_friction_mass;
  1594. pOutput->maxFrictionMass = limits->max_friction_mass;
  1595. }
  1596. IVP_Range_Manager *range = m_pPhysEnv->get_range_manager();
  1597. if ( range )
  1598. {
  1599. pOutput->lookAheadTimeObjectsVsWorld = range->look_ahead_time_world;
  1600. pOutput->lookAheadTimeObjectsVsObject = range->look_ahead_time_intra;
  1601. }
  1602. }
  1603. void CPhysicsEnvironment::SetPerformanceSettings( const physics_performanceparams_t *pSettings )
  1604. {
  1605. if ( !pSettings )
  1606. return;
  1607. IVP_Anomaly_Limits *limits = m_pPhysEnv->get_anomaly_limits();
  1608. if ( limits )
  1609. {
  1610. // UNDONE: Expose these values for tuning
  1611. limits->max_velocity = ConvertDistanceToIVP( pSettings->maxVelocity );
  1612. limits->max_collisions_per_psi = pSettings->maxCollisionsPerObjectPerTimestep;
  1613. limits->max_collision_checks_per_psi = pSettings->maxCollisionChecksPerTimestep;
  1614. limits->max_angular_velocity_per_psi = ConvertAngleToIVP(pSettings->maxAngularVelocity) * m_pPhysEnv->get_delta_PSI_time();
  1615. limits->min_friction_mass = clamp(pSettings->minFrictionMass, 1.0f, VPHYSICS_MAX_MASS );
  1616. limits->max_friction_mass = clamp(pSettings->maxFrictionMass, 1.0f, VPHYSICS_MAX_MASS );
  1617. }
  1618. IVP_Range_Manager *range = m_pPhysEnv->get_range_manager();
  1619. if ( range )
  1620. {
  1621. range->look_ahead_time_world = pSettings->lookAheadTimeObjectsVsWorld;
  1622. range->look_ahead_time_intra = pSettings->lookAheadTimeObjectsVsObject;
  1623. }
  1624. }
  1625. // perf/cost statistics
  1626. void CPhysicsEnvironment::ReadStats( physics_stats_t *pOutput )
  1627. {
  1628. if ( !pOutput )
  1629. return;
  1630. IVP_Statistic_Manager *stats = m_pPhysEnv->get_statistic_manager();
  1631. if ( stats )
  1632. {
  1633. pOutput->maxRescueSpeed = ConvertDistanceToHL( stats->max_rescue_speed );
  1634. pOutput->maxSpeedGain = ConvertDistanceToHL( stats->max_speed_gain );
  1635. pOutput->impactSysNum = stats->impact_sys_num;
  1636. pOutput->impactCounter = stats->impact_counter;
  1637. pOutput->impactSumSys = stats->impact_sum_sys;
  1638. pOutput->impactHardRescueCount = stats->impact_hard_rescue_counter;
  1639. pOutput->impactRescueAfterCount = stats->impact_rescue_after_counter;
  1640. pOutput->impactDelayedCount = stats->impact_delayed_counter;
  1641. pOutput->impactCollisionChecks = stats->impact_coll_checks;
  1642. pOutput->impactStaticCount = stats->impact_unmov;
  1643. pOutput->totalEnergyDestroyed = stats->sum_energy_destr;
  1644. pOutput->collisionPairsTotal = stats->sum_of_mindists;
  1645. pOutput->collisionPairsCreated = stats->mindists_generated;
  1646. pOutput->collisionPairsDestroyed = stats->mindists_deleted;
  1647. pOutput->potentialCollisionsObjectVsObject = stats->range_intra_exceeded;
  1648. pOutput->potentialCollisionsObjectVsWorld = stats->range_world_exceeded;
  1649. pOutput->frictionEventsProcessed = stats->processed_fmindists;
  1650. }
  1651. }
  1652. void CPhysicsEnvironment::ClearStats()
  1653. {
  1654. IVP_Statistic_Manager *stats = m_pPhysEnv->get_statistic_manager();
  1655. if ( stats )
  1656. {
  1657. stats->clear_statistic();
  1658. }
  1659. }
  1660. void CPhysicsEnvironment::EnableConstraintNotify( bool bEnable )
  1661. {
  1662. m_enableConstraintNotify = bEnable;
  1663. }
  1664. IPhysicsEnvironment *CreatePhysicsEnvironment( void )
  1665. {
  1666. return new CPhysicsEnvironment;
  1667. }
  1668. // This wraps IVP_Collision_Filter_Exclusive_Pair since we're reusing it
  1669. // as a general void * pair hash and it's API implies that has something
  1670. // to do with collision detection
  1671. class CVoidPairHash : private IVP_Collision_Filter_Exclusive_Pair
  1672. {
  1673. public:
  1674. void AddPair( void *pObject0, void *pObject1 )
  1675. {
  1676. // disabled pairs are stored int the collision filter's hash
  1677. disable_collision_between_objects( (IVP_Real_Object *)pObject0, (IVP_Real_Object *)pObject1 );
  1678. }
  1679. void RemovePair( void *pObject0, void *pObject1 )
  1680. {
  1681. // enabling removes the stored hash pair
  1682. enable_collision_between_objects( (IVP_Real_Object *)pObject0, (IVP_Real_Object *)pObject1 );
  1683. }
  1684. bool HasPair( void *pObject0, void *pObject1 )
  1685. {
  1686. // If collision is enabled, the pair is NOT present, so invert the test here.
  1687. return check_objects_for_collision_detection( (IVP_Real_Object *)pObject0, (IVP_Real_Object *)pObject1 ) ? false : true;
  1688. }
  1689. };
  1690. class CObjectPairHash : public IPhysicsObjectPairHash
  1691. {
  1692. public:
  1693. CObjectPairHash()
  1694. {
  1695. m_pObjectHash = new IVP_VHash_Store(1024);
  1696. }
  1697. ~CObjectPairHash()
  1698. {
  1699. delete m_pObjectHash;
  1700. }
  1701. // converts the void * stored in the hash to a list in the multilist
  1702. unsigned short HashToListIndex( void *pHash )
  1703. {
  1704. if ( !pHash )
  1705. return m_objectList.InvalidIndex();
  1706. unsigned int hash = (unsigned int)pHash;
  1707. // mask off the extra bit we added to avoid zeros
  1708. hash &= 0xFFFF;
  1709. return (unsigned short)hash;
  1710. }
  1711. // converts the list in the multilist to a void * we can put in the hash
  1712. void *ListIndexToHash( unsigned short listIndex )
  1713. {
  1714. unsigned int hash = (unsigned int)listIndex;
  1715. // set the high bit, so zero means "not there"
  1716. hash |= 0x80000000;
  1717. return (void *)hash;
  1718. }
  1719. // Lookup this object and get a multilist entry
  1720. unsigned short GetListForObject( void *pObject )
  1721. {
  1722. return HashToListIndex( m_pObjectHash->find_elem( pObject ) );
  1723. }
  1724. // new object, set up his list
  1725. void SetListForObject( void *pObject, unsigned short listIndex )
  1726. {
  1727. Assert( !m_pObjectHash->find_elem( pObject ) );
  1728. m_pObjectHash->add_elem( pObject, ListIndexToHash(listIndex) );
  1729. }
  1730. // last entry is gone, remove the object
  1731. void DestroyListForObject( void *pObject, unsigned short listIndex )
  1732. {
  1733. if ( m_objectList.IsValidList( listIndex ) )
  1734. {
  1735. m_objectList.DestroyList( listIndex );
  1736. m_pObjectHash->remove_elem( pObject );
  1737. }
  1738. }
  1739. // Add this object to the list of disabled objects
  1740. void AddToObjectList( void *pObject, void *pAdd )
  1741. {
  1742. unsigned short listIndex = GetListForObject( pObject );
  1743. if ( !m_objectList.IsValidList( listIndex ) )
  1744. {
  1745. listIndex = m_objectList.CreateList();
  1746. SetListForObject( pObject, listIndex );
  1747. }
  1748. m_objectList.AddToTail( listIndex, pAdd );
  1749. }
  1750. // Remove one object from a particular object's list (linear time)
  1751. void RemoveFromObjectList( void *pObject, void *pRemove )
  1752. {
  1753. unsigned short listIndex = GetListForObject( pObject );
  1754. if ( !m_objectList.IsValidList( listIndex ) )
  1755. return;
  1756. for ( unsigned short item = m_objectList.Head(listIndex); item != m_objectList.InvalidIndex(); item = m_objectList.Next(item) )
  1757. {
  1758. if ( m_objectList[item] == pRemove )
  1759. {
  1760. // found it, remove
  1761. m_objectList.Remove( listIndex, item );
  1762. if ( m_objectList.Head(listIndex) == m_objectList.InvalidIndex() )
  1763. {
  1764. DestroyListForObject( pObject, listIndex );
  1765. }
  1766. return;
  1767. }
  1768. }
  1769. }
  1770. // add a pair (constant time)
  1771. virtual void AddObjectPair( void *pObject0, void *pObject1 )
  1772. {
  1773. if ( IsObjectPairInHash(pObject0,pObject1) )
  1774. return;
  1775. // add the pair to the hash
  1776. m_pairHash.AddPair( pObject0, pObject1 );
  1777. AddToObjectList( pObject0, pObject1 );
  1778. AddToObjectList( pObject1, pObject0 );
  1779. }
  1780. // remove a pair (linear time x 2)
  1781. virtual void RemoveObjectPair( void *pObject0, void *pObject1 )
  1782. {
  1783. if ( !IsObjectPairInHash(pObject0,pObject1) )
  1784. return;
  1785. // remove the pair from the hash
  1786. m_pairHash.RemovePair( pObject0, pObject1 );
  1787. RemoveFromObjectList( pObject0, pObject1 );
  1788. RemoveFromObjectList( pObject1, pObject0 );
  1789. }
  1790. // check for pair presence (fast constant time)
  1791. virtual bool IsObjectPairInHash( void *pObject0, void *pObject1 )
  1792. {
  1793. return m_pairHash.HasPair( pObject0, pObject1 );
  1794. }
  1795. virtual void RemoveAllPairsForObject( void *pObject )
  1796. {
  1797. unsigned short listIndex = GetListForObject( pObject );
  1798. if ( !m_objectList.IsValidList( listIndex ) )
  1799. return;
  1800. unsigned short item = m_objectList.Head(listIndex);
  1801. while ( item != m_objectList.InvalidIndex() )
  1802. {
  1803. unsigned short next = m_objectList.Next(item);
  1804. void *pOther = m_objectList[item];
  1805. m_objectList.Remove( listIndex, item );
  1806. // remove the matching entry
  1807. RemoveFromObjectList( pOther, pObject );
  1808. m_pairHash.RemovePair( pOther, pObject );
  1809. item = next;
  1810. }
  1811. DestroyListForObject( pObject, listIndex );
  1812. }
  1813. // Gets the # of dependencies for a particular entity
  1814. virtual int GetPairCountForObject( void *pObject0 )
  1815. {
  1816. unsigned short listIndex = GetListForObject( pObject0 );
  1817. if ( !m_objectList.IsValidList( listIndex ) )
  1818. return 0;
  1819. int nCount = 0;
  1820. unsigned short item;
  1821. for ( item = m_objectList.Head(listIndex); item != m_objectList.InvalidIndex();
  1822. item = m_objectList.Next(item) )
  1823. {
  1824. ++nCount;
  1825. }
  1826. return nCount;
  1827. }
  1828. // Gets all dependencies for a particular entity
  1829. virtual int GetPairListForObject( void *pObject0, int nMaxCount, void **ppObjectList )
  1830. {
  1831. unsigned short listIndex = GetListForObject( pObject0 );
  1832. if ( !m_objectList.IsValidList( listIndex ) )
  1833. return 0;
  1834. int nCount = 0;
  1835. unsigned short item;
  1836. for ( item = m_objectList.Head(listIndex); item != m_objectList.InvalidIndex();
  1837. item = m_objectList.Next(item) )
  1838. {
  1839. ppObjectList[nCount] = m_objectList[item];
  1840. if ( ++nCount >= nMaxCount )
  1841. break;
  1842. }
  1843. return nCount;
  1844. }
  1845. virtual bool IsObjectInHash( void *pObject0 )
  1846. {
  1847. return m_pObjectHash->find_elem(pObject0) != NULL ? true : false;
  1848. }
  1849. #if 0
  1850. virtual int CountObjectsInHash()
  1851. {
  1852. return m_pObjectHash->n_elems();
  1853. }
  1854. #endif
  1855. private:
  1856. // this is a hash of object pairs
  1857. CVoidPairHash m_pairHash;
  1858. // this is a hash of pObjects with each element storing an index to the head of its list of disabled collisions
  1859. IVP_VHash_Store *m_pObjectHash;
  1860. // this is the list of disabled collisions for each object. Uses multilist
  1861. CUtlMultiList<void *, unsigned short> m_objectList;
  1862. };
  1863. IPhysicsObjectPairHash *CreateObjectPairHash()
  1864. {
  1865. return new CObjectPairHash;
  1866. }