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.

1420 lines
41 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #include "cbase.h"
  9. #include "physics_shadow.h"
  10. #include "vphysics/player_controller.h"
  11. #include "physics_friction.h"
  12. #include "vphysics/friction.h"
  13. // IsInContact
  14. #include "ivp_mindist.hxx"
  15. #include "ivp_core.hxx"
  16. #include "ivp_friction.hxx"
  17. #include "ivp_listener_object.hxx"
  18. // memdbgon must be the last include file in a .cpp file!!!
  19. #include "tier0/memdbgon.h"
  20. struct vphysics_save_cshadowcontroller_t;
  21. struct vphysics_save_shadowcontrolparams_t;
  22. // UNDONE: Try this controller!
  23. //damping is usually 1.0
  24. //frequency is usually in the range 1..16
  25. void ComputePDControllerCoefficients( float *coefficientsOut, const float frequency, const float damping, const float dt )
  26. {
  27. const float ks = 9.0f * frequency * frequency;
  28. const float kd = 4.5f * frequency * damping;
  29. const float scale = 1.0f / ( 1.0f + kd * dt + ks * dt * dt );
  30. coefficientsOut[0] = ks * scale;
  31. coefficientsOut[1] = ( kd + ks * dt ) * scale;
  32. // Use this controller like:
  33. // speed += (coefficientsOut[0] * (targetPos - currentPos) + coefficientsOut[1] * (targetSpeed - currentSpeed)) * dt
  34. }
  35. void ComputeController( IVP_U_Float_Point &currentSpeed, const IVP_U_Float_Point &delta, float maxSpeed, float maxDampSpeed, float scaleDelta, float damping, IVP_U_Float_Point *pOutImpulse = NULL )
  36. {
  37. if ( currentSpeed.quad_length() < 1e-6 )
  38. {
  39. currentSpeed.set_to_zero();
  40. }
  41. // scale by timestep
  42. IVP_U_Float_Point acceleration;
  43. if ( maxSpeed > 0 )
  44. {
  45. acceleration.set_multiple( &delta, scaleDelta );
  46. float speed = acceleration.real_length();
  47. if ( speed > maxSpeed )
  48. {
  49. speed = maxSpeed / speed;
  50. acceleration.mult( speed );
  51. }
  52. }
  53. else
  54. {
  55. acceleration.set_to_zero();
  56. }
  57. IVP_U_Float_Point dampAccel;
  58. if ( maxDampSpeed > 0 )
  59. {
  60. dampAccel.set_multiple( &currentSpeed, -damping );
  61. float speed = dampAccel.real_length();
  62. if ( speed > maxDampSpeed )
  63. {
  64. speed = maxDampSpeed / speed;
  65. dampAccel.mult( speed );
  66. }
  67. }
  68. else
  69. {
  70. dampAccel.set_to_zero();
  71. }
  72. currentSpeed.add( &dampAccel );
  73. currentSpeed.add( &acceleration );
  74. if ( pOutImpulse )
  75. {
  76. *pOutImpulse = acceleration;
  77. }
  78. }
  79. void ComputeController( IVP_U_Float_Point &currentSpeed, const IVP_U_Float_Point &delta, const IVP_U_Float_Point &maxSpeed, float scaleDelta, float damping, IVP_U_Float_Point *pOutImpulse )
  80. {
  81. // scale by timestep
  82. IVP_U_Float_Point acceleration;
  83. acceleration.set_multiple( &delta, scaleDelta );
  84. if ( currentSpeed.quad_length() < 1e-6 )
  85. {
  86. currentSpeed.set_to_zero();
  87. }
  88. acceleration.add_multiple( &currentSpeed, -damping );
  89. for(int i=2; i>=0; i--)
  90. {
  91. if(IVP_Inline_Math::fabsd(acceleration.k[i]) < maxSpeed.k[i])
  92. continue;
  93. // clip force
  94. acceleration.k[i] = (acceleration.k[i] < 0) ? -maxSpeed.k[i] : maxSpeed.k[i];
  95. }
  96. currentSpeed.add( &acceleration );
  97. if ( pOutImpulse )
  98. {
  99. *pOutImpulse = acceleration;
  100. }
  101. }
  102. static bool IsOnGround( IVP_Real_Object *pivp )
  103. {
  104. IPhysicsFrictionSnapshot *pSnapshot = CreateFrictionSnapshot( pivp );
  105. bool bGround = false;
  106. while (pSnapshot->IsValid())
  107. {
  108. Vector normal;
  109. pSnapshot->GetSurfaceNormal( normal );
  110. if ( normal.z < -0.7f )
  111. {
  112. bGround = true;
  113. break;
  114. }
  115. pSnapshot->NextFrictionData();
  116. }
  117. DestroyFrictionSnapshot( pSnapshot );
  118. return bGround;
  119. }
  120. class CPlayerController : public IVP_Controller_Independent, public IPhysicsPlayerController, public IVP_Listener_Object
  121. {
  122. public:
  123. CPlayerController( CPhysicsObject *pObject );
  124. ~CPlayerController( void );
  125. // ipion interfaces
  126. void do_simulation_controller( IVP_Event_Sim *es,IVP_U_Vector<IVP_Core> *cores);
  127. virtual IVP_CONTROLLER_PRIORITY get_controller_priority() { return (IVP_CONTROLLER_PRIORITY) (IVP_CP_MOTION+1); }
  128. virtual const char *get_controller_name() { return "vphysics:player"; }
  129. void SetObject( IPhysicsObject *pObject );
  130. void SetEventHandler( IPhysicsPlayerControllerEvent *handler );
  131. void Update( const Vector& position, const Vector& velocity, float secondsToArrival, bool onground, IPhysicsObject *ground );
  132. void MaxSpeed( const Vector &velocity );
  133. bool IsInContact( void );
  134. virtual bool WasFrozen()
  135. {
  136. IVP_Real_Object *pivp = m_pObject->GetObject();
  137. IVP_Core *pCore = pivp->get_core();
  138. return pCore->temporarily_unmovable ? true : false;
  139. }
  140. void ForceTeleportToCurrentPosition()
  141. {
  142. m_forceTeleport = true;
  143. }
  144. int GetShadowPosition( Vector *position, QAngle *angles )
  145. {
  146. IVP_U_Matrix matrix;
  147. IVP_Environment *pEnv = m_pObject->GetObject()->get_environment();
  148. double psi = pEnv->get_next_PSI_time().get_seconds();
  149. m_pObject->GetObject()->calc_at_matrix( psi, &matrix );
  150. if ( angles )
  151. {
  152. ConvertRotationToHL( matrix, *angles );
  153. }
  154. if ( position )
  155. {
  156. ConvertPositionToHL( matrix.vv, *position );
  157. }
  158. return 1;
  159. }
  160. void GetShadowVelocity( Vector *velocity );
  161. virtual void GetLastImpulse( Vector *pOut )
  162. {
  163. ConvertPositionToHL( m_lastImpulse, *pOut );
  164. }
  165. virtual void StepUp( float height );
  166. virtual void Jump();
  167. virtual IPhysicsObject *GetObject() { return m_pObject; }
  168. virtual void SetPushMassLimit( float maxPushMass )
  169. {
  170. m_pushableMassLimit = maxPushMass;
  171. }
  172. virtual void SetPushSpeedLimit( float maxPushSpeed )
  173. {
  174. m_pushableSpeedLimit = maxPushSpeed;
  175. }
  176. virtual float GetPushMassLimit() { return m_pushableMassLimit; }
  177. virtual float GetPushSpeedLimit() { return m_pushableSpeedLimit; }
  178. // Object listener
  179. virtual void event_object_deleted( IVP_Event_Object *pEvent)
  180. {
  181. Assert( pEvent->real_object == m_pGround->GetObject() );
  182. m_pGround = NULL;
  183. }
  184. virtual void event_object_created( IVP_Event_Object *) {}
  185. virtual void event_object_revived( IVP_Event_Object *) {}
  186. virtual void event_object_frozen ( IVP_Event_Object *) {}
  187. private:
  188. void AttachObject( void );
  189. void DetachObject( void );
  190. int TryTeleportObject( void );
  191. void SetGround( CPhysicsObject *pGroundObject );
  192. CPhysicsObject *m_pObject;
  193. IVP_U_Float_Point m_saveRot;
  194. CPhysicsObject *m_pGround; // Uses object listener to clear - so ok to hold over frames
  195. IPhysicsPlayerControllerEvent *m_handler;
  196. float m_maxDeltaPosition;
  197. float m_dampFactor;
  198. float m_secondsToArrival;
  199. float m_pushableMassLimit;
  200. float m_pushableSpeedLimit;
  201. IVP_U_Point m_targetPosition;
  202. IVP_U_Float_Point m_groundPosition;
  203. IVP_U_Float_Point m_maxSpeed;
  204. IVP_U_Float_Point m_currentSpeed;
  205. IVP_U_Float_Point m_lastImpulse;
  206. bool m_enable : 1;
  207. bool m_onground : 1;
  208. bool m_forceTeleport : 1;
  209. bool m_updatedSinceLast : 5;
  210. };
  211. CPlayerController::CPlayerController( CPhysicsObject *pObject )
  212. {
  213. m_pGround = NULL;
  214. m_pObject = pObject;
  215. m_handler = NULL;
  216. m_maxDeltaPosition = ConvertDistanceToIVP( 24 );
  217. m_dampFactor = 1.0f;
  218. m_targetPosition.k[0] = m_targetPosition.k[1] = m_targetPosition.k[2] = 0;
  219. m_pushableMassLimit = VPHYSICS_MAX_MASS;
  220. m_pushableSpeedLimit = 1e4f;
  221. m_forceTeleport = false;
  222. AttachObject();
  223. }
  224. CPlayerController::~CPlayerController( void )
  225. {
  226. DetachObject();
  227. }
  228. void CPlayerController::SetGround( CPhysicsObject *pGroundObject )
  229. {
  230. if ( m_pGround != pGroundObject )
  231. {
  232. if ( m_pGround && m_pGround->GetObject() )
  233. {
  234. m_pGround->GetObject()->remove_listener_object(this);
  235. }
  236. m_pGround = pGroundObject;
  237. if ( m_pGround && m_pGround->GetObject() )
  238. {
  239. m_pGround->GetObject()->add_listener_object(this);
  240. }
  241. }
  242. }
  243. void CPlayerController::AttachObject( void )
  244. {
  245. m_pObject->EnableDrag( false );
  246. IVP_Real_Object *pivp = m_pObject->GetObject();
  247. IVP_Core *pCore = pivp->get_core();
  248. m_saveRot = pCore->rot_speed_damp_factor;
  249. pCore->rot_speed_damp_factor = IVP_U_Float_Point( 100, 100, 100 );
  250. pCore->calc_calc();
  251. BEGIN_IVP_ALLOCATION();
  252. pivp->get_environment()->get_controller_manager()->add_controller_to_core( this, pCore );
  253. END_IVP_ALLOCATION();
  254. m_pObject->AddCallbackFlags( CALLBACK_IS_PLAYER_CONTROLLER );
  255. }
  256. void CPlayerController::DetachObject( void )
  257. {
  258. if ( !m_pObject )
  259. return;
  260. IVP_Real_Object *pivp = m_pObject->GetObject();
  261. IVP_Core *pCore = pivp->get_core();
  262. pCore->rot_speed_damp_factor = m_saveRot;
  263. pCore->calc_calc();
  264. m_pObject->RemoveCallbackFlags( CALLBACK_IS_PLAYER_CONTROLLER );
  265. m_pObject = NULL;
  266. pivp->get_environment()->get_controller_manager()->remove_controller_from_core( this, pCore );
  267. SetGround(NULL);
  268. }
  269. void CPlayerController::SetObject( IPhysicsObject *pObject )
  270. {
  271. CPhysicsObject *obj = (CPhysicsObject *)pObject;
  272. if ( obj == m_pObject )
  273. return;
  274. DetachObject();
  275. m_pObject = obj;
  276. AttachObject();
  277. }
  278. int CPlayerController::TryTeleportObject( void )
  279. {
  280. if ( m_handler && !m_forceTeleport )
  281. {
  282. Vector hlPosition;
  283. ConvertPositionToHL( m_targetPosition, hlPosition );
  284. if ( !m_handler->ShouldMoveTo( m_pObject, hlPosition ) )
  285. return 0;
  286. }
  287. IVP_Real_Object *pivp = m_pObject->GetObject();
  288. IVP_U_Quat targetOrientation;
  289. IVP_U_Point outPosition;
  290. pivp->get_quat_world_f_object_AT( &targetOrientation, &outPosition );
  291. if ( pivp->is_collision_detection_enabled() )
  292. {
  293. m_pObject->EnableCollisions( false );
  294. pivp->beam_object_to_new_position( &targetOrientation, &m_targetPosition, IVP_TRUE );
  295. m_pObject->EnableCollisions( true );
  296. }
  297. else
  298. {
  299. pivp->beam_object_to_new_position( &targetOrientation, &m_targetPosition, IVP_TRUE );
  300. }
  301. m_forceTeleport = false;
  302. return 1;
  303. }
  304. void CPlayerController::StepUp( float height )
  305. {
  306. if ( height == 0.0f )
  307. return;
  308. Vector step( 0, 0, height );
  309. IVP_Real_Object *pIVP = m_pObject->GetObject();
  310. IVP_U_Quat world_f_object;
  311. IVP_U_Point positionIVP, deltaIVP;
  312. ConvertPositionToIVP( step, deltaIVP );
  313. pIVP->get_quat_world_f_object_AT( &world_f_object, &positionIVP );
  314. positionIVP.add( &deltaIVP );
  315. pIVP->beam_object_to_new_position( &world_f_object, &positionIVP, IVP_TRUE );
  316. }
  317. void CPlayerController::Jump()
  318. {
  319. #if 0
  320. // float for one tick to allow stepping and jumping to work properly
  321. IVP_Real_Object *pIVP = m_pObject->GetObject();
  322. const IVP_U_Point *pgrav = pIVP->get_environment()->get_gravity();
  323. IVP_U_Float_Point gravSpeed;
  324. gravSpeed.set_multiple( pgrav, pIVP->get_environment()->get_delta_PSI_time() );
  325. pIVP->get_core()->speed.subtract( &gravSpeed );
  326. #endif
  327. }
  328. const int MAX_LIST_NORMALS = 8;
  329. class CNormalList
  330. {
  331. public:
  332. bool IsFull() { return m_Normals.Count() == MAX_LIST_NORMALS; }
  333. void AddNormal( const Vector &normal )
  334. {
  335. if ( IsFull() )
  336. return;
  337. for ( int i = m_Normals.Count(); --i >= 0; )
  338. {
  339. if ( DotProduct( m_Normals[i], normal ) > 0.99f )
  340. return;
  341. }
  342. m_Normals.AddToTail( normal );
  343. }
  344. bool HasPositiveProjection( const Vector &vec )
  345. {
  346. for ( int i = m_Normals.Count(); --i >= 0; )
  347. {
  348. if ( DotProduct( m_Normals[i], vec ) > 0 )
  349. return true;
  350. }
  351. return false;
  352. }
  353. // UNDONE: Handle the case better where we clamp to multiple planes
  354. // and still have a projection, but don't exceed limitVel. Currently that will stop.
  355. // when this is done, remove the ground exception below.
  356. Vector ClampVector( const Vector &inVector, float limitVel )
  357. {
  358. if ( m_Normals.Count() > 2 )
  359. {
  360. for ( int i = 0; i < m_Normals.Count(); i++ )
  361. {
  362. if ( DotProduct(inVector, m_Normals[i]) > 0 )
  363. {
  364. return vec3_origin;
  365. }
  366. }
  367. }
  368. else
  369. {
  370. if ( m_Normals.Count() == 2 )
  371. {
  372. Vector crease;
  373. CrossProduct( m_Normals[0], m_Normals[1], crease );
  374. float dot = DotProduct( inVector, crease );
  375. return crease * dot;
  376. }
  377. else if (m_Normals.Count() == 1)
  378. {
  379. float dot = DotProduct( inVector, m_Normals[0] );
  380. if ( dot > limitVel )
  381. {
  382. return inVector + m_Normals[0]*(limitVel - dot);
  383. }
  384. }
  385. }
  386. return inVector;
  387. }
  388. private:
  389. CUtlVectorFixed<Vector, MAX_LIST_NORMALS> m_Normals;
  390. };
  391. void CPlayerController::do_simulation_controller( IVP_Event_Sim *es,IVP_U_Vector<IVP_Core> *)
  392. {
  393. if ( !m_enable )
  394. return;
  395. IVP_Real_Object *pivp = m_pObject->GetObject();
  396. IVP_Core *pCore = pivp->get_core();
  397. Assert(!pCore->pinned && !pCore->physical_unmoveable);
  398. // current situation
  399. const IVP_U_Matrix *m_world_f_core = pCore->get_m_world_f_core_PSI();
  400. const IVP_U_Point *cur_pos_ws = m_world_f_core->get_position();
  401. IVP_U_Float_Point baseVelocity;
  402. baseVelocity.set_to_zero();
  403. // ---------------------------------------------------------
  404. // Translation
  405. // ---------------------------------------------------------
  406. if ( m_pGround )
  407. {
  408. const IVP_U_Matrix *pMatrix = m_pGround->GetObject()->get_core()->get_m_world_f_core_PSI();
  409. pMatrix->vmult4( &m_groundPosition, &m_targetPosition );
  410. m_pGround->GetObject()->get_core()->get_surface_speed( &m_groundPosition, &baseVelocity );
  411. pCore->speed.subtract( &baseVelocity );
  412. }
  413. IVP_U_Float_Point delta_position; delta_position.subtract( &m_targetPosition, cur_pos_ws);
  414. if (!pivp->flags.shift_core_f_object_is_zero)
  415. {
  416. IVP_U_Float_Point shift_cs_os_ws;
  417. m_world_f_core->vmult3( pivp->get_shift_core_f_object(), &shift_cs_os_ws);
  418. delta_position.subtract( &shift_cs_os_ws );
  419. }
  420. IVP_DOUBLE qdist = delta_position.quad_length();
  421. // UNDONE: This is totally bogus! Measure error using last known estimate
  422. // not current position!
  423. if ( m_forceTeleport || qdist > m_maxDeltaPosition * m_maxDeltaPosition )
  424. {
  425. if ( TryTeleportObject() )
  426. return;
  427. }
  428. // float to allow stepping
  429. const IVP_U_Point *pgrav = es->environment->get_gravity();
  430. IVP_U_Float_Point gravSpeed;
  431. gravSpeed.set_multiple( pgrav, es->delta_time );
  432. if ( m_onground )
  433. {
  434. pCore->speed.subtract( &gravSpeed );
  435. }
  436. float fraction = 1.0;
  437. if ( m_secondsToArrival > 0 )
  438. {
  439. fraction = es->delta_time / m_secondsToArrival;
  440. if ( fraction > 1 )
  441. {
  442. fraction = 1;
  443. }
  444. }
  445. if ( !m_updatedSinceLast )
  446. {
  447. // we haven't received an update from the game code since the last controller step
  448. // This means we haven't gotten feedback integrated into the motion plan, so the error may be
  449. // exaggerated. Assume that the first updated tick had valid information, and limit
  450. // all subsequent ticks to the same size impulses.
  451. // NOTE: Don't update the saved impulse - so any subsequent ticks will still have the last
  452. // known good information.
  453. float len = m_lastImpulse.real_length();
  454. // cap the max speed to the length of the last known good impulse
  455. IVP_U_Float_Point tmp;
  456. tmp.set( len, len, len );
  457. ComputeController( pCore->speed, delta_position, tmp, fraction / es->delta_time, m_dampFactor, NULL );
  458. }
  459. else
  460. {
  461. ComputeController( pCore->speed, delta_position, m_maxSpeed, fraction / es->delta_time, m_dampFactor, &m_lastImpulse );
  462. }
  463. pCore->speed.add( &baseVelocity );
  464. m_updatedSinceLast = false;
  465. // UNDONE: Assumes gravity points down
  466. Vector lastImpulseHL;
  467. ConvertPositionToHL( pCore->speed, lastImpulseHL );
  468. IPhysicsFrictionSnapshot *pSnapshot = CreateFrictionSnapshot( pivp );
  469. bool bGround = false;
  470. float invMass = pivp->get_core()->get_inv_mass();
  471. float limitVel = m_pushableSpeedLimit;
  472. CNormalList normalList;
  473. while (pSnapshot->IsValid())
  474. {
  475. Vector normal;
  476. pSnapshot->GetSurfaceNormal( normal );
  477. if ( normal.z < -0.7f )
  478. {
  479. bGround = true;
  480. }
  481. // remove this when clamp works better
  482. if ( normal.z > -0.99f )
  483. {
  484. IPhysicsObject *pOther = pSnapshot->GetObject(1);
  485. if ( !pOther->IsMoveable() || pOther->GetMass() > m_pushableMassLimit )
  486. {
  487. limitVel = 0.0f;
  488. }
  489. float pushSpeed = DotProduct( lastImpulseHL, normal );
  490. float contactVel = pSnapshot->GetNormalForce() * invMass;
  491. float pushTotal = pushSpeed + contactVel;
  492. if ( pushTotal > limitVel )
  493. {
  494. normalList.AddNormal( normal );
  495. }
  496. }
  497. pSnapshot->NextFrictionData();
  498. }
  499. DestroyFrictionSnapshot( pSnapshot );
  500. Vector clamped = normalList.ClampVector( lastImpulseHL, limitVel );
  501. Vector limit = clamped - lastImpulseHL;
  502. IVP_U_Float_Point limitIVP;
  503. ConvertPositionToIVP( limit, limitIVP );
  504. pivp->get_core()->speed.add( &limitIVP );
  505. m_lastImpulse.add( &limitIVP );
  506. if ( bGround )
  507. {
  508. float gravDt = gravSpeed.real_length();
  509. // moving down? Press down with full gravity and no more
  510. if ( m_lastImpulse.k[1] >= 0 )
  511. {
  512. float delta = gravDt - m_lastImpulse.k[1];
  513. pivp->get_core()->speed.k[1] += delta;
  514. m_lastImpulse.k[1] += delta;
  515. }
  516. }
  517. // if we have time left, subtract it off
  518. m_secondsToArrival -= es->delta_time;
  519. if ( m_secondsToArrival < 0 )
  520. {
  521. m_secondsToArrival = 0;
  522. }
  523. }
  524. void CPlayerController::SetEventHandler( IPhysicsPlayerControllerEvent *handler )
  525. {
  526. m_handler = handler;
  527. }
  528. void CPlayerController::Update( const Vector& position, const Vector& velocity, float secondsToArrival, bool onground, IPhysicsObject *ground )
  529. {
  530. IVP_U_Point targetPositionIVP;
  531. IVP_U_Float_Point targetSpeedIVP;
  532. ConvertPositionToIVP( position, targetPositionIVP );
  533. ConvertPositionToIVP( velocity, targetSpeedIVP );
  534. m_updatedSinceLast = true;
  535. // if the object hasn't moved, abort
  536. if ( targetSpeedIVP.quad_distance_to( &m_currentSpeed ) < 1e-6 )
  537. {
  538. if ( targetPositionIVP.quad_distance_to( &m_targetPosition ) < 1e-6 )
  539. {
  540. return;
  541. }
  542. }
  543. m_targetPosition.set( &targetPositionIVP );
  544. m_secondsToArrival = secondsToArrival < 0 ? 0 : secondsToArrival;
  545. // Sanity check to make sure the position is good.
  546. #ifdef _DEBUG
  547. float large = 1024 * 512;
  548. Assert( m_targetPosition.k[0] >= -large && m_targetPosition.k[0] <= large );
  549. Assert( m_targetPosition.k[1] >= -large && m_targetPosition.k[1] <= large );
  550. Assert( m_targetPosition.k[2] >= -large && m_targetPosition.k[2] <= large );
  551. #endif
  552. m_currentSpeed.set( &targetSpeedIVP );
  553. IVP_Real_Object *pivp = m_pObject->GetObject();
  554. IVP_Core *pCore = pivp->get_core();
  555. IVP_Environment *pEnv = pivp->get_environment();
  556. pEnv->get_controller_manager()->ensure_core_in_simulation(pCore);
  557. m_enable = true;
  558. // m_onground makes this object anti-grav
  559. // UNDONE: Re-evaluate this
  560. m_onground = false;//onground;
  561. if ( velocity.LengthSqr() <= 0.1f )
  562. {
  563. // no input velocity, just go where physics takes you.
  564. m_enable = false;
  565. ground = NULL;
  566. }
  567. else
  568. {
  569. MaxSpeed( velocity );
  570. }
  571. CPhysicsObject *pGroundObject = static_cast<CPhysicsObject *>(ground);
  572. SetGround( pGroundObject );
  573. if ( m_pGround )
  574. {
  575. const IVP_U_Matrix *pMatrix = m_pGround->GetObject()->get_core()->get_m_world_f_core_PSI();
  576. pMatrix->vimult4( &m_targetPosition, &m_groundPosition );
  577. }
  578. }
  579. void CPlayerController::MaxSpeed( const Vector &velocity )
  580. {
  581. IVP_Core *pCore = m_pObject->GetObject()->get_core();
  582. IVP_U_Float_Point ivpVel;
  583. ConvertPositionToIVP( velocity, ivpVel );
  584. IVP_U_Float_Point available = ivpVel;
  585. // normalize and save length
  586. float length = ivpVel.real_length_plus_normize();
  587. IVP_U_Float_Point baseVelocity;
  588. baseVelocity.set_to_zero();
  589. float dot = ivpVel.dot_product( &pCore->speed );
  590. if ( dot > 0 )
  591. {
  592. ivpVel.mult( dot * length );
  593. available.subtract( &ivpVel );
  594. }
  595. pCore->speed.add( &baseVelocity );
  596. IVP_Float_PointAbs( m_maxSpeed, available );
  597. }
  598. void CPlayerController::GetShadowVelocity( Vector *velocity )
  599. {
  600. IVP_Core *core = m_pObject->GetObject()->get_core();
  601. if ( velocity )
  602. {
  603. IVP_U_Float_Point speed;
  604. speed.add( &core->speed, &core->speed_change );
  605. if ( m_pGround )
  606. {
  607. IVP_U_Float_Point baseVelocity;
  608. m_pGround->GetObject()->get_core()->get_surface_speed( &m_groundPosition, &baseVelocity );
  609. speed.subtract( &baseVelocity );
  610. }
  611. ConvertPositionToHL( speed, *velocity );
  612. }
  613. }
  614. bool CPlayerController::IsInContact( void )
  615. {
  616. IVP_Real_Object *pivp = m_pObject->GetObject();
  617. if ( !pivp->flags.collision_detection_enabled )
  618. return false;
  619. IVP_Synapse_Friction *pfriction = pivp->get_first_friction_synapse();
  620. while ( pfriction )
  621. {
  622. extern IVP_Real_Object *GetOppositeSynapseObject( IVP_Synapse_Friction *pfriction );
  623. IVP_Real_Object *pobj = GetOppositeSynapseObject( pfriction );
  624. if ( pobj->flags.collision_detection_enabled )
  625. {
  626. // skip if this is a static object
  627. if ( !pobj->get_core()->physical_unmoveable && !pobj->get_core()->pinned )
  628. {
  629. CPhysicsObject *pPhys = static_cast<CPhysicsObject *>(pobj->client_data);
  630. // If this is a game-controlled shadow object, then skip it.
  631. // otherwise, we're in contact with something physically simulated
  632. if ( !pPhys->IsControlledByGame() )
  633. return true;
  634. }
  635. }
  636. pfriction = pfriction->get_next();
  637. }
  638. return false;
  639. }
  640. IPhysicsPlayerController *CreatePlayerController( CPhysicsObject *pObject )
  641. {
  642. return new CPlayerController( pObject );
  643. }
  644. void DestroyPlayerController( IPhysicsPlayerController *pController )
  645. {
  646. delete pController;
  647. }
  648. void QuaternionDiff( const IVP_U_Quat &p, const IVP_U_Quat &q, IVP_U_Quat &qt )
  649. {
  650. IVP_U_Quat q2;
  651. // decide if one of the quaternions is backwards
  652. q2.set_invert_unit_quat( &q );
  653. qt.set_mult_quat( &q2, &p );
  654. qt.normize_quat();
  655. }
  656. void QuaternionAxisAngle( const IVP_U_Quat &q, Vector &axis, float &angle )
  657. {
  658. angle = 2 * acos(q.w);
  659. if ( angle > M_PI )
  660. {
  661. angle -= 2*M_PI;
  662. }
  663. axis.Init( q.x, q.y, q.z );
  664. VectorNormalize( axis );
  665. }
  666. void GetObjectPosition_IVP( IVP_U_Point &origin, IVP_Real_Object *pivp )
  667. {
  668. const IVP_U_Matrix *m_world_f_core = pivp->get_core()->get_m_world_f_core_PSI();
  669. origin.set( m_world_f_core->get_position() );
  670. if (!pivp->flags.shift_core_f_object_is_zero)
  671. {
  672. IVP_U_Float_Point shift_cs_os_ws;
  673. m_world_f_core->vmult3( pivp->get_shift_core_f_object(), &shift_cs_os_ws );
  674. origin.add(&shift_cs_os_ws);
  675. }
  676. }
  677. bool IsZeroVector( const IVP_U_Point &vec )
  678. {
  679. return (vec.k[0] == 0.0 && vec.k[1] == 0.0 && vec.k[2] == 0.0 ) ? true : false;
  680. }
  681. float ComputeShadowControllerIVP( IVP_Real_Object *pivp, shadowcontrol_params_t &params, float secondsToArrival, float dt )
  682. {
  683. // resample fraction
  684. // This allows us to arrive at the target at the requested time
  685. float fraction = 1.0;
  686. if ( secondsToArrival > 0 )
  687. {
  688. fraction = dt / secondsToArrival;
  689. if ( fraction > 1 )
  690. {
  691. fraction = 1;
  692. }
  693. }
  694. secondsToArrival -= dt;
  695. if ( secondsToArrival < 0 )
  696. {
  697. secondsToArrival = 0;
  698. }
  699. if ( fraction <= 0 )
  700. return secondsToArrival;
  701. // ---------------------------------------------------------
  702. // Translation
  703. // ---------------------------------------------------------
  704. IVP_U_Point positionIVP;
  705. GetObjectPosition_IVP( positionIVP, pivp );
  706. IVP_U_Float_Point delta_position;
  707. delta_position.subtract( &params.targetPosition, &positionIVP);
  708. // BUGBUG: Save off velocities and estimate final positions
  709. // measure error against these final sets
  710. // also, damp out 100% saved velocity, use max additional impulses
  711. // to correct error and damp out error velocity
  712. // extrapolate position
  713. if ( params.teleportDistance > 0 )
  714. {
  715. IVP_DOUBLE qdist;
  716. if ( !IsZeroVector(params.lastPosition) )
  717. {
  718. IVP_U_Float_Point tmpDelta;
  719. tmpDelta.subtract( &positionIVP, &params.lastPosition );
  720. qdist = tmpDelta.quad_length();
  721. }
  722. else
  723. {
  724. // UNDONE: This is totally bogus! Measure error using last known estimate
  725. // not current position!
  726. qdist = delta_position.quad_length();
  727. }
  728. if ( qdist > params.teleportDistance * params.teleportDistance )
  729. {
  730. if ( pivp->is_collision_detection_enabled() )
  731. {
  732. pivp->enable_collision_detection( IVP_FALSE );
  733. pivp->beam_object_to_new_position( &params.targetRotation, &params.targetPosition, IVP_TRUE );
  734. pivp->enable_collision_detection( IVP_TRUE );
  735. }
  736. else
  737. {
  738. pivp->beam_object_to_new_position( &params.targetRotation, &params.targetPosition, IVP_TRUE );
  739. }
  740. delta_position.set_to_zero();
  741. }
  742. }
  743. float invDt = 1.0f / dt;
  744. IVP_Core *pCore = pivp->get_core();
  745. ComputeController( pCore->speed, delta_position, params.maxSpeed, params.maxDampSpeed, fraction * invDt, params.dampFactor, &params.lastImpulse );
  746. params.lastPosition.add_multiple( &positionIVP, &pCore->speed, dt );
  747. IVP_U_Float_Point deltaAngles;
  748. // compute rotation offset
  749. IVP_U_Quat deltaRotation;
  750. QuaternionDiff( params.targetRotation, pCore->q_world_f_core_next_psi, deltaRotation );
  751. // convert offset to angular impulse
  752. Vector axis;
  753. float angle;
  754. QuaternionAxisAngle( deltaRotation, axis, angle );
  755. VectorNormalize(axis);
  756. deltaAngles.k[0] = axis.x * angle;
  757. deltaAngles.k[1] = axis.y * angle;
  758. deltaAngles.k[2] = axis.z * angle;
  759. ComputeController( pCore->rot_speed, deltaAngles, params.maxAngular, params.maxDampAngular, fraction * invDt, params.dampFactor, NULL );
  760. return secondsToArrival;
  761. }
  762. void ConvertShadowControllerToIVP( const hlshadowcontrol_params_t &in, shadowcontrol_params_t &out )
  763. {
  764. ConvertPositionToIVP( in.targetPosition, out.targetPosition );
  765. ConvertRotationToIVP( in.targetRotation, out.targetRotation );
  766. out.teleportDistance = ConvertDistanceToIVP( in.teleportDistance );
  767. out.maxSpeed = ConvertDistanceToIVP( in.maxSpeed );
  768. out.maxDampSpeed = ConvertDistanceToIVP( in.maxDampSpeed );
  769. out.maxAngular = ConvertAngleToIVP( in.maxAngular );
  770. out.maxDampAngular = ConvertAngleToIVP( in.maxDampAngular );
  771. out.dampFactor = in.dampFactor;
  772. }
  773. void ConvertShadowControllerToHL( const shadowcontrol_params_t &in, hlshadowcontrol_params_t &out )
  774. {
  775. ConvertPositionToHL( in.targetPosition, out.targetPosition );
  776. ConvertRotationToHL( in.targetRotation, out.targetRotation );
  777. out.teleportDistance = ConvertDistanceToHL( in.teleportDistance );
  778. out.maxSpeed = ConvertDistanceToHL( in.maxSpeed );
  779. out.maxDampSpeed = ConvertDistanceToHL( in.maxDampSpeed );
  780. out.maxAngular = ConvertAngleToHL( in.maxAngular );
  781. out.maxDampAngular = ConvertAngleToHL( in.maxDampAngular );
  782. out.dampFactor = in.dampFactor;
  783. }
  784. float ComputeShadowControllerHL( CPhysicsObject *pObject, const hlshadowcontrol_params_t &params, float secondsToArrival, float dt )
  785. {
  786. shadowcontrol_params_t ivpParams;
  787. ConvertShadowControllerToIVP( params, ivpParams );
  788. return ComputeShadowControllerIVP( pObject->GetObject(), ivpParams, secondsToArrival, dt );
  789. }
  790. class CShadowController : public IVP_Controller_Independent, public IPhysicsShadowController, public CAlignedNewDelete<16>
  791. {
  792. public:
  793. CShadowController();
  794. CShadowController( CPhysicsObject *pObject, bool allowTranslation, bool allowRotation );
  795. ~CShadowController( void );
  796. // ipion interfaces
  797. void do_simulation_controller( IVP_Event_Sim *es,IVP_U_Vector<IVP_Core> *cores);
  798. virtual IVP_CONTROLLER_PRIORITY get_controller_priority() { return IVP_CP_MOTION; }
  799. virtual const char *get_controller_name() { return "vphysics:shadow"; }
  800. void SetObject( IPhysicsObject *pObject );
  801. void Update( const Vector &position, const QAngle &angles, float secondsToArrival );
  802. void MaxSpeed( float maxSpeed, float maxAngularSpeed );
  803. virtual void StepUp( float height );
  804. virtual void SetTeleportDistance( float teleportDistance );
  805. virtual bool AllowsTranslation() { return m_allowsTranslation; }
  806. virtual bool AllowsRotation() { return m_allowsRotation; }
  807. virtual void GetLastImpulse( Vector *pOut )
  808. {
  809. ConvertPositionToHL( m_shadow.lastImpulse, *pOut );
  810. }
  811. bool IsEnabled() { return m_enabled; }
  812. void Enable( bool bEnable )
  813. {
  814. m_enabled = bEnable;
  815. }
  816. void WriteToTemplate( vphysics_save_cshadowcontroller_t &controllerTemplate );
  817. void InitFromTemplate( const vphysics_save_cshadowcontroller_t &controllerTemplate );
  818. virtual void SetPhysicallyControlled( bool isPhysicallyControlled ) { m_isPhysicallyControlled = isPhysicallyControlled; }
  819. virtual bool IsPhysicallyControlled() { return m_isPhysicallyControlled; }
  820. virtual void UseShadowMaterial( bool bUseShadowMaterial )
  821. {
  822. if ( !m_pObject )
  823. return;
  824. int current = m_pObject->GetMaterialIndexInternal();
  825. int target = bUseShadowMaterial ? MATERIAL_INDEX_SHADOW : m_savedMaterialIndex;
  826. if ( target != current )
  827. {
  828. m_pObject->SetMaterialIndex( target );
  829. }
  830. }
  831. virtual void ObjectMaterialChanged( int materialIndex )
  832. {
  833. if ( !m_pObject )
  834. return;
  835. m_savedMaterialIndex = materialIndex;
  836. }
  837. //Basically get the last inputs to IPhysicsShadowController::Update(), returns last input to timeOffset in Update()
  838. virtual float GetTargetPosition( Vector *pPositionOut, QAngle *pAnglesOut );
  839. virtual float GetTeleportDistance( void );
  840. virtual void GetMaxSpeed( float *pMaxSpeedOut, float *pMaxAngularSpeedOut );
  841. private:
  842. void AttachObject( void );
  843. void DetachObject( void );
  844. shadowcontrol_params_t m_shadow;
  845. IVP_U_Float_Point m_saveRot;
  846. IVP_U_Float_Point m_savedRI;
  847. CPhysicsObject *m_pObject;
  848. float m_secondsToArrival;
  849. float m_savedMass;
  850. unsigned int m_savedFlags;
  851. unsigned short m_savedMaterialIndex;
  852. bool m_enabled : 1;
  853. bool m_allowsTranslation : 1;
  854. bool m_allowsRotation : 1;
  855. bool m_isPhysicallyControlled : 1;
  856. };
  857. CShadowController::CShadowController()
  858. {
  859. m_shadow.targetPosition.set_to_zero();
  860. m_shadow.targetRotation.init();
  861. }
  862. CShadowController::CShadowController( CPhysicsObject *pObject, bool allowTranslation, bool allowRotation )
  863. {
  864. m_pObject = pObject;
  865. m_shadow.dampFactor = 1.0f;
  866. m_shadow.teleportDistance = 0;
  867. m_shadow.maxDampSpeed = 0;
  868. m_shadow.maxDampAngular = 0;
  869. m_shadow.targetPosition.set_to_zero();
  870. m_shadow.targetRotation.init();
  871. m_allowsTranslation = allowTranslation;
  872. m_allowsRotation = allowRotation;
  873. m_isPhysicallyControlled = false;
  874. m_enabled = false;
  875. AttachObject();
  876. }
  877. CShadowController::~CShadowController( void )
  878. {
  879. DetachObject();
  880. }
  881. void CShadowController::AttachObject( void )
  882. {
  883. IVP_Real_Object *pivp = m_pObject->GetObject();
  884. IVP_Core *pCore = pivp->get_core();
  885. m_saveRot = pCore->rot_speed_damp_factor;
  886. m_savedRI = *pCore->get_rot_inertia();
  887. m_savedMass = pCore->get_mass();
  888. m_savedMaterialIndex = m_pObject->GetMaterialIndexInternal();
  889. Vector position;
  890. QAngle angles;
  891. m_pObject->GetPosition( &position, &angles );
  892. ConvertPositionToIVP( position, m_shadow.targetPosition );
  893. ConvertRotationToIVP( angles, m_shadow.targetRotation );
  894. UseShadowMaterial( true );
  895. pCore->rot_speed_damp_factor = IVP_U_Float_Point( 100, 100, 100 );
  896. if ( !m_allowsRotation )
  897. {
  898. IVP_U_Float_Point ri( 1e15f, 1e15f, 1e15f );
  899. pCore->set_rotation_inertia( &ri );
  900. }
  901. if ( !m_allowsTranslation )
  902. {
  903. m_pObject->SetMass( VPHYSICS_MAX_MASS );
  904. //pCore->inv_rot_inertia.hesse_val = 0.0f;
  905. m_pObject->EnableGravity( false );
  906. }
  907. m_savedFlags = m_pObject->CallbackFlags();
  908. unsigned int flags = m_savedFlags | CALLBACK_SHADOW_COLLISION;
  909. flags &= ~CALLBACK_GLOBAL_FRICTION;
  910. flags &= ~CALLBACK_GLOBAL_COLLIDE_STATIC;
  911. m_pObject->SetCallbackFlags( flags );
  912. m_pObject->EnableDrag( false );
  913. pCore->calc_calc();
  914. pivp->get_environment()->get_controller_manager()->add_controller_to_core( this, pCore );
  915. m_shadow.lastPosition.set_to_zero();
  916. }
  917. void CShadowController::DetachObject( void )
  918. {
  919. IVP_Real_Object *pivp = m_pObject->GetObject();
  920. IVP_Core *pCore = pivp->get_core();
  921. // don't bother if we're just doing this to delete the object
  922. if ( !(m_pObject->GetCallbackFlags() & CALLBACK_MARKED_FOR_DELETE) )
  923. {
  924. pCore->rot_speed_damp_factor = m_saveRot;
  925. pCore->set_mass( m_savedMass );
  926. m_pObject->SetCallbackFlags( m_savedFlags );
  927. m_pObject->EnableDrag( true );
  928. m_pObject->EnableGravity( true );
  929. UseShadowMaterial( false );
  930. pCore->set_rotation_inertia( &m_savedRI ); // this calls calc_calc()
  931. }
  932. m_pObject = NULL;
  933. pivp->get_environment()->get_controller_manager()->remove_controller_from_core( this, pCore );
  934. }
  935. void CShadowController::SetObject( IPhysicsObject *pObject )
  936. {
  937. CPhysicsObject *obj = (CPhysicsObject *)pObject;
  938. if ( obj == m_pObject )
  939. return;
  940. DetachObject();
  941. m_pObject = obj;
  942. AttachObject();
  943. }
  944. void CShadowController::StepUp( float height )
  945. {
  946. Vector step( 0, 0, height );
  947. IVP_Real_Object *pIVP = m_pObject->GetObject();
  948. IVP_U_Quat world_f_object;
  949. IVP_U_Point positionIVP, deltaIVP;
  950. ConvertPositionToIVP( step, deltaIVP );
  951. pIVP->get_quat_world_f_object_AT( &world_f_object, &positionIVP );
  952. positionIVP.add( &deltaIVP );
  953. pIVP->beam_object_to_new_position( &world_f_object, &positionIVP, IVP_TRUE );
  954. }
  955. void CShadowController::SetTeleportDistance( float teleportDistance )
  956. {
  957. m_shadow.teleportDistance = ConvertDistanceToIVP( teleportDistance );
  958. }
  959. float CShadowController::GetTeleportDistance( void )
  960. {
  961. return ConvertDistanceToHL( m_shadow.teleportDistance );
  962. }
  963. void CShadowController::do_simulation_controller( IVP_Event_Sim *es,IVP_U_Vector<IVP_Core> *)
  964. {
  965. if ( IsEnabled() )
  966. {
  967. IVP_Real_Object *pivp = m_pObject->GetObject();
  968. Assert(!pivp->get_core()->pinned && !pivp->get_core()->physical_unmoveable);
  969. ComputeShadowControllerIVP( pivp, m_shadow, m_secondsToArrival, es->delta_time );
  970. if ( m_allowsTranslation )
  971. {
  972. // UNDONE: Assumes gravity points down
  973. const IVP_U_Point *pgrav = pivp->get_environment()->get_gravity();
  974. float gravDt = pgrav->k[1] * es->delta_time;
  975. if ( m_shadow.lastImpulse.k[1] > gravDt )
  976. {
  977. if ( IsOnGround( pivp ) )
  978. {
  979. float delta = gravDt - m_shadow.lastImpulse.k[1];
  980. pivp->get_core()->speed.k[1] += delta;
  981. m_shadow.lastImpulse.k[1] += delta;
  982. }
  983. }
  984. }
  985. // if we have time left, subtract it off
  986. m_secondsToArrival -= es->delta_time;
  987. if ( m_secondsToArrival < 0 )
  988. {
  989. m_secondsToArrival = 0;
  990. }
  991. }
  992. else
  993. {
  994. m_shadow.lastPosition.set_to_zero();
  995. }
  996. }
  997. // NOTE: This isn't a test for equivalent orientations, it's a test for calling update
  998. // with EXACTLY the same data repeatedly
  999. static bool IsEqual( const IVP_U_Point &pt0, const IVP_U_Point &pt1 )
  1000. {
  1001. return pt0.quad_distance_to( &pt1 ) < 1e-8f ? true : false;
  1002. }
  1003. // NOTE: This isn't a test for equivalent orientations, it's a test for calling update
  1004. // with EXACTLY the same data repeatedly
  1005. static bool IsEqual( const IVP_U_Quat &pt0, const IVP_U_Quat &pt1 )
  1006. {
  1007. float delta = fabs(pt0.x - pt1.x);
  1008. delta += fabs(pt0.y - pt1.y);
  1009. delta += fabs(pt0.z - pt1.z);
  1010. delta += fabs(pt0.w - pt1.w);
  1011. return delta < 1e-8f ? true : false;
  1012. }
  1013. void CShadowController::Update( const Vector &position, const QAngle &angles, float secondsToArrival )
  1014. {
  1015. IVP_U_Point targetPosition = m_shadow.targetPosition;
  1016. IVP_U_Quat targetRotation = m_shadow.targetRotation;
  1017. ConvertPositionToIVP( position, m_shadow.targetPosition );
  1018. m_secondsToArrival = secondsToArrival < 0 ? 0 : secondsToArrival;
  1019. ConvertRotationToIVP( angles, m_shadow.targetRotation );
  1020. Enable( true );
  1021. if ( IsEqual( targetPosition, m_shadow.targetPosition ) && IsEqual( targetRotation, m_shadow.targetRotation ) )
  1022. return;
  1023. m_pObject->Wake();
  1024. }
  1025. float CShadowController::GetTargetPosition( Vector *pPositionOut, QAngle *pAnglesOut )
  1026. {
  1027. if( pPositionOut )
  1028. ConvertPositionToHL( m_shadow.targetPosition, *pPositionOut );
  1029. if( pAnglesOut )
  1030. ConvertRotationToHL( m_shadow.targetRotation, *pAnglesOut );
  1031. return m_secondsToArrival;
  1032. }
  1033. void CShadowController::MaxSpeed( float maxSpeed, float maxAngularSpeed )
  1034. {
  1035. // UNDONE: Turn this on when shadow controllers are having velocity updated per frame
  1036. // right now this has the effect of making dampspeed zero by default.
  1037. #if 0
  1038. IVP_Core *pCore = m_pObject->GetObject()->get_core();
  1039. {
  1040. // limit additional velocity to that which is not amplifying the current velocity
  1041. float availableSpeed = ConvertDistanceToIVP( maxSpeed );
  1042. float currentSpeed = pCore->speed.real_length();
  1043. m_shadow.maxDampSpeed = min(currentSpeed, availableSpeed);
  1044. m_shadow.maxSpeed = availableSpeed - m_shadow.maxDampSpeed;
  1045. }
  1046. {
  1047. // limit additional velocity to that which is not amplifying the current velocity
  1048. float availableAngularSpeed = ConvertAngleToIVP( maxAngularSpeed );
  1049. float currentAngularSpeed = pCore->rot_speed.real_length();
  1050. m_shadow.maxDampAngular = min(currentAngularSpeed, availableAngularSpeed);
  1051. m_shadow.maxAngular = availableAngularSpeed - m_shadow.maxDampAngular;
  1052. }
  1053. #else
  1054. m_shadow.maxSpeed = maxSpeed;
  1055. m_shadow.maxDampSpeed = maxSpeed;
  1056. m_shadow.maxAngular = maxAngularSpeed;
  1057. m_shadow.maxDampAngular = maxAngularSpeed;
  1058. #endif
  1059. }
  1060. void CShadowController::GetMaxSpeed( float *pMaxSpeedOut, float *pMaxAngularSpeedOut )
  1061. {
  1062. if( pMaxSpeedOut )
  1063. *pMaxSpeedOut = m_shadow.maxSpeed;
  1064. if( pMaxAngularSpeedOut )
  1065. *pMaxAngularSpeedOut = m_shadow.maxAngular;
  1066. }
  1067. struct vphysics_save_shadowcontrolparams_t : public hlshadowcontrol_params_t
  1068. {
  1069. DECLARE_SIMPLE_DATADESC();
  1070. };
  1071. BEGIN_SIMPLE_DATADESC( vphysics_save_shadowcontrolparams_t )
  1072. DEFINE_FIELD( targetPosition, FIELD_POSITION_VECTOR ),
  1073. DEFINE_FIELD( targetRotation, FIELD_VECTOR ),
  1074. DEFINE_FIELD( maxSpeed, FIELD_FLOAT ),
  1075. DEFINE_FIELD( maxDampSpeed, FIELD_FLOAT ),
  1076. DEFINE_FIELD( maxAngular, FIELD_FLOAT ),
  1077. DEFINE_FIELD( maxDampAngular, FIELD_FLOAT ),
  1078. DEFINE_FIELD( dampFactor, FIELD_FLOAT ),
  1079. DEFINE_FIELD( teleportDistance, FIELD_FLOAT ),
  1080. END_DATADESC()
  1081. struct vphysics_save_cshadowcontroller_t
  1082. {
  1083. CPhysicsObject *pObject;
  1084. float secondsToArrival;
  1085. IVP_U_Float_Point saveRot;
  1086. IVP_U_Float_Point savedRI;
  1087. IVP_U_Float_Point currentSpeed;
  1088. float savedMass;
  1089. int savedMaterial;
  1090. unsigned int savedFlags;
  1091. bool enable;
  1092. bool allowPhysicsMovement;
  1093. bool allowPhysicsRotation;
  1094. bool isPhysicallyControlled;
  1095. hlshadowcontrol_params_t shadowParams;
  1096. DECLARE_SIMPLE_DATADESC();
  1097. };
  1098. BEGIN_SIMPLE_DATADESC( vphysics_save_cshadowcontroller_t )
  1099. //DEFINE_VPHYSPTR( pObject ),
  1100. DEFINE_FIELD( secondsToArrival, FIELD_FLOAT ),
  1101. DEFINE_ARRAY( saveRot.k, FIELD_FLOAT, 3 ),
  1102. DEFINE_ARRAY( savedRI.k, FIELD_FLOAT, 3 ),
  1103. DEFINE_ARRAY( currentSpeed.k, FIELD_FLOAT, 3 ),
  1104. DEFINE_FIELD( savedMass, FIELD_FLOAT ),
  1105. DEFINE_FIELD( savedFlags, FIELD_INTEGER ),
  1106. DEFINE_CUSTOM_FIELD( savedMaterial, MaterialIndexDataOps() ),
  1107. DEFINE_FIELD( enable, FIELD_BOOLEAN ),
  1108. DEFINE_FIELD( allowPhysicsMovement, FIELD_BOOLEAN ),
  1109. DEFINE_FIELD( allowPhysicsRotation, FIELD_BOOLEAN ),
  1110. DEFINE_FIELD( isPhysicallyControlled, FIELD_BOOLEAN ),
  1111. DEFINE_EMBEDDED_OVERRIDE( shadowParams, vphysics_save_shadowcontrolparams_t ),
  1112. END_DATADESC()
  1113. void CShadowController::WriteToTemplate( vphysics_save_cshadowcontroller_t &controllerTemplate )
  1114. {
  1115. controllerTemplate.pObject = m_pObject;
  1116. controllerTemplate.secondsToArrival = m_secondsToArrival;
  1117. controllerTemplate.saveRot = m_saveRot;
  1118. controllerTemplate.savedRI = m_savedRI;
  1119. controllerTemplate.savedMass = m_savedMass;
  1120. controllerTemplate.savedFlags = m_savedFlags;
  1121. controllerTemplate.savedMaterial = m_savedMaterialIndex;
  1122. controllerTemplate.enable = IsEnabled();
  1123. controllerTemplate.allowPhysicsMovement = m_allowsTranslation;
  1124. controllerTemplate.allowPhysicsRotation = m_allowsRotation;
  1125. controllerTemplate.isPhysicallyControlled = m_isPhysicallyControlled;
  1126. ConvertShadowControllerToHL( m_shadow, controllerTemplate.shadowParams );
  1127. }
  1128. void CShadowController::InitFromTemplate( const vphysics_save_cshadowcontroller_t &controllerTemplate )
  1129. {
  1130. m_pObject = controllerTemplate.pObject;
  1131. m_secondsToArrival = controllerTemplate.secondsToArrival;
  1132. m_saveRot = controllerTemplate.saveRot;
  1133. m_savedRI = controllerTemplate.savedRI;
  1134. m_savedMass = controllerTemplate.savedMass;
  1135. m_savedFlags = controllerTemplate.savedFlags;
  1136. m_savedMaterialIndex = controllerTemplate.savedMaterial;
  1137. Enable( controllerTemplate.enable );
  1138. m_allowsTranslation = controllerTemplate.allowPhysicsMovement;
  1139. m_allowsRotation = controllerTemplate.allowPhysicsRotation;
  1140. m_isPhysicallyControlled = controllerTemplate.isPhysicallyControlled;
  1141. ConvertShadowControllerToIVP( controllerTemplate.shadowParams, m_shadow );
  1142. m_pObject->GetObject()->get_environment()->get_controller_manager()->add_controller_to_core( this, m_pObject->GetObject()->get_core() );
  1143. }
  1144. IPhysicsShadowController *CreateShadowController( CPhysicsObject *pObject, bool allowTranslation, bool allowRotation )
  1145. {
  1146. return new CShadowController( pObject, allowTranslation, allowRotation );
  1147. }
  1148. bool SavePhysicsShadowController( const physsaveparams_t &params, IPhysicsShadowController *pIShadow )
  1149. {
  1150. vphysics_save_cshadowcontroller_t controllerTemplate;
  1151. memset( &controllerTemplate, 0, sizeof(controllerTemplate) );
  1152. CShadowController *pShadowController = (CShadowController *)pIShadow;
  1153. pShadowController->WriteToTemplate( controllerTemplate );
  1154. params.pSave->WriteAll( &controllerTemplate );
  1155. return true;
  1156. }
  1157. bool RestorePhysicsShadowController( const physrestoreparams_t &params, IPhysicsShadowController **ppShadowController )
  1158. {
  1159. return false;
  1160. }
  1161. bool RestorePhysicsShadowControllerInternal( const physrestoreparams_t &params, IPhysicsShadowController **ppShadowController, CPhysicsObject *pObject )
  1162. {
  1163. vphysics_save_cshadowcontroller_t controllerTemplate;
  1164. memset( &controllerTemplate, 0, sizeof(controllerTemplate) );
  1165. params.pRestore->ReadAll( &controllerTemplate );
  1166. // HACKHACK: pass this in
  1167. controllerTemplate.pObject = pObject;
  1168. CShadowController *pShadow = new CShadowController();
  1169. pShadow->InitFromTemplate( controllerTemplate );
  1170. *ppShadowController = pShadow;
  1171. return true;
  1172. }
  1173. bool SavePhysicsPlayerController( const physsaveparams_t &params, CPlayerController *pPlayerController )
  1174. {
  1175. return false;
  1176. }
  1177. bool RestorePhysicsPlayerController( const physrestoreparams_t &params, CPlayerController **ppPlayerController )
  1178. {
  1179. return false;
  1180. }
  1181. //HACKHACK: The physics object transfer system needs to temporarily detach a shadow controller from an object, then reattach without other repercussions
  1182. void ControlPhysicsShadowControllerAttachment_Silent( IPhysicsShadowController *pController, IVP_Real_Object *pivp, bool bAttach )
  1183. {
  1184. if( bAttach )
  1185. {
  1186. pivp->get_environment()->get_controller_manager()->add_controller_to_core( (CShadowController *)pController, pivp->get_core() );
  1187. }
  1188. else
  1189. {
  1190. pivp->get_environment()->get_controller_manager()->remove_controller_from_core( (CShadowController *)pController, pivp->get_core() );
  1191. }
  1192. }
  1193. void ControlPhysicsPlayerControllerAttachment_Silent( IPhysicsPlayerController *pController, IVP_Real_Object *pivp, bool bAttach )
  1194. {
  1195. if( bAttach )
  1196. {
  1197. pivp->get_environment()->get_controller_manager()->add_controller_to_core( (CPlayerController *)pController, pivp->get_core() );
  1198. }
  1199. else
  1200. {
  1201. pivp->get_environment()->get_controller_manager()->remove_controller_from_core( (CPlayerController *)pController, pivp->get_core() );
  1202. }
  1203. }