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.

2001 lines
54 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "ivp_surman_polygon.hxx"
  9. #include "ivp_compact_ledge.hxx"
  10. #include "ivp_compact_ledge_solver.hxx"
  11. #include "ivp_mindist.hxx"
  12. #include "ivp_friction.hxx"
  13. #include "ivp_phantom.hxx"
  14. #include "ivp_listener_collision.hxx"
  15. #include "ivp_clustering_visualizer.hxx"
  16. #include "ivp_anomaly_manager.hxx"
  17. #include "ivp_collision_filter.hxx"
  18. #include "hk_mopp/ivp_surman_mopp.hxx"
  19. #include "hk_mopp/ivp_compact_mopp.hxx"
  20. #include "ivp_compact_surface.hxx"
  21. #include "physics_trace.h"
  22. #include "physics_shadow.h"
  23. #include "physics_friction.h"
  24. #include "physics_constraint.h"
  25. #include "bspflags.h"
  26. #include "vphysics/player_controller.h"
  27. #include "vphysics/friction.h"
  28. // memdbgon must be the last include file in a .cpp file!!!
  29. #include "tier0/memdbgon.h"
  30. extern IPhysicsCollision *physcollision;
  31. // UNDONE: Make this a stack variable / member variable of some save/load object or function?
  32. // NOTE: This keeps a list of objects who were saved while asleep, but not created asleep
  33. // So some info will be lost unless it's regenerated after loading.
  34. struct postrestore_objectlist_t
  35. {
  36. CPhysicsObject *pObject;
  37. bool growFriction;
  38. bool enableCollisions;
  39. void Defaults()
  40. {
  41. pObject = NULL;
  42. growFriction = false;
  43. enableCollisions = false;
  44. }
  45. };
  46. static CUtlVector<postrestore_objectlist_t> g_PostRestoreObjectList;
  47. // This angular basis is the integral of each differential drag area's torque over the whole OBB
  48. // For each axis, each face, the integral is (1/Iaxis) * (1/3 * w^2l^3 + 1/2 * w^4l + lw^2h^2)
  49. // l,w, & h are half widths - where l is in the direction of the axis, w is in the plane (l/w plane) of the face,
  50. // and h is perpendicular to the face. So for each axis, you sum up this integral over 2 pairs of faces
  51. // (this function returns the integral for one pair of opposite faces, not one face)
  52. static float AngDragIntegral( float invInertia, float l, float w, float h )
  53. {
  54. float w2 = w*w;
  55. float l2 = l*l;
  56. float h2 = h*h;
  57. return invInertia * ( (1.f/3.f)*w2*l*l2 + 0.5 * w2*w2*l + l*w2*h2 );
  58. }
  59. CPhysicsObject::CPhysicsObject( void )
  60. {
  61. #ifdef _WIN32
  62. void *pData = ((char *)this) + sizeof(void *); // offset beyond vtable
  63. int dataSize = sizeof(*this) - sizeof(void *);
  64. Assert( pData == &m_pGameData );
  65. memset( pData, 0, dataSize );
  66. #elif POSIX
  67. //!!HACK HACK - rework this if we ever change compiler versions (from gcc 3.2!!!)
  68. void *pData = ((char *)this) + sizeof(void *); // offset beyond vtable
  69. int dataSize = sizeof(*this) - sizeof(void *);
  70. Assert( pData == &m_pGameData );
  71. memset( pData, 0, dataSize );
  72. #else
  73. #error
  74. #endif
  75. // HACKHACK: init this as a sphere until someone attaches a surfacemanager
  76. m_collideType = COLLIDE_BALL;
  77. m_contentsMask = CONTENTS_SOLID;
  78. m_hasTouchedDynamic = 0;
  79. }
  80. void CPhysicsObject::Init( const CPhysCollide *pCollisionModel, IVP_Real_Object *pObject, int materialIndex, float volume, float drag, float angDrag )
  81. {
  82. m_pCollide = pCollisionModel;
  83. m_materialIndex = materialIndex;
  84. m_pObject = pObject;
  85. pObject->client_data = (void *)this;
  86. m_pGameData = NULL;
  87. m_gameFlags = 0;
  88. m_gameIndex = 0;
  89. m_sleepState = OBJ_SLEEP; // objects start asleep
  90. m_callbacks = CALLBACK_GLOBAL_COLLISION|CALLBACK_GLOBAL_FRICTION|CALLBACK_FLUID_TOUCH|CALLBACK_GLOBAL_TOUCH|CALLBACK_GLOBAL_COLLIDE_STATIC|CALLBACK_DO_FLUID_SIMULATION;
  91. m_activeIndex = 0xFFFF;
  92. m_pShadow = NULL;
  93. m_shadowTempGravityDisable = false;
  94. m_forceSilentDelete = false;
  95. m_dragBasis = vec3_origin;
  96. m_angDragBasis = vec3_origin;
  97. if ( !IsStatic() && GetCollide() )
  98. {
  99. RecomputeDragBases();
  100. }
  101. else
  102. {
  103. drag = 0;
  104. angDrag = 0;
  105. }
  106. m_dragCoefficient = drag;
  107. m_angDragCoefficient = angDrag;
  108. SetVolume( volume );
  109. }
  110. CPhysicsObject::~CPhysicsObject( void )
  111. {
  112. RemoveShadowController();
  113. if ( m_pObject )
  114. {
  115. // prevents callbacks to the game code / unlink from this object
  116. m_callbacks = 0;
  117. m_pGameData = 0;
  118. m_pObject->client_data = 0;
  119. IVP_Core *pCore = m_pObject->get_core();
  120. if ( pCore->physical_unmoveable == IVP_TRUE && pCore->controllers_of_core.n_elems )
  121. {
  122. // go ahead and notify them if this happens in the real world
  123. for(int i = pCore->controllers_of_core.len()-1; i >=0 ;i-- )
  124. {
  125. IVP_Controller *my_controller = pCore->controllers_of_core.element_at(i);
  126. my_controller->core_is_going_to_be_deleted_event(pCore);
  127. Assert(my_controller==pCore->environment->get_gravity_controller());
  128. }
  129. }
  130. // UNDONE: Don't free the surface manager here
  131. // UNDONE: Remove reference to it by calling something in physics_collide
  132. IVP_SurfaceManager *pSurman = GetSurfaceManager();
  133. CPhysicsEnvironment *pVEnv = GetVPhysicsEnvironment();
  134. // BUGBUG: Sometimes IVP will call a "revive" on the object we're deleting!
  135. MEM_ALLOC_CREDIT();
  136. if ( m_forceSilentDelete || (pVEnv && pVEnv->ShouldQuickDelete()) || !m_hasTouchedDynamic )
  137. {
  138. m_pObject->delete_silently();
  139. }
  140. else
  141. {
  142. m_pObject->delete_and_check_vicinity();
  143. }
  144. delete pSurman;
  145. }
  146. }
  147. void CPhysicsObject::Wake( void )
  148. {
  149. m_pObject->ensure_in_simulation();
  150. }
  151. // supported
  152. void CPhysicsObject::Sleep( void )
  153. {
  154. m_pObject->disable_simulation();
  155. }
  156. bool CPhysicsObject::IsAsleep() const
  157. {
  158. if ( m_sleepState == OBJ_AWAKE )
  159. return false;
  160. // double-check that we aren't pending
  161. if ( m_pObject->get_core()->is_in_wakeup_vec )
  162. return false;
  163. return true;
  164. }
  165. void CPhysicsObject::NotifySleep( void )
  166. {
  167. if ( m_sleepState == OBJ_AWAKE )
  168. {
  169. m_sleepState = OBJ_STARTSLEEP;
  170. }
  171. else
  172. {
  173. // UNDONE: This fails sometimes and we get sleep calls for a sleeping object, debug?
  174. //Assert(m_sleepState==OBJ_STARTSLEEP);
  175. m_sleepState = OBJ_SLEEP;
  176. }
  177. }
  178. void CPhysicsObject::NotifyWake( void )
  179. {
  180. m_asleepSinceCreation = false;
  181. m_sleepState = OBJ_AWAKE;
  182. }
  183. void CPhysicsObject::SetCallbackFlags( unsigned short callbackflags )
  184. {
  185. #if IVP_ENABLE_VISUALIZER
  186. unsigned short changedFlags = m_callbacks ^ callbackflags;
  187. if ( changedFlags & CALLBACK_MARKED_FOR_TEST )
  188. {
  189. if ( callbackflags & CALLBACK_MARKED_FOR_TEST )
  190. {
  191. ENABLE_SHORTRANGE_VISUALIZATION(m_pObject);
  192. ENABLE_LONGRANGE_VISUALIZATION(m_pObject);
  193. }
  194. else
  195. {
  196. DISABLE_SHORTRANGE_VISUALIZATION(m_pObject);
  197. DISABLE_LONGRANGE_VISUALIZATION(m_pObject);
  198. }
  199. }
  200. #endif
  201. m_callbacks = callbackflags;
  202. }
  203. unsigned short CPhysicsObject::GetCallbackFlags() const
  204. {
  205. return m_callbacks;
  206. }
  207. void CPhysicsObject::SetGameFlags( unsigned short userFlags )
  208. {
  209. m_gameFlags = userFlags;
  210. }
  211. unsigned short CPhysicsObject::GetGameFlags() const
  212. {
  213. return m_gameFlags;
  214. }
  215. void CPhysicsObject::SetGameIndex( unsigned short gameIndex )
  216. {
  217. m_gameIndex = gameIndex;
  218. }
  219. unsigned short CPhysicsObject::GetGameIndex() const
  220. {
  221. return m_gameIndex;
  222. }
  223. bool CPhysicsObject::IsStatic() const
  224. {
  225. if ( m_pObject->get_core()->physical_unmoveable )
  226. return true;
  227. return false;
  228. }
  229. void CPhysicsObject::EnableCollisions( bool enable )
  230. {
  231. if ( enable )
  232. {
  233. m_callbacks |= CALLBACK_ENABLING_COLLISION;
  234. BEGIN_IVP_ALLOCATION();
  235. m_pObject->enable_collision_detection( IVP_TRUE );
  236. END_IVP_ALLOCATION();
  237. m_callbacks &= ~CALLBACK_ENABLING_COLLISION;
  238. }
  239. else
  240. {
  241. if ( IsCollisionEnabled() )
  242. {
  243. // Delete all contact points with this physics object because it's collision is becoming disabled
  244. IPhysicsFrictionSnapshot *pSnapshot = CreateFrictionSnapshot();
  245. while ( pSnapshot->IsValid() )
  246. {
  247. pSnapshot->MarkContactForDelete();
  248. pSnapshot->NextFrictionData();
  249. }
  250. pSnapshot->DeleteAllMarkedContacts( true );
  251. DestroyFrictionSnapshot( pSnapshot );
  252. }
  253. m_pObject->enable_collision_detection( IVP_FALSE );
  254. }
  255. }
  256. void CPhysicsObject::RecheckCollisionFilter()
  257. {
  258. if ( CallbackFlags() & CALLBACK_MARKED_FOR_DELETE )
  259. return;
  260. m_callbacks |= CALLBACK_ENABLING_COLLISION;
  261. BEGIN_IVP_ALLOCATION();
  262. m_pObject->recheck_collision_filter();
  263. // UNDONE: do a RecheckContactPoints() here?
  264. END_IVP_ALLOCATION();
  265. m_callbacks &= ~CALLBACK_ENABLING_COLLISION;
  266. }
  267. void CPhysicsObject::RecheckContactPoints()
  268. {
  269. IVP_Environment *pEnv = m_pObject->get_environment();
  270. IVP_Collision_Filter *coll_filter = pEnv->get_collision_filter();
  271. IPhysicsFrictionSnapshot *pSnapshot = CreateFrictionSnapshot();
  272. while ( pSnapshot->IsValid() )
  273. {
  274. CPhysicsObject *pOther = static_cast<CPhysicsObject *>(pSnapshot->GetObject(1));
  275. if ( !coll_filter->check_objects_for_collision_detection( m_pObject, pOther->m_pObject ) )
  276. {
  277. pSnapshot->MarkContactForDelete();
  278. }
  279. pSnapshot->NextFrictionData();
  280. }
  281. pSnapshot->DeleteAllMarkedContacts( true );
  282. DestroyFrictionSnapshot( pSnapshot );
  283. }
  284. CPhysicsEnvironment *CPhysicsObject::GetVPhysicsEnvironment()
  285. {
  286. return (CPhysicsEnvironment *) (m_pObject->get_environment()->client_data);
  287. }
  288. const CPhysicsEnvironment *CPhysicsObject::GetVPhysicsEnvironment() const
  289. {
  290. return (CPhysicsEnvironment *) (m_pObject->get_environment()->client_data);
  291. }
  292. bool CPhysicsObject::IsControlling( const IVP_Controller *pController ) const
  293. {
  294. IVP_Core *pCore = m_pObject->get_core();
  295. for ( int i = 0; i < pCore->controllers_of_core.len(); i++ )
  296. {
  297. // already controlling this core?
  298. if ( pCore->controllers_of_core.element_at(i) == pController )
  299. return true;
  300. }
  301. return false;
  302. }
  303. bool CPhysicsObject::IsGravityEnabled() const
  304. {
  305. if ( !IsStatic() )
  306. {
  307. return IsControlling( m_pObject->get_core()->environment->get_gravity_controller() );
  308. }
  309. return false;
  310. }
  311. bool CPhysicsObject::IsDragEnabled() const
  312. {
  313. if ( !IsStatic() )
  314. {
  315. return IsControlling( GetVPhysicsEnvironment()->GetDragController() );
  316. }
  317. return false;
  318. }
  319. bool CPhysicsObject::IsMotionEnabled() const
  320. {
  321. return m_pObject->get_core()->pinned ? false : true;
  322. }
  323. bool CPhysicsObject::IsMoveable() const
  324. {
  325. if ( IsStatic() || !IsMotionEnabled() )
  326. return false;
  327. return true;
  328. }
  329. void CPhysicsObject::EnableGravity( bool enable )
  330. {
  331. if ( IsStatic() )
  332. return;
  333. bool isEnabled = IsGravityEnabled();
  334. if ( enable == isEnabled )
  335. return;
  336. IVP_Controller *pGravity = m_pObject->get_core()->environment->get_gravity_controller();
  337. if ( enable )
  338. {
  339. m_pObject->get_core()->add_core_controller( pGravity );
  340. }
  341. else
  342. {
  343. m_pObject->get_core()->rem_core_controller( pGravity );
  344. }
  345. }
  346. void CPhysicsObject::EnableDrag( bool enable )
  347. {
  348. if ( IsStatic() )
  349. return;
  350. bool isEnabled = IsDragEnabled();
  351. if ( enable == isEnabled )
  352. return;
  353. IVP_Controller *pDrag = GetVPhysicsEnvironment()->GetDragController();
  354. if ( enable )
  355. {
  356. m_pObject->get_core()->add_core_controller( pDrag );
  357. }
  358. else
  359. {
  360. m_pObject->get_core()->rem_core_controller( pDrag );
  361. }
  362. }
  363. void CPhysicsObject::SetDragCoefficient( float *pDrag, float *pAngularDrag )
  364. {
  365. if ( pDrag )
  366. {
  367. m_dragCoefficient = *pDrag;
  368. }
  369. if ( pAngularDrag )
  370. {
  371. m_angDragCoefficient = *pAngularDrag;
  372. }
  373. EnableDrag( m_dragCoefficient || m_angDragCoefficient );
  374. }
  375. void CPhysicsObject::RecomputeDragBases()
  376. {
  377. if ( IsStatic() || !GetCollide() )
  378. return;
  379. // Basically we are computing drag as an OBB. Get OBB extents for projection
  380. // scale those extents by appropriate mass/inertia to compute velocity directly (not force)
  381. // in the controller
  382. // NOTE: Compute these even if drag coefficients are zero, because the drag coefficient could change later
  383. // Get an AABB for this object and use the area of each side as a basis for approximating cross-section area for drag
  384. Vector dragMins, dragMaxs;
  385. // NOTE: coordinates in/out of physcollision are in HL units, not IVP
  386. // PERFORMANCE: Cache this? Expensive.
  387. physcollision->CollideGetAABB( &dragMins, &dragMaxs, GetCollide(), vec3_origin, vec3_angle );
  388. Vector areaFractions = physcollision->CollideGetOrthographicAreas( GetCollide() );
  389. Vector delta = dragMaxs - dragMins;
  390. ConvertPositionToIVP( delta.x, delta.y, delta.z );
  391. delta.x = fabsf(delta.x);
  392. delta.y = fabsf(delta.y);
  393. delta.z = fabsf(delta.z);
  394. // dragBasis is now the area of each side
  395. m_dragBasis.x = delta.y * delta.z * areaFractions.x;
  396. m_dragBasis.y = delta.x * delta.z * areaFractions.y;
  397. m_dragBasis.z = delta.x * delta.y * areaFractions.z;
  398. m_dragBasis *= GetInvMass();
  399. const IVP_U_Float_Point *pInvRI = m_pObject->get_core()->get_inv_rot_inertia();
  400. // This angular basis is the integral of each differential drag area's torque over the whole OBB
  401. // need half lengths for this integral
  402. delta *= 0.5;
  403. // rotation about the x axis
  404. m_angDragBasis.x = areaFractions.z * AngDragIntegral( pInvRI->k[0], delta.x, delta.y, delta.z ) + areaFractions.y * AngDragIntegral( pInvRI->k[0], delta.x, delta.z, delta.y );
  405. // rotation about the y axis
  406. m_angDragBasis.y = areaFractions.z * AngDragIntegral( pInvRI->k[1], delta.y, delta.x, delta.z ) + areaFractions.x * AngDragIntegral( pInvRI->k[1], delta.y, delta.z, delta.x );
  407. // rotation about the z axis
  408. m_angDragBasis.z = areaFractions.y * AngDragIntegral( pInvRI->k[2], delta.z, delta.x, delta.y ) + areaFractions.x * AngDragIntegral( pInvRI->k[2], delta.z, delta.y, delta.x );
  409. }
  410. void CPhysicsObject::EnableMotion( bool enable )
  411. {
  412. if ( IsStatic() )
  413. return;
  414. bool isMoveable = IsMotionEnabled();
  415. // no change
  416. if ( isMoveable == enable )
  417. return;
  418. BEGIN_IVP_ALLOCATION();
  419. m_pObject->set_pinned( enable ? IVP_FALSE : IVP_TRUE );
  420. END_IVP_ALLOCATION();
  421. if ( enable && IsHinged() )
  422. {
  423. BecomeHinged( m_hingedAxis-1 );
  424. }
  425. RecheckCollisionFilter();
  426. RecheckContactPoints();
  427. }
  428. bool CPhysicsObject::IsControlledByGame() const
  429. {
  430. if (m_pShadow && !m_pShadow->IsPhysicallyControlled())
  431. return true;
  432. if ( CallbackFlags() & CALLBACK_IS_PLAYER_CONTROLLER )
  433. return true;
  434. return false;
  435. }
  436. IPhysicsFrictionSnapshot *CPhysicsObject::CreateFrictionSnapshot()
  437. {
  438. return ::CreateFrictionSnapshot( m_pObject );
  439. }
  440. void CPhysicsObject::DestroyFrictionSnapshot( IPhysicsFrictionSnapshot *pSnapshot )
  441. {
  442. ::DestroyFrictionSnapshot(pSnapshot);
  443. }
  444. bool CPhysicsObject::IsMassCenterAtDefault() const
  445. {
  446. // this is the actual mass center of the object as created
  447. Vector massCenterHL = GetMassCenterLocalSpace();
  448. // Get the default mass center to see if it has been changed
  449. IVP_U_Float_Point massCenterIVPDefault;
  450. Vector massCenterHLDefault;
  451. GetObject()->get_surface_manager()->get_mass_center( &massCenterIVPDefault );
  452. ConvertPositionToHL( massCenterIVPDefault, massCenterHLDefault );
  453. float delta = (massCenterHLDefault - massCenterHL).Length();
  454. return ( delta <= g_PhysicsUnits.collisionSweepIncrementalEpsilon ) ? true : false;
  455. }
  456. Vector CPhysicsObject::GetMassCenterLocalSpace() const
  457. {
  458. if ( m_pObject->flags.shift_core_f_object_is_zero )
  459. return vec3_origin;
  460. Vector out;
  461. ConvertPositionToHL( *m_pObject->get_shift_core_f_object(), out );
  462. // core shift is what you add to the mass center to get the origin
  463. // so we want the negative core shift (origin relative position of the mass center)
  464. return -out;
  465. }
  466. void CPhysicsObject::SetGameData( void *pGameData )
  467. {
  468. m_pGameData = pGameData;
  469. }
  470. void *CPhysicsObject::GetGameData( void ) const
  471. {
  472. return m_pGameData;
  473. }
  474. void CPhysicsObject::SetMass( float mass )
  475. {
  476. bool reset = false;
  477. if ( !IsMoveable() )
  478. {
  479. reset = true;
  480. EnableMotion(true);
  481. }
  482. Assert( mass > 0 );
  483. mass = clamp( mass, 0, VPHYSICS_MAX_MASS ); // NOTE: Allow zero procedurally, but not by initialization
  484. m_pObject->change_mass( mass );
  485. SetVolume( m_volume );
  486. RecomputeDragBases();
  487. if ( reset )
  488. {
  489. EnableMotion(false);
  490. }
  491. }
  492. float CPhysicsObject::GetMass( void ) const
  493. {
  494. return m_pObject->get_core()->get_mass();
  495. }
  496. float CPhysicsObject::GetInvMass( void ) const
  497. {
  498. return m_pObject->get_core()->get_inv_mass();
  499. }
  500. Vector CPhysicsObject::GetInertia( void ) const
  501. {
  502. const IVP_U_Float_Point *pRI = m_pObject->get_core()->get_rot_inertia();
  503. Vector hlInertia;
  504. ConvertDirectionToHL( *pRI, hlInertia );
  505. VectorAbs( hlInertia, hlInertia );
  506. return hlInertia;
  507. }
  508. Vector CPhysicsObject::GetInvInertia( void ) const
  509. {
  510. const IVP_U_Float_Point *pRI = m_pObject->get_core()->get_inv_rot_inertia();
  511. Vector hlInvInertia;
  512. ConvertDirectionToHL( *pRI, hlInvInertia );
  513. VectorAbs( hlInvInertia, hlInvInertia );
  514. return hlInvInertia;
  515. }
  516. void CPhysicsObject::SetInertia( const Vector &inertia )
  517. {
  518. IVP_U_Float_Point ri;
  519. ConvertDirectionToIVP( inertia, ri );
  520. ri.k[0] = IVP_Inline_Math::fabsd(ri.k[0]);
  521. ri.k[1] = IVP_Inline_Math::fabsd(ri.k[1]);
  522. ri.k[2] = IVP_Inline_Math::fabsd(ri.k[2]);
  523. m_pObject->get_core()->set_rotation_inertia( &ri );
  524. }
  525. void CPhysicsObject::GetDamping( float *speed, float *rot ) const
  526. {
  527. IVP_Core *pCore = m_pObject->get_core();
  528. if ( speed )
  529. {
  530. *speed = pCore->speed_damp_factor;
  531. }
  532. if ( rot )
  533. {
  534. *rot = pCore->rot_speed_damp_factor.k[0];
  535. }
  536. }
  537. void CPhysicsObject::SetDamping( const float *speed, const float *rot )
  538. {
  539. IVP_Core *pCore = m_pObject->get_core();
  540. if ( speed )
  541. {
  542. pCore->speed_damp_factor = *speed;
  543. }
  544. if ( rot )
  545. {
  546. pCore->rot_speed_damp_factor.set( *rot, *rot, *rot );
  547. }
  548. }
  549. void CPhysicsObject::SetVolume( float volume )
  550. {
  551. m_volume = volume;
  552. if ( volume != 0.f )
  553. {
  554. // minimum volume is 5 cubic inches - otherwise buoyancy can get unstable
  555. if ( volume < 5.0f )
  556. {
  557. volume = 5.0f;
  558. }
  559. volume *= HL2IVP_FACTOR*HL2IVP_FACTOR*HL2IVP_FACTOR;
  560. float density = GetMass() / volume;
  561. float matDensity;
  562. physprops->GetPhysicsProperties( GetMaterialIndexInternal(), &matDensity, NULL, NULL, NULL );
  563. m_buoyancyRatio = density / matDensity;
  564. }
  565. else
  566. {
  567. m_buoyancyRatio = 1.0f;
  568. }
  569. }
  570. float CPhysicsObject::GetVolume() const
  571. {
  572. return m_volume;
  573. }
  574. void CPhysicsObject::SetBuoyancyRatio( float ratio )
  575. {
  576. m_buoyancyRatio = ratio;
  577. }
  578. void CPhysicsObject::SetContents( unsigned int contents )
  579. {
  580. m_contentsMask = contents;
  581. }
  582. // converts HL local units to HL world units
  583. void CPhysicsObject::LocalToWorld( Vector *worldPosition, const Vector &localPosition ) const
  584. {
  585. matrix3x4_t matrix;
  586. GetPositionMatrix( &matrix );
  587. // copy in case the src == dest
  588. VectorTransform( Vector(localPosition), matrix, *worldPosition );
  589. }
  590. // Converts world HL units to HL local/object units
  591. void CPhysicsObject::WorldToLocal( Vector *localPosition, const Vector &worldPosition ) const
  592. {
  593. matrix3x4_t matrix;
  594. GetPositionMatrix( &matrix );
  595. // copy in case the src == dest
  596. VectorITransform( Vector(worldPosition), matrix, *localPosition );
  597. }
  598. void CPhysicsObject::LocalToWorldVector( Vector *worldVector, const Vector &localVector ) const
  599. {
  600. matrix3x4_t matrix;
  601. GetPositionMatrix( &matrix );
  602. // copy in case the src == dest
  603. VectorRotate( Vector(localVector), matrix, *worldVector );
  604. }
  605. void CPhysicsObject::WorldToLocalVector( Vector *localVector, const Vector &worldVector ) const
  606. {
  607. matrix3x4_t matrix;
  608. GetPositionMatrix( &matrix );
  609. // copy in case the src == dest
  610. VectorIRotate( Vector(worldVector), matrix, *localVector );
  611. }
  612. // Apply force impulse (momentum) to the object
  613. void CPhysicsObject::ApplyForceCenter( const Vector &forceVector )
  614. {
  615. if ( !IsMoveable() )
  616. return;
  617. IVP_U_Float_Point tmp;
  618. ConvertForceImpulseToIVP( forceVector, tmp );
  619. IVP_Core *core = m_pObject->get_core();
  620. tmp.mult( core->get_inv_mass() );
  621. m_pObject->async_add_speed_object_ws( &tmp );
  622. ClampVelocity();
  623. }
  624. void CPhysicsObject::ApplyForceOffset( const Vector &forceVector, const Vector &worldPosition )
  625. {
  626. if ( !IsMoveable() )
  627. return;
  628. IVP_U_Point pos;
  629. IVP_U_Float_Point force;
  630. ConvertForceImpulseToIVP( forceVector, force );
  631. ConvertPositionToIVP( worldPosition, pos );
  632. IVP_Core *core = m_pObject->get_core();
  633. core->async_push_core_ws( &pos, &force );
  634. Wake();
  635. ClampVelocity();
  636. }
  637. void CPhysicsObject::CalculateForceOffset( const Vector &forceVector, const Vector &worldPosition, Vector *centerForce, AngularImpulse *centerTorque ) const
  638. {
  639. IVP_U_Point pos;
  640. IVP_U_Float_Point force;
  641. ConvertPositionToIVP( forceVector, force );
  642. ConvertPositionToIVP( worldPosition, pos );
  643. IVP_Core *core = m_pObject->get_core();
  644. const IVP_U_Matrix *m_world_f_core = core->get_m_world_f_core_PSI();
  645. IVP_U_Float_Point point_d_ws;
  646. point_d_ws.subtract(&pos, m_world_f_core->get_position());
  647. IVP_U_Float_Point cross_point_dir;
  648. cross_point_dir.calc_cross_product( &point_d_ws, &force);
  649. m_world_f_core->inline_vimult3( &cross_point_dir, &cross_point_dir);
  650. ConvertAngularImpulseToHL( cross_point_dir, *centerTorque );
  651. ConvertForceImpulseToHL( force, *centerForce );
  652. }
  653. void CPhysicsObject::CalculateVelocityOffset( const Vector &forceVector, const Vector &worldPosition, Vector *centerVelocity, AngularImpulse *centerAngularVelocity ) const
  654. {
  655. IVP_U_Point pos;
  656. IVP_U_Float_Point force;
  657. ConvertForceImpulseToIVP( forceVector, force );
  658. ConvertPositionToIVP( worldPosition, pos );
  659. IVP_Core *core = m_pObject->get_core();
  660. const IVP_U_Matrix *m_world_f_core = core->get_m_world_f_core_PSI();
  661. IVP_U_Float_Point point_d_ws;
  662. point_d_ws.subtract(&pos, m_world_f_core->get_position());
  663. IVP_U_Float_Point cross_point_dir;
  664. cross_point_dir.calc_cross_product( &point_d_ws, &force);
  665. m_world_f_core->inline_vimult3( &cross_point_dir, &cross_point_dir);
  666. cross_point_dir.set_pairwise_mult( &cross_point_dir, core->get_inv_rot_inertia());
  667. ConvertAngularImpulseToHL( cross_point_dir, *centerAngularVelocity );
  668. force.set_multiple( &force, core->get_inv_mass() );
  669. ConvertForceImpulseToHL( force, *centerVelocity );
  670. }
  671. void CPhysicsObject::ApplyTorqueCenter( const AngularImpulse &torqueImpulse )
  672. {
  673. if ( !IsMoveable() )
  674. return;
  675. IVP_U_Float_Point ivpTorque;
  676. ConvertAngularImpulseToIVP( torqueImpulse, ivpTorque );
  677. IVP_Core *core = m_pObject->get_core();
  678. core->async_rot_push_core_multiple_ws( &ivpTorque, 1.0 );
  679. Wake();
  680. ClampVelocity();
  681. }
  682. void CPhysicsObject::GetPosition( Vector *worldPosition, QAngle *angles ) const
  683. {
  684. IVP_U_Matrix matrix;
  685. m_pObject->get_m_world_f_object_AT( &matrix );
  686. if ( worldPosition )
  687. {
  688. ConvertPositionToHL( matrix.vv, *worldPosition );
  689. }
  690. if ( angles )
  691. {
  692. ConvertRotationToHL( matrix, *angles );
  693. }
  694. }
  695. void CPhysicsObject::GetPositionMatrix( matrix3x4_t *positionMatrix ) const
  696. {
  697. IVP_U_Matrix matrix;
  698. m_pObject->get_m_world_f_object_AT( &matrix );
  699. ConvertMatrixToHL( matrix, *positionMatrix );
  700. }
  701. void CPhysicsObject::GetImplicitVelocity( Vector *velocity, AngularImpulse *angularVelocity ) const
  702. {
  703. if ( !velocity && !angularVelocity )
  704. return;
  705. IVP_Core *core = m_pObject->get_core();
  706. if ( velocity )
  707. {
  708. // just convert the cached dx
  709. ConvertPositionToHL( core->delta_world_f_core_psis, *velocity );
  710. }
  711. if ( angularVelocity )
  712. {
  713. // compute the relative transform that was actually integrated in the last psi
  714. IVP_U_Quat q_core_f_core;
  715. q_core_f_core.set_invert_mult( &core->q_world_f_core_last_psi, &core->q_world_f_core_next_psi);
  716. // now convert that to an axis/angle pair
  717. Quaternion q( q_core_f_core.x, q_core_f_core.y, q_core_f_core.z, q_core_f_core.w );
  718. AngularImpulse axis;
  719. float angle;
  720. QuaternionAxisAngle( q, axis, angle );
  721. // scale it by the timestep to get a velocity
  722. angle *= core->i_delta_time;
  723. // ConvertDirectionToHL() - convert this ipion direction (in HL type) to HL coords
  724. float tmpY = axis.z;
  725. angularVelocity->z = -axis.y;
  726. angularVelocity->y = tmpY;
  727. angularVelocity->x = axis.x;
  728. // now scale the axis by the angle to return the data in the correct format
  729. (*angularVelocity) *= angle;
  730. }
  731. }
  732. void CPhysicsObject::GetVelocity( Vector *velocity, AngularImpulse *angularVelocity ) const
  733. {
  734. if ( !velocity && !angularVelocity )
  735. return;
  736. IVP_Core *core = m_pObject->get_core();
  737. if ( velocity )
  738. {
  739. IVP_U_Float_Point speed;
  740. speed.add( &core->speed, &core->speed_change );
  741. ConvertPositionToHL( speed, *velocity );
  742. }
  743. if ( angularVelocity )
  744. {
  745. IVP_U_Float_Point rotSpeed;
  746. rotSpeed.add( &core->rot_speed, &core->rot_speed_change );
  747. // xform to HL space
  748. ConvertAngularImpulseToHL( rotSpeed, *angularVelocity );
  749. }
  750. }
  751. void CPhysicsObject::GetVelocityAtPoint( const Vector &worldPosition, Vector *pVelocity ) const
  752. {
  753. IVP_Core *core = m_pObject->get_core();
  754. IVP_U_Point pos;
  755. ConvertPositionToIVP( worldPosition, pos );
  756. IVP_U_Float_Point rotSpeed;
  757. rotSpeed.add( &core->rot_speed, &core->rot_speed_change );
  758. IVP_U_Float_Point av_ws;
  759. core->get_m_world_f_core_PSI()->vmult3( &rotSpeed, &av_ws);
  760. IVP_U_Float_Point pos_rel;
  761. pos_rel.subtract( &pos, core->get_position_PSI());
  762. IVP_U_Float_Point cross;
  763. cross.inline_calc_cross_product(&av_ws,&pos_rel);
  764. IVP_U_Float_Point speed;
  765. speed.add(&core->speed, &cross);
  766. speed.add(&core->speed_change);
  767. ConvertPositionToHL( speed, *pVelocity );
  768. }
  769. // UNDONE: Limit these?
  770. void CPhysicsObject::AddVelocity( const Vector *velocity, const AngularImpulse *angularVelocity )
  771. {
  772. Assert(IsMoveable());
  773. if ( !IsMoveable() )
  774. return;
  775. IVP_Core *core = m_pObject->get_core();
  776. Wake();
  777. if ( velocity )
  778. {
  779. IVP_U_Float_Point ivpVelocity;
  780. ConvertPositionToIVP( *velocity, ivpVelocity );
  781. core->speed_change.add( &ivpVelocity );
  782. }
  783. if ( angularVelocity )
  784. {
  785. IVP_U_Float_Point ivpAngularVelocity;
  786. ConvertAngularImpulseToIVP( *angularVelocity, ivpAngularVelocity );
  787. core->rot_speed_change.add(&ivpAngularVelocity);
  788. }
  789. ClampVelocity();
  790. }
  791. void CPhysicsObject::SetPosition( const Vector &worldPosition, const QAngle &angles, bool isTeleport )
  792. {
  793. IVP_U_Quat rot;
  794. IVP_U_Point pos;
  795. if ( m_pShadow )
  796. {
  797. UpdateShadow( worldPosition, angles, false, 0 );
  798. }
  799. ConvertPositionToIVP( worldPosition, pos );
  800. ConvertRotationToIVP( angles, rot );
  801. if ( m_pObject->is_collision_detection_enabled() && isTeleport )
  802. {
  803. EnableCollisions( false );
  804. m_pObject->beam_object_to_new_position( &rot, &pos, IVP_FALSE );
  805. EnableCollisions( true );
  806. }
  807. else
  808. {
  809. m_pObject->beam_object_to_new_position( &rot, &pos, IVP_FALSE );
  810. }
  811. }
  812. void CPhysicsObject::SetPositionMatrix( const matrix3x4_t& matrix, bool isTeleport )
  813. {
  814. if ( m_pShadow )
  815. {
  816. Vector worldPosition;
  817. QAngle angles;
  818. MatrixAngles( matrix, angles );
  819. MatrixGetColumn( matrix, 3, worldPosition );
  820. UpdateShadow( worldPosition, angles, false, 0 );
  821. }
  822. IVP_U_Quat rot;
  823. IVP_U_Matrix mat;
  824. ConvertMatrixToIVP( matrix, mat );
  825. rot.set_quaternion( &mat );
  826. if ( m_pObject->is_collision_detection_enabled() && isTeleport )
  827. {
  828. EnableCollisions( false );
  829. m_pObject->beam_object_to_new_position( &rot, &mat.vv, IVP_FALSE );
  830. EnableCollisions( true );
  831. }
  832. else
  833. {
  834. m_pObject->beam_object_to_new_position( &rot, &mat.vv, IVP_FALSE );
  835. }
  836. }
  837. void CPhysicsObject::SetVelocityInstantaneous( const Vector *velocity, const AngularImpulse *angularVelocity )
  838. {
  839. Assert(IsMoveable());
  840. if ( !IsMoveable() )
  841. return;
  842. IVP_Core *core = m_pObject->get_core();
  843. Wake();
  844. if ( velocity )
  845. {
  846. ConvertPositionToIVP( *velocity, core->speed );
  847. core->speed_change.set_to_zero();
  848. }
  849. if ( angularVelocity )
  850. {
  851. ConvertAngularImpulseToIVP( *angularVelocity, core->rot_speed );
  852. core->rot_speed_change.set_to_zero();
  853. }
  854. ClampVelocity();
  855. }
  856. void CPhysicsObject::SetVelocity( const Vector *velocity, const AngularImpulse *angularVelocity )
  857. {
  858. if ( !IsMoveable() )
  859. return;
  860. IVP_Core *core = m_pObject->get_core();
  861. Wake();
  862. if ( velocity )
  863. {
  864. ConvertPositionToIVP( *velocity, core->speed_change );
  865. core->speed.set_to_zero();
  866. }
  867. if ( angularVelocity )
  868. {
  869. ConvertAngularImpulseToIVP( *angularVelocity, core->rot_speed_change );
  870. core->rot_speed.set_to_zero();
  871. }
  872. ClampVelocity();
  873. }
  874. void CPhysicsObject::ClampVelocity()
  875. {
  876. if ( m_pShadow )
  877. return;
  878. m_pObject->get_core()->apply_velocity_limit();
  879. }
  880. void GetWorldCoordFromSynapse( IVP_Synapse_Friction *pfriction, IVP_U_Point &world )
  881. {
  882. world.set(pfriction->get_contact_point()->get_contact_point_ws());
  883. }
  884. bool CPhysicsObject::GetContactPoint( Vector *contactPoint, IPhysicsObject **contactObject ) const
  885. {
  886. IVP_Synapse_Friction *pfriction = m_pObject->get_first_friction_synapse();
  887. if ( !pfriction )
  888. return false;
  889. if ( contactPoint )
  890. {
  891. IVP_U_Point world;
  892. GetWorldCoordFromSynapse( pfriction, world );
  893. ConvertPositionToHL( world, *contactPoint );
  894. }
  895. if ( contactObject )
  896. {
  897. IVP_Real_Object *pivp = GetOppositeSynapseObject( pfriction );
  898. *contactObject = static_cast<IPhysicsObject *>(pivp->client_data);
  899. }
  900. return true;
  901. }
  902. void CPhysicsObject::SetShadow( float maxSpeed, float maxAngularSpeed, bool allowPhysicsMovement, bool allowPhysicsRotation )
  903. {
  904. if ( m_pShadow )
  905. {
  906. m_pShadow->MaxSpeed( maxSpeed, maxAngularSpeed );
  907. }
  908. else
  909. {
  910. m_shadowTempGravityDisable = false;
  911. CPhysicsEnvironment *pVEnv = GetVPhysicsEnvironment();
  912. m_pShadow = pVEnv->CreateShadowController( this, allowPhysicsMovement, allowPhysicsRotation );
  913. m_pShadow->MaxSpeed( maxSpeed, maxAngularSpeed );
  914. // This really should be in the game code, but do this here because the game may (does) use
  915. // shadow/AI control as a collision filter indicator.
  916. RecheckCollisionFilter();
  917. }
  918. }
  919. void CPhysicsObject::UpdateShadow( const Vector &targetPosition, const QAngle &targetAngles, bool tempDisableGravity, float timeOffset )
  920. {
  921. if ( tempDisableGravity != m_shadowTempGravityDisable )
  922. {
  923. m_shadowTempGravityDisable = tempDisableGravity;
  924. if ( !m_pShadow || m_pShadow->AllowsTranslation() )
  925. {
  926. EnableGravity( !m_shadowTempGravityDisable );
  927. }
  928. }
  929. if ( m_pShadow )
  930. {
  931. m_pShadow->Update( targetPosition, targetAngles, timeOffset );
  932. }
  933. }
  934. void CPhysicsObject::RemoveShadowController()
  935. {
  936. if ( m_pShadow )
  937. {
  938. CPhysicsEnvironment *pVEnv = GetVPhysicsEnvironment();
  939. pVEnv->DestroyShadowController( m_pShadow );
  940. m_pShadow = NULL;
  941. }
  942. }
  943. // Back door to allow save/restore of backlink between shadow controller and physics object
  944. void CPhysicsObject::RestoreShadowController( IPhysicsShadowController *pShadowController )
  945. {
  946. Assert( !m_pShadow );
  947. m_pShadow = pShadowController;
  948. }
  949. int CPhysicsObject::GetShadowPosition( Vector *position, QAngle *angles ) const
  950. {
  951. IVP_U_Matrix matrix;
  952. IVP_Environment *pEnv = m_pObject->get_environment();
  953. double psi = pEnv->get_next_PSI_time().get_seconds();
  954. m_pObject->calc_at_matrix( psi, &matrix );
  955. if ( angles )
  956. {
  957. ConvertRotationToHL( matrix, *angles );
  958. }
  959. if ( position )
  960. {
  961. ConvertPositionToHL( matrix.vv, *position );
  962. }
  963. return 1;
  964. }
  965. IPhysicsShadowController *CPhysicsObject::GetShadowController( void ) const
  966. {
  967. return m_pShadow;
  968. }
  969. const CPhysCollide *CPhysicsObject::GetCollide( void ) const
  970. {
  971. return m_pCollide;
  972. }
  973. IVP_SurfaceManager *CPhysicsObject::GetSurfaceManager( void ) const
  974. {
  975. if ( m_collideType != COLLIDE_BALL )
  976. {
  977. return m_pObject->get_surface_manager();
  978. }
  979. return NULL;
  980. }
  981. float CPhysicsObject::GetDragInDirection( const IVP_U_Float_Point &velocity ) const
  982. {
  983. IVP_U_Float_Point local;
  984. const IVP_U_Matrix *m_world_f_core = m_pObject->get_core()->get_m_world_f_core_PSI();
  985. m_world_f_core->vimult3( &velocity, &local );
  986. return m_dragCoefficient * IVP_Inline_Math::fabsd( local.k[0] * m_dragBasis.x ) +
  987. IVP_Inline_Math::fabsd( local.k[1] * m_dragBasis.y ) +
  988. IVP_Inline_Math::fabsd( local.k[2] * m_dragBasis.z );
  989. }
  990. float CPhysicsObject::GetAngularDragInDirection( const IVP_U_Float_Point &angVelocity ) const
  991. {
  992. return m_angDragCoefficient * IVP_Inline_Math::fabsd( angVelocity.k[0] * m_angDragBasis.x ) +
  993. IVP_Inline_Math::fabsd( angVelocity.k[1] * m_angDragBasis.y ) +
  994. IVP_Inline_Math::fabsd( angVelocity.k[2] * m_angDragBasis.z );
  995. }
  996. const char *CPhysicsObject::GetName() const
  997. {
  998. return m_pObject->get_name();
  999. }
  1000. void CPhysicsObject::SetMaterialIndex( int materialIndex )
  1001. {
  1002. if ( m_materialIndex == materialIndex )
  1003. return;
  1004. m_materialIndex = materialIndex;
  1005. IVP_Material *pMaterial = physprops->GetIVPMaterial( materialIndex );
  1006. Assert(pMaterial);
  1007. m_pObject->l_default_material = pMaterial;
  1008. m_callbacks |= CALLBACK_ENABLING_COLLISION;
  1009. BEGIN_IVP_ALLOCATION();
  1010. m_pObject->recompile_material_changed();
  1011. END_IVP_ALLOCATION();
  1012. m_callbacks &= ~CALLBACK_ENABLING_COLLISION;
  1013. if ( GetShadowController() )
  1014. {
  1015. GetShadowController()->ObjectMaterialChanged( materialIndex );
  1016. }
  1017. }
  1018. // convert square velocity magnitude from IVP to HL
  1019. float CPhysicsObject::GetEnergy() const
  1020. {
  1021. IVP_Core *pCore = m_pObject->get_core();
  1022. IVP_FLOAT energy = 0.0f;
  1023. IVP_U_Float_Point tmp;
  1024. energy = 0.5f * pCore->get_mass() * pCore->speed.dot_product(&pCore->speed); // 1/2mvv
  1025. tmp.set_pairwise_mult(&pCore->rot_speed, pCore->get_rot_inertia()); // wI
  1026. energy += 0.5f * tmp.dot_product(&pCore->rot_speed); // 1/2mvv + 1/2wIw
  1027. return ConvertEnergyToHL( energy );
  1028. }
  1029. float CPhysicsObject::ComputeShadowControl( const hlshadowcontrol_params_t &params, float secondsToArrival, float dt )
  1030. {
  1031. return ComputeShadowControllerHL( this, params, secondsToArrival, dt );
  1032. }
  1033. float CPhysicsObject::GetSphereRadius() const
  1034. {
  1035. if ( m_collideType != COLLIDE_BALL )
  1036. return 0;
  1037. return ConvertDistanceToHL( m_pObject->to_ball()->get_radius() );
  1038. }
  1039. float CPhysicsObject::CalculateLinearDrag( const Vector &unitDirection ) const
  1040. {
  1041. IVP_U_Float_Point ivpDir;
  1042. ConvertDirectionToIVP( unitDirection, ivpDir );
  1043. return GetDragInDirection( ivpDir );
  1044. }
  1045. float CPhysicsObject::CalculateAngularDrag( const Vector &objectSpaceRotationAxis ) const
  1046. {
  1047. IVP_U_Float_Point ivpAxis;
  1048. ConvertDirectionToIVP( objectSpaceRotationAxis, ivpAxis );
  1049. // drag factor is per-radian, convert to per-degree
  1050. return GetAngularDragInDirection( ivpAxis ) * DEG2RAD(1.0);
  1051. }
  1052. void CPhysicsObject::BecomeTrigger()
  1053. {
  1054. if ( IsTrigger() )
  1055. return;
  1056. if ( GetShadowController() )
  1057. {
  1058. // triggers won't have the standard collisions, so the material change is no longer necessary
  1059. // also: This will fix problems with surfaceprops if the trigger becomes a fluid.
  1060. GetShadowController()->UseShadowMaterial( false );
  1061. }
  1062. EnableDrag( false );
  1063. EnableGravity( false );
  1064. // UNDONE: Use defaults here? Do we want object sets by default?
  1065. IVP_Template_Phantom trigger;
  1066. trigger.manage_intruding_cores = IVP_TRUE; // manage a list of intruded objects
  1067. trigger.manage_sleeping_cores = IVP_TRUE; // don't untouch/touch on sleep/wake
  1068. trigger.dont_check_for_unmoveables = IVP_TRUE;
  1069. trigger.exit_policy_extra_radius = 0.1f; // relatively strict exit check [m]
  1070. bool enableCollisions = IsCollisionEnabled();
  1071. EnableCollisions( false );
  1072. BEGIN_IVP_ALLOCATION();
  1073. m_pObject->convert_to_phantom( &trigger );
  1074. END_IVP_ALLOCATION();
  1075. // hook up events
  1076. CPhysicsEnvironment *pVEnv = GetVPhysicsEnvironment();
  1077. pVEnv->PhantomAdd( this );
  1078. EnableCollisions( enableCollisions );
  1079. }
  1080. void CPhysicsObject::RemoveTrigger()
  1081. {
  1082. IVP_Controller_Phantom *pController = m_pObject->get_controller_phantom();
  1083. // NOTE: This will remove the back-link in the object
  1084. delete pController;
  1085. }
  1086. bool CPhysicsObject::IsTrigger() const
  1087. {
  1088. return m_pObject->get_controller_phantom() != NULL ? true : false;
  1089. }
  1090. bool CPhysicsObject::IsFluid() const
  1091. {
  1092. IVP_Controller_Phantom *pController = m_pObject->get_controller_phantom();
  1093. if ( pController )
  1094. {
  1095. // UNDONE: Make a base class for triggers? IPhysicsTrigger?
  1096. // and derive fluids and any other triggers from that class
  1097. // then you can ask that class what to do here.
  1098. if ( pController->client_data )
  1099. return true;
  1100. }
  1101. return false;
  1102. }
  1103. // sets the object to be hinged. Fixed it place, but able to rotate around one axis.
  1104. void CPhysicsObject::BecomeHinged( int localAxis )
  1105. {
  1106. if ( IsMoveable() )
  1107. {
  1108. float savedMass = GetMass();
  1109. IVP_U_Float_Hesse *iri = (IVP_U_Float_Hesse *)m_pObject->get_core()->get_inv_rot_inertia();
  1110. float savedRI[3];
  1111. for ( int i = 0; i < 3; i++ )
  1112. savedRI[i] = iri->k[i];
  1113. SetMass( VPHYSICS_MAX_MASS );
  1114. IVP_U_Float_Hesse tmp = *iri;
  1115. #if 0
  1116. for ( i = 0; i < 3; i++ )
  1117. tmp.k[i] = savedRI[i];
  1118. #else
  1119. int localAxisIVP = ConvertCoordinateAxisToIVP(localAxis);
  1120. tmp.k[localAxisIVP] = savedRI[localAxisIVP];
  1121. #endif
  1122. SetMass( savedMass );
  1123. *iri = tmp;
  1124. }
  1125. m_hingedAxis = localAxis+1;
  1126. }
  1127. void CPhysicsObject::RemoveHinged()
  1128. {
  1129. m_hingedAxis = 0;
  1130. m_pObject->get_core()->calc_calc();
  1131. }
  1132. // dumps info about the object to Msg()
  1133. void CPhysicsObject::OutputDebugInfo() const
  1134. {
  1135. Msg("-----------------\nObject: %s\n", m_pObject->get_name());
  1136. Msg("Mass: %.1f (inv %.3f)\n", GetMass(), GetInvMass() );
  1137. Vector inertia = GetInertia();
  1138. Vector invInertia = GetInvInertia();
  1139. Msg("Inertia: %.2f, %.2f, %.2f (inv %.3f, %.3f, %.3f)\n", inertia.x, inertia.y, inertia.z, invInertia.x, invInertia.y, invInertia.z );
  1140. Vector speed, angSpeed;
  1141. GetVelocity( &speed, &angSpeed );
  1142. Msg("Velocity: %.2f, %.2f, %.2f \n", speed.x, speed.y, speed.z );
  1143. Msg("Ang Velocity: %.2f, %.2f, %.2f \n", angSpeed.x, angSpeed.y, angSpeed.z );
  1144. float damp, angDamp;
  1145. GetDamping( &damp, &angDamp );
  1146. Msg("Damping %.2f linear, %.2f angular\n", damp, angDamp );
  1147. Msg("Linear Drag: %.2f, %.2f, %.2f (factor %.2f)\n", m_dragBasis.x, m_dragBasis.y, m_dragBasis.z, m_dragCoefficient );
  1148. Msg("Angular Drag: %.2f, %.2f, %.2f (factor %.2f)\n", m_angDragBasis.x, m_angDragBasis.y, m_angDragBasis.z, m_angDragCoefficient );
  1149. if ( IsHinged() )
  1150. {
  1151. const char *pAxisNames[] = {"x", "y", "z"};
  1152. Msg("Hinged on %s axis\n", pAxisNames[m_hingedAxis-1] );
  1153. }
  1154. Msg("attached to %d controllers\n", m_pObject->get_core()->controllers_of_core.len() );
  1155. for (int k = m_pObject->get_core()->controllers_of_core.len()-1; k>=0;k--)
  1156. {
  1157. // NOTE: Set a breakpoint here and take a look at what it's hooked to
  1158. IVP_Controller *pController = m_pObject->get_core()->controllers_of_core.element_at(k);
  1159. Msg("%d) %s\n", k, pController->get_controller_name() );
  1160. }
  1161. Msg("State: %s, Collision %s, Motion %s, %sFlags %04X (game %04x, index %d)\n",
  1162. IsAsleep() ? "Asleep" : "Awake",
  1163. IsCollisionEnabled() ? "Enabled" : "Disabled",
  1164. IsStatic() ? "Static" : (IsMotionEnabled() ? "Enabled" : "Disabled"),
  1165. (GetCallbackFlags() & CALLBACK_MARKED_FOR_TEST) ? "Debug! " : "",
  1166. (int)GetCallbackFlags(), (int)GetGameFlags(), (int)GetGameIndex() );
  1167. float matDensity = 0;
  1168. float matThickness = 0;
  1169. float matFriction = 0;
  1170. float matElasticity = 0;
  1171. physprops->GetPhysicsProperties( GetMaterialIndexInternal(), &matDensity, &matThickness, &matFriction, &matElasticity );
  1172. Msg("Material: %s : density(%.1f), thickness(%.2f), friction(%.2f), elasticity(%.2f)\n", physprops->GetPropName(GetMaterialIndexInternal()),
  1173. matDensity, matThickness, matFriction, matElasticity );
  1174. if ( GetCollide() )
  1175. {
  1176. OutputCollideDebugInfo( GetCollide() );
  1177. }
  1178. }
  1179. bool CPhysicsObject::IsAttachedToConstraint( bool bExternalOnly ) const
  1180. {
  1181. if ( m_pObject )
  1182. {
  1183. for (int k = m_pObject->get_core()->controllers_of_core.len()-1; k>=0;k--)
  1184. {
  1185. IVP_Controller *pController = m_pObject->get_core()->controllers_of_core.element_at(k);
  1186. if ( pController->get_controller_priority() == IVP_CP_CONSTRAINTS )
  1187. {
  1188. if ( !bExternalOnly || IsExternalConstraint(pController, GetGameData()) )
  1189. return true;
  1190. }
  1191. }
  1192. }
  1193. return false;
  1194. }
  1195. static void InitObjectTemplate( IVP_Template_Real_Object &objectTemplate, int materialIndex, objectparams_t *pParams, bool isStatic )
  1196. {
  1197. objectTemplate.mass = pParams->mass;
  1198. objectTemplate.mass = clamp( objectTemplate.mass, VPHYSICS_MIN_MASS, VPHYSICS_MAX_MASS );
  1199. if ( materialIndex >= 0 )
  1200. {
  1201. objectTemplate.material = physprops->GetIVPMaterial( materialIndex );
  1202. }
  1203. else
  1204. {
  1205. materialIndex = physprops->GetSurfaceIndex( "default" );
  1206. objectTemplate.material = physprops->GetIVPMaterial( materialIndex );
  1207. }
  1208. // HACKHACK: Do something with this name?
  1209. BEGIN_IVP_ALLOCATION();
  1210. if ( IsPC() )
  1211. {
  1212. objectTemplate.set_name(pParams->pName);
  1213. }
  1214. END_IVP_ALLOCATION();
  1215. #if USE_COLLISION_GROUP_STRING
  1216. objectTemplate.set_nocoll_group_ident( NULL );
  1217. #endif
  1218. objectTemplate.physical_unmoveable = isStatic ? IVP_TRUE : IVP_FALSE;
  1219. objectTemplate.rot_inertia_is_factor = IVP_TRUE;
  1220. float inertia = pParams->inertia;
  1221. // don't allow <=0 inertia!!!!
  1222. if ( inertia <= 0 )
  1223. inertia = 1.0;
  1224. if ( inertia > 1e18f )
  1225. inertia = 1e18f;
  1226. objectTemplate.rot_inertia.set(inertia, inertia, inertia);
  1227. objectTemplate.rot_speed_damp_factor.set(pParams->rotdamping, pParams->rotdamping, pParams->rotdamping);
  1228. objectTemplate.speed_damp_factor = pParams->damping;
  1229. objectTemplate.auto_check_rot_inertia = pParams->rotInertiaLimit;
  1230. }
  1231. CPhysicsObject *CreatePhysicsObject( CPhysicsEnvironment *pEnvironment, const CPhysCollide *pCollisionModel, int materialIndex, const Vector &position, const QAngle& angles, objectparams_t *pParams, bool isStatic )
  1232. {
  1233. if ( materialIndex < 0 )
  1234. {
  1235. materialIndex = physprops->GetSurfaceIndex( "default" );
  1236. }
  1237. AssertOnce(materialIndex>=0 && materialIndex<127);
  1238. IVP_Template_Real_Object objectTemplate;
  1239. IVP_U_Quat rotation;
  1240. IVP_U_Point pos;
  1241. Assert( position.IsValid() );
  1242. Assert( angles.IsValid() );
  1243. #if _WIN32
  1244. if ( !position.IsValid() || !angles.IsValid() )
  1245. {
  1246. DebuggerBreakIfDebugging();
  1247. Warning("Invalid initial position on %s\n", pParams->pName );
  1248. Vector *pPos = (Vector *)&position;
  1249. QAngle *pRot = (QAngle *)&angles;
  1250. if ( !pPos->IsValid() )
  1251. pPos->Init();
  1252. if ( !pRot->IsValid() )
  1253. pRot->Init();
  1254. }
  1255. #endif
  1256. ConvertRotationToIVP( angles, rotation );
  1257. ConvertPositionToIVP( position, pos );
  1258. InitObjectTemplate( objectTemplate, materialIndex, pParams, isStatic );
  1259. IVP_U_Matrix massCenterMatrix;
  1260. massCenterMatrix.init();
  1261. if ( pParams->massCenterOverride )
  1262. {
  1263. IVP_U_Point center;
  1264. ConvertPositionToIVP( *pParams->massCenterOverride, center );
  1265. massCenterMatrix.shift_os( &center );
  1266. objectTemplate.mass_center_override = &massCenterMatrix;
  1267. }
  1268. CPhysicsObject *pObject = new CPhysicsObject();
  1269. short collideType;
  1270. IVP_SurfaceManager *pSurman = CreateSurfaceManager( pCollisionModel, collideType );
  1271. if ( !pSurman )
  1272. return NULL;
  1273. pObject->m_collideType = collideType;
  1274. pObject->m_asleepSinceCreation = true;
  1275. BEGIN_IVP_ALLOCATION();
  1276. IVP_Polygon *realObject = pEnvironment->GetIVPEnvironment()->create_polygon(pSurman, &objectTemplate, &rotation, &pos);
  1277. pObject->Init( pCollisionModel, realObject, materialIndex, pParams->volume, pParams->dragCoefficient, pParams->dragCoefficient );
  1278. pObject->SetGameData( pParams->pGameData );
  1279. if ( pParams->enableCollisions )
  1280. {
  1281. pObject->EnableCollisions( true );
  1282. }
  1283. if ( !isStatic && pParams->dragCoefficient != 0.0f )
  1284. {
  1285. pObject->EnableDrag( true );
  1286. }
  1287. END_IVP_ALLOCATION();
  1288. return pObject;
  1289. }
  1290. CPhysicsObject *CreatePhysicsSphere( CPhysicsEnvironment *pEnvironment, float radius, int materialIndex, const Vector &position, const QAngle &angles, objectparams_t *pParams, bool isStatic )
  1291. {
  1292. IVP_U_Quat rotation;
  1293. IVP_U_Point pos;
  1294. ConvertRotationToIVP( angles, rotation );
  1295. ConvertPositionToIVP( position, pos );
  1296. IVP_Template_Real_Object objectTemplate;
  1297. InitObjectTemplate( objectTemplate, materialIndex, pParams, isStatic );
  1298. IVP_Template_Ball ballTemplate;
  1299. ballTemplate.radius = ConvertDistanceToIVP( radius );
  1300. MEM_ALLOC_CREDIT();
  1301. IVP_Ball *realObject = pEnvironment->GetIVPEnvironment()->create_ball( &ballTemplate, &objectTemplate, &rotation, &pos );
  1302. float volume = pParams->volume;
  1303. if ( volume <= 0 )
  1304. {
  1305. volume = 4.0f * radius * radius * radius * M_PI / 3.0f;
  1306. }
  1307. CPhysicsObject *pObject = new CPhysicsObject();
  1308. pObject->Init( NULL, realObject, materialIndex, volume, 0, 0 ); //, pParams->dragCoefficient, pParams->dragCoefficient
  1309. pObject->SetGameData( pParams->pGameData );
  1310. if ( pParams->enableCollisions )
  1311. {
  1312. pObject->EnableCollisions( true );
  1313. }
  1314. // drag is not supported on spheres
  1315. //pObject->EnableDrag( false );
  1316. return pObject;
  1317. }
  1318. class CMaterialIndexOps : public CDefSaveRestoreOps
  1319. {
  1320. public:
  1321. // save data type interface
  1322. virtual void Save( const SaveRestoreFieldInfo_t &fieldInfo, ISave *pSave )
  1323. {
  1324. int materialIndex = *((int *)fieldInfo.pField);
  1325. const char *pMaterialName = physprops->GetPropName( materialIndex );
  1326. if ( !pMaterialName )
  1327. {
  1328. pMaterialName = physprops->GetPropName( 0 );
  1329. }
  1330. int len = strlen(pMaterialName) + 1;
  1331. pSave->WriteInt( &len );
  1332. pSave->WriteString( pMaterialName );
  1333. }
  1334. virtual void Restore( const SaveRestoreFieldInfo_t &fieldInfo, IRestore *pRestore )
  1335. {
  1336. char nameBuf[1024];
  1337. int nameLen = pRestore->ReadInt();
  1338. pRestore->ReadString( nameBuf, sizeof(nameBuf), nameLen );
  1339. int *pMaterialIndex = (int *)fieldInfo.pField;
  1340. *pMaterialIndex = physprops->GetSurfaceIndex( nameBuf );
  1341. if ( *pMaterialIndex < 0 )
  1342. {
  1343. *pMaterialIndex = 0;
  1344. }
  1345. }
  1346. virtual bool IsEmpty( const SaveRestoreFieldInfo_t &fieldInfo )
  1347. {
  1348. int *pMaterialIndex = (int *)fieldInfo.pField;
  1349. return (*pMaterialIndex == 0);
  1350. }
  1351. virtual void MakeEmpty( const SaveRestoreFieldInfo_t &fieldInfo )
  1352. {
  1353. int *pMaterialIndex = (int *)fieldInfo.pField;
  1354. *pMaterialIndex = 0;
  1355. }
  1356. };
  1357. static CMaterialIndexOps g_MaterialIndexDataOps;
  1358. ISaveRestoreOps* MaterialIndexDataOps()
  1359. {
  1360. return &g_MaterialIndexDataOps;
  1361. }
  1362. BEGIN_SIMPLE_DATADESC( vphysics_save_cphysicsobject_t )
  1363. // DEFINE_FIELD( pCollide, FIELD_??? ), // don't save this
  1364. // DEFINE_FIELD( pName, FIELD_??? ), // don't save this
  1365. DEFINE_FIELD( sphereRadius, FIELD_FLOAT ),
  1366. DEFINE_FIELD( isStatic, FIELD_BOOLEAN ),
  1367. DEFINE_FIELD( collisionEnabled, FIELD_BOOLEAN ),
  1368. DEFINE_FIELD( gravityEnabled, FIELD_BOOLEAN ),
  1369. DEFINE_FIELD( dragEnabled, FIELD_BOOLEAN ),
  1370. DEFINE_FIELD( motionEnabled, FIELD_BOOLEAN ),
  1371. DEFINE_FIELD( isAsleep, FIELD_BOOLEAN ),
  1372. DEFINE_FIELD( isTrigger, FIELD_BOOLEAN ),
  1373. DEFINE_FIELD( asleepSinceCreation, FIELD_BOOLEAN ),
  1374. DEFINE_FIELD( hasTouchedDynamic, FIELD_BOOLEAN ),
  1375. DEFINE_CUSTOM_FIELD( materialIndex, &g_MaterialIndexDataOps ),
  1376. DEFINE_FIELD( mass, FIELD_FLOAT ),
  1377. DEFINE_FIELD( rotInertia, FIELD_VECTOR ),
  1378. DEFINE_FIELD( speedDamping, FIELD_FLOAT ),
  1379. DEFINE_FIELD( rotSpeedDamping, FIELD_FLOAT ),
  1380. DEFINE_FIELD( massCenterOverride, FIELD_VECTOR ),
  1381. DEFINE_FIELD( callbacks, FIELD_INTEGER ),
  1382. DEFINE_FIELD( gameFlags, FIELD_INTEGER ),
  1383. DEFINE_FIELD( contentsMask, FIELD_INTEGER ),
  1384. DEFINE_FIELD( volume, FIELD_FLOAT ),
  1385. DEFINE_FIELD( dragCoefficient, FIELD_FLOAT ),
  1386. DEFINE_FIELD( angDragCoefficient, FIELD_FLOAT ),
  1387. DEFINE_FIELD( hasShadowController,FIELD_BOOLEAN ),
  1388. //DEFINE_VPHYSPTR( pShadow ),
  1389. DEFINE_FIELD( origin, FIELD_POSITION_VECTOR ),
  1390. DEFINE_FIELD( angles, FIELD_VECTOR ),
  1391. DEFINE_FIELD( velocity, FIELD_VECTOR ),
  1392. DEFINE_FIELD( angVelocity, FIELD_VECTOR ),
  1393. DEFINE_FIELD( collideType, FIELD_SHORT ),
  1394. DEFINE_FIELD( gameIndex, FIELD_SHORT ),
  1395. DEFINE_FIELD( hingeAxis, FIELD_INTEGER ),
  1396. END_DATADESC()
  1397. bool CPhysicsObject::IsCollisionEnabled() const
  1398. {
  1399. return GetObject()->is_collision_detection_enabled() ? true : false;
  1400. }
  1401. void CPhysicsObject::WriteToTemplate( vphysics_save_cphysicsobject_t &objectTemplate )
  1402. {
  1403. if ( m_collideType == COLLIDE_BALL )
  1404. {
  1405. objectTemplate.pCollide = NULL;
  1406. objectTemplate.sphereRadius = GetSphereRadius();
  1407. }
  1408. else
  1409. {
  1410. objectTemplate.pCollide = GetCollide();
  1411. objectTemplate.sphereRadius = 0;
  1412. }
  1413. objectTemplate.isStatic = IsStatic();
  1414. objectTemplate.collisionEnabled = IsCollisionEnabled();
  1415. objectTemplate.gravityEnabled = IsGravityEnabled();
  1416. objectTemplate.dragEnabled = IsDragEnabled();
  1417. objectTemplate.motionEnabled = IsMotionEnabled();
  1418. objectTemplate.isAsleep = IsAsleep();
  1419. objectTemplate.isTrigger = IsTrigger();
  1420. objectTemplate.asleepSinceCreation = m_asleepSinceCreation;
  1421. objectTemplate.materialIndex = m_materialIndex;
  1422. objectTemplate.mass = GetMass();
  1423. objectTemplate.rotInertia = GetInertia();
  1424. GetDamping( &objectTemplate.speedDamping, &objectTemplate.rotSpeedDamping );
  1425. objectTemplate.massCenterOverride.Init();
  1426. if ( !IsMassCenterAtDefault() )
  1427. {
  1428. objectTemplate.massCenterOverride = GetMassCenterLocalSpace();
  1429. }
  1430. objectTemplate.callbacks = m_callbacks;
  1431. objectTemplate.gameFlags = m_gameFlags;
  1432. objectTemplate.volume = GetVolume();
  1433. objectTemplate.dragCoefficient = m_dragCoefficient;
  1434. objectTemplate.angDragCoefficient = m_angDragCoefficient;
  1435. objectTemplate.pShadow = m_pShadow;
  1436. objectTemplate.hasShadowController = (m_pShadow != NULL) ? true : false;
  1437. objectTemplate.hasTouchedDynamic = HasTouchedDynamic();
  1438. //bool m_shadowTempGravityDisable;
  1439. objectTemplate.collideType = m_collideType;
  1440. objectTemplate.gameIndex = m_gameIndex;
  1441. objectTemplate.contentsMask = m_contentsMask;
  1442. objectTemplate.hingeAxis = m_hingedAxis;
  1443. GetPosition( &objectTemplate.origin, &objectTemplate.angles );
  1444. GetVelocity( &objectTemplate.velocity, &objectTemplate.angVelocity );
  1445. }
  1446. void CPhysicsObject::InitFromTemplate( CPhysicsEnvironment *pEnvironment, void *pGameData, const vphysics_save_cphysicsobject_t &objectTemplate )
  1447. {
  1448. MEM_ALLOC_CREDIT();
  1449. m_collideType = objectTemplate.collideType;
  1450. IVP_Template_Real_Object ivpObjectTemplate;
  1451. IVP_U_Quat rotation;
  1452. IVP_U_Point pos;
  1453. ConvertRotationToIVP( objectTemplate.angles, rotation );
  1454. ConvertPositionToIVP( objectTemplate.origin, pos );
  1455. ivpObjectTemplate.mass = objectTemplate.mass;
  1456. if ( objectTemplate.materialIndex >= 0 )
  1457. {
  1458. ivpObjectTemplate.material = physprops->GetIVPMaterial( objectTemplate.materialIndex );
  1459. }
  1460. else
  1461. {
  1462. ivpObjectTemplate.material = physprops->GetIVPMaterial( physprops->GetSurfaceIndex( "default" ) );
  1463. }
  1464. Assert( ivpObjectTemplate.material );
  1465. // HACKHACK: Pass this name in for debug
  1466. ivpObjectTemplate.set_name(objectTemplate.pName);
  1467. #if USE_COLLISION_GROUP_STRING
  1468. ivpObjectTemplate.set_nocoll_group_ident( NULL );
  1469. #endif
  1470. ivpObjectTemplate.physical_unmoveable = objectTemplate.isStatic ? IVP_TRUE : IVP_FALSE;
  1471. ivpObjectTemplate.rot_inertia_is_factor = IVP_TRUE;
  1472. ivpObjectTemplate.rot_inertia.set( 1,1,1 );
  1473. ivpObjectTemplate.rot_speed_damp_factor.set( objectTemplate.rotSpeedDamping, objectTemplate.rotSpeedDamping, objectTemplate.rotSpeedDamping );
  1474. ivpObjectTemplate.speed_damp_factor = objectTemplate.speedDamping;
  1475. IVP_U_Matrix massCenterMatrix;
  1476. massCenterMatrix.init();
  1477. if ( objectTemplate.massCenterOverride != vec3_origin )
  1478. {
  1479. IVP_U_Point center;
  1480. ConvertPositionToIVP( objectTemplate.massCenterOverride, center );
  1481. massCenterMatrix.shift_os( &center );
  1482. ivpObjectTemplate.mass_center_override = &massCenterMatrix;
  1483. }
  1484. IVP_Real_Object *realObject = NULL;
  1485. if ( m_collideType == COLLIDE_BALL )
  1486. {
  1487. IVP_Template_Ball ballTemplate;
  1488. ballTemplate.radius = ConvertDistanceToIVP( objectTemplate.sphereRadius );
  1489. realObject = pEnvironment->GetIVPEnvironment()->create_ball( &ballTemplate, &ivpObjectTemplate, &rotation, &pos );
  1490. }
  1491. else
  1492. {
  1493. short collideType;
  1494. IVP_SurfaceManager *surman = CreateSurfaceManager( objectTemplate.pCollide, collideType );
  1495. m_collideType = collideType;
  1496. realObject = pEnvironment->GetIVPEnvironment()->create_polygon(surman, &ivpObjectTemplate, &rotation, &pos);
  1497. }
  1498. m_pObject = realObject;
  1499. SetInertia( objectTemplate.rotInertia );
  1500. Init( objectTemplate.pCollide, realObject, objectTemplate.materialIndex, objectTemplate.volume, objectTemplate.dragCoefficient, objectTemplate.dragCoefficient );
  1501. SetCallbackFlags( (unsigned short) objectTemplate.callbacks );
  1502. SetGameFlags( (unsigned short) objectTemplate.gameFlags );
  1503. SetGameIndex( objectTemplate.gameIndex );
  1504. SetGameData( pGameData );
  1505. SetContents( objectTemplate.contentsMask );
  1506. if ( objectTemplate.dragEnabled )
  1507. {
  1508. Assert( !objectTemplate.isStatic );
  1509. EnableDrag( true );
  1510. }
  1511. if ( !objectTemplate.motionEnabled )
  1512. {
  1513. Assert( !objectTemplate.isStatic );
  1514. EnableMotion( false );
  1515. }
  1516. if ( objectTemplate.isTrigger )
  1517. {
  1518. BecomeTrigger();
  1519. }
  1520. if ( !objectTemplate.gravityEnabled )
  1521. {
  1522. EnableGravity( false );
  1523. }
  1524. if ( objectTemplate.collisionEnabled )
  1525. {
  1526. EnableCollisions( true );
  1527. }
  1528. // will wake up the object
  1529. if ( objectTemplate.velocity.LengthSqr() != 0 || objectTemplate.angVelocity.LengthSqr() != 0 )
  1530. {
  1531. SetVelocityInstantaneous( &objectTemplate.velocity, &objectTemplate.angVelocity );
  1532. if ( objectTemplate.isAsleep )
  1533. {
  1534. Sleep();
  1535. }
  1536. }
  1537. m_asleepSinceCreation = objectTemplate.asleepSinceCreation;
  1538. if ( !objectTemplate.isAsleep )
  1539. {
  1540. Assert( !objectTemplate.isStatic );
  1541. Wake();
  1542. }
  1543. if ( objectTemplate.hingeAxis )
  1544. {
  1545. BecomeHinged( objectTemplate.hingeAxis-1 );
  1546. }
  1547. if ( objectTemplate.hasTouchedDynamic )
  1548. {
  1549. SetTouchedDynamic();
  1550. }
  1551. m_pShadow = NULL;
  1552. }
  1553. bool SavePhysicsObject( const physsaveparams_t &params, CPhysicsObject *pObject )
  1554. {
  1555. vphysics_save_cphysicsobject_t objectTemplate;
  1556. memset( &objectTemplate, 0, sizeof(objectTemplate) );
  1557. pObject->WriteToTemplate( objectTemplate );
  1558. params.pSave->WriteAll( &objectTemplate );
  1559. if ( objectTemplate.hasShadowController )
  1560. {
  1561. return SavePhysicsShadowController( params, objectTemplate.pShadow );
  1562. }
  1563. return true;
  1564. }
  1565. bool RestorePhysicsObject( const physrestoreparams_t &params, CPhysicsObject **ppObject )
  1566. {
  1567. vphysics_save_cphysicsobject_t objectTemplate;
  1568. memset( &objectTemplate, 0, sizeof(objectTemplate) );
  1569. params.pRestore->ReadAll( &objectTemplate );
  1570. Assert(objectTemplate.origin.IsValid());
  1571. Assert(objectTemplate.angles.IsValid());
  1572. objectTemplate.pCollide = params.pCollisionModel;
  1573. objectTemplate.pName = params.pName;
  1574. *ppObject = new CPhysicsObject();
  1575. postrestore_objectlist_t entry;
  1576. entry.Defaults();
  1577. if ( objectTemplate.collisionEnabled )
  1578. {
  1579. // queue up the collision enable for these in case their entities have other dependent
  1580. // physics handlers (like controllers) that need to be restored before callbacks are useful
  1581. entry.pObject = *ppObject;
  1582. entry.enableCollisions = true;
  1583. objectTemplate.collisionEnabled = false;
  1584. }
  1585. (*ppObject)->InitFromTemplate( static_cast<CPhysicsEnvironment *>(params.pEnvironment), params.pGameData, objectTemplate );
  1586. if ( (*ppObject)->IsAsleep() && !(*ppObject)->m_asleepSinceCreation && !(*ppObject)->IsStatic() )
  1587. {
  1588. entry.pObject = *ppObject;
  1589. entry.growFriction = true;
  1590. }
  1591. if ( entry.pObject )
  1592. {
  1593. g_PostRestoreObjectList.AddToTail( entry );
  1594. }
  1595. if ( objectTemplate.hasShadowController )
  1596. {
  1597. bool restored = RestorePhysicsShadowControllerInternal( params, &objectTemplate.pShadow, *ppObject );
  1598. (*ppObject)->RestoreShadowController( objectTemplate.pShadow );
  1599. return restored;
  1600. }
  1601. return true;
  1602. }
  1603. IPhysicsObject *CreateObjectFromBuffer( CPhysicsEnvironment *pEnvironment, void *pGameData, unsigned char *pBuffer, unsigned int bufferSize, bool enableCollisions )
  1604. {
  1605. CPhysicsObject *pObject = new CPhysicsObject();
  1606. if ( bufferSize >= sizeof(vphysics_save_cphysicsobject_t))
  1607. {
  1608. vphysics_save_cphysicsobject_t *pTemplate = reinterpret_cast<vphysics_save_cphysicsobject_t *>(pBuffer);
  1609. pTemplate->hasShadowController = false; // this hasn't been saved separately so cannot be supported via this path
  1610. pObject->InitFromTemplate( pEnvironment, pGameData, *pTemplate );
  1611. if ( pTemplate->collisionEnabled && enableCollisions )
  1612. {
  1613. pObject->EnableCollisions(true);
  1614. }
  1615. return pObject;
  1616. }
  1617. return NULL;
  1618. }
  1619. IPhysicsObject *CreateObjectFromBuffer_UseExistingMemory( CPhysicsEnvironment *pEnvironment, void *pGameData, unsigned char *pBuffer, unsigned int bufferSize, CPhysicsObject *pExistingMemory )
  1620. {
  1621. if ( bufferSize >= sizeof(vphysics_save_cphysicsobject_t))
  1622. {
  1623. vphysics_save_cphysicsobject_t *pTemplate = reinterpret_cast<vphysics_save_cphysicsobject_t *>(pBuffer);
  1624. // Allow the placement new. If we don't do this, then it'll get a compile error because new
  1625. // might be defined as the special form in MEMALL_DEBUG_NEW.
  1626. #include "tier0/memdbgoff.h"
  1627. pExistingMemory = new ( pExistingMemory ) CPhysicsObject();
  1628. #include "tier0/memdbgon.h"
  1629. pExistingMemory->InitFromTemplate( pEnvironment, pGameData, *pTemplate );
  1630. if ( pTemplate->collisionEnabled )
  1631. {
  1632. pExistingMemory->EnableCollisions(true);
  1633. }
  1634. return pExistingMemory;
  1635. }
  1636. return NULL;
  1637. }
  1638. // regenerate the friction systems for these objects. Because when it was saved it had them (came to rest with the contact points).
  1639. // So now we need to recreate them or some objects may not wake up when this object (or its neighbors) are deleted.
  1640. void PostRestorePhysicsObject()
  1641. {
  1642. for ( int i = g_PostRestoreObjectList.Count()-1; i >= 0; --i )
  1643. {
  1644. if ( g_PostRestoreObjectList[i].pObject )
  1645. {
  1646. if ( g_PostRestoreObjectList[i].growFriction )
  1647. {
  1648. g_PostRestoreObjectList[i].pObject->GetObject()->force_grow_friction_system();
  1649. }
  1650. if ( g_PostRestoreObjectList[i].enableCollisions )
  1651. {
  1652. g_PostRestoreObjectList[i].pObject->EnableCollisions( true );
  1653. }
  1654. }
  1655. }
  1656. g_PostRestoreObjectList.Purge();
  1657. }