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.

604 lines
17 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "stdafx.h"
  7. #include "Box3D.h"
  8. #include "StockSolids.h"
  9. #include "GlobalFunctions.h"
  10. #include "hammer_mathlib.h"
  11. #include "MapDoc.h"
  12. #include "MapEntity.h"
  13. #include "MapWorld.h"
  14. #include "KeyFrame/KeyFrame.h"
  15. #include "MapKeyFrame.h"
  16. #include "MapAnimator.h"
  17. #include "Render3D.h"
  18. #include "TextureSystem.h"
  19. #include "materialsystem/imesh.h"
  20. #include "Material.h"
  21. // memdbgon must be the last include file in a .cpp file!!!
  22. #include <tier0/memdbgon.h>
  23. IMPLEMENT_MAPCLASS( CMapKeyFrame );
  24. //-----------------------------------------------------------------------------
  25. // Purpose: Factory function. Used for creating a CMapKeyFrame from a set
  26. // of string parameters from the FGD file.
  27. // Input : *pInfo - Pointer to helper info class which gives us information
  28. // about how to create the class.
  29. // Output : Returns a pointer to the class, NULL if an error occurs.
  30. //-----------------------------------------------------------------------------
  31. CMapClass *CMapKeyFrame::CreateMapKeyFrame(CHelperInfo *pHelperInfo, CMapEntity *pParent)
  32. {
  33. return(new CMapKeyFrame);
  34. }
  35. //-----------------------------------------------------------------------------
  36. // Purpose:
  37. //-----------------------------------------------------------------------------
  38. CMapKeyFrame::CMapKeyFrame()
  39. {
  40. m_pAnimator = NULL;
  41. m_pNextKeyFrame = NULL;
  42. m_flMoveTime = 0;
  43. m_flSpeed = 0;
  44. m_bRebuildPath = false;
  45. m_Angles.Init();
  46. // setup the quaternion identity
  47. m_qAngles[0] = m_qAngles[1] = m_qAngles[2] = 0;
  48. m_qAngles[3] = 1;
  49. m_pPositionInterpolator = NULL;
  50. m_iPositionInterpolator = -1;
  51. m_iChangeFrame = -1;
  52. }
  53. //-----------------------------------------------------------------------------
  54. // Purpose:
  55. //-----------------------------------------------------------------------------
  56. CMapKeyFrame::~CMapKeyFrame()
  57. {
  58. if( m_pPositionInterpolator )
  59. m_pPositionInterpolator->Release();
  60. }
  61. //-----------------------------------------------------------------------------
  62. // Purpose:
  63. // Input : bFullUpdate -
  64. //-----------------------------------------------------------------------------
  65. void CMapKeyFrame::CalcBounds(BOOL bFullUpdate)
  66. {
  67. CMapClass::CalcBounds(bFullUpdate);
  68. //
  69. // Calculate the 3D bounds to include all points on our line.
  70. //
  71. m_CullBox.ResetBounds();
  72. m_CullBox.UpdateBounds(m_Origin);
  73. if( m_pNextKeyFrame )
  74. {
  75. // Expand the bbox by the target entity's origin.
  76. Vector vNextOrigin;
  77. m_pNextKeyFrame->GetOrigin( vNextOrigin );
  78. m_CullBox.UpdateBounds(vNextOrigin);
  79. // Expand the bbox by the points on our line.
  80. for ( int i=0; i < MAX_LINE_POINTS; i++ )
  81. {
  82. m_CullBox.UpdateBounds(m_LinePoints[i]);
  83. }
  84. }
  85. m_BoundingBox = m_CullBox;
  86. //
  87. // Our 2D bounds are just a point, because we don't render in 2D.
  88. //
  89. m_Render2DBox.ResetBounds();
  90. m_Render2DBox.UpdateBounds(m_Origin, m_Origin);
  91. }
  92. //-----------------------------------------------------------------------------
  93. // Purpose:
  94. // Output : CMapClass *
  95. //-----------------------------------------------------------------------------
  96. CMapClass *CMapKeyFrame::Copy(bool bUpdateDependencies)
  97. {
  98. CMapKeyFrame *pNew = new CMapKeyFrame;
  99. pNew->CopyFrom(this, bUpdateDependencies);
  100. return pNew;
  101. }
  102. //-----------------------------------------------------------------------------
  103. // Purpose:
  104. // Input : *pObj -
  105. // Output : CMapClass *
  106. //-----------------------------------------------------------------------------
  107. CMapClass *CMapKeyFrame::CopyFrom(CMapClass *pObj, bool bUpdateDependencies)
  108. {
  109. CMapClass::CopyFrom(pObj, bUpdateDependencies);
  110. CMapKeyFrame *pFrom = dynamic_cast<CMapKeyFrame*>( pObj );
  111. Assert( pFrom != NULL );
  112. m_qAngles = pFrom->m_qAngles;
  113. m_Angles = pFrom->m_Angles;
  114. m_flSpeed = pFrom->m_flSpeed;
  115. m_flMoveTime = pFrom->m_flMoveTime;
  116. if (bUpdateDependencies)
  117. {
  118. m_pNextKeyFrame = (CMapKeyFrame *)UpdateDependency(m_pNextKeyFrame, pFrom->m_pNextKeyFrame);
  119. }
  120. else
  121. {
  122. m_pNextKeyFrame = pFrom->m_pNextKeyFrame;
  123. }
  124. m_bRebuildPath = true;
  125. return this;
  126. }
  127. //-----------------------------------------------------------------------------
  128. // Purpose: notifies the keyframe that it has been cloned
  129. // inserts the clone into the correct place in the keyframe list
  130. // Input : *pClone -
  131. //-----------------------------------------------------------------------------
  132. void CMapKeyFrame::OnClone( CMapClass *pClone, CMapWorld *pWorld, const CMapObjectList &OriginalList, CMapObjectList &NewList )
  133. {
  134. CMapClass::OnClone( pClone, pWorld, OriginalList, NewList );
  135. CMapKeyFrame *pNewKey = dynamic_cast<CMapKeyFrame*>( pClone );
  136. Assert( pNewKey != NULL );
  137. if ( !pNewKey )
  138. return;
  139. CMapEntity *pEntity = dynamic_cast<CMapEntity*>( m_pParent );
  140. CMapEntity *pNewEntity = dynamic_cast<CMapEntity*>( pClone->GetParent() );
  141. // insert the newly created keyframe into the sequence
  142. // point the clone's next at what we were pointing at
  143. const char *nextKey = pEntity->GetKeyValue( "NextKey" );
  144. if ( nextKey )
  145. {
  146. pNewEntity->SetKeyValue( "NextKey", nextKey );
  147. }
  148. // create a new targetname for the clone
  149. char newName[128];
  150. const char *oldName = pEntity->GetKeyValue( "targetname" );
  151. if ( !oldName || oldName[0] == 0 )
  152. oldName = "keyframe";
  153. pWorld->GenerateNewTargetname( oldName, newName, sizeof( newName ), true, NULL );
  154. pNewEntity->SetKeyValue( "targetname", newName );
  155. // point the current keyframe at the clone
  156. pEntity->SetKeyValue( "NextKey", newName );
  157. }
  158. //-----------------------------------------------------------------------------
  159. // Purpose: Called just after this object has been removed from the world so
  160. // that it can unlink itself from other objects in the world.
  161. // Input : pWorld - The world that we were just removed from.
  162. // bNotifyChildren - Whether we should forward notification to our children.
  163. //-----------------------------------------------------------------------------
  164. void CMapKeyFrame::OnRemoveFromWorld(CMapWorld *pWorld, bool bNotifyChildren)
  165. {
  166. CMapClass::OnRemoveFromWorld(pWorld, bNotifyChildren);
  167. //
  168. // Detach ourselves from the next keyframe in the path.
  169. //
  170. m_pNextKeyFrame = (CMapKeyFrame *)UpdateDependency(m_pNextKeyFrame, NULL);
  171. }
  172. //-----------------------------------------------------------------------------
  173. // Purpose:
  174. // Input : *outQuat -
  175. //-----------------------------------------------------------------------------
  176. void CMapKeyFrame::GetQuatAngles( Quaternion &outQuat )
  177. {
  178. outQuat = m_qAngles;
  179. }
  180. //-----------------------------------------------------------------------------
  181. // Purpose: Recalulates timings based on the new position
  182. // Input : *pfOrigin -
  183. //-----------------------------------------------------------------------------
  184. void CMapKeyFrame::SetOrigin( Vector& pfOrigin )
  185. {
  186. CMapClass::SetOrigin(pfOrigin);
  187. m_bRebuildPath = true;
  188. }
  189. //-----------------------------------------------------------------------------
  190. // Purpose: Renders the connecting lines between the keyframes
  191. // Input : pRender -
  192. //-----------------------------------------------------------------------------
  193. void CMapKeyFrame::Render3D( CRender3D *pRender )
  194. {
  195. if ( m_bRebuildPath )
  196. {
  197. if (GetAnimator() != NULL)
  198. {
  199. GetAnimator()->RebuildPath();
  200. }
  201. }
  202. // only draw if we have a valid connection
  203. if ( m_pNextKeyFrame && m_flSpeed > 0 )
  204. {
  205. // only draw if we haven't already been drawn this frame
  206. if ( GetRenderFrame() != pRender->GetRenderFrame() )
  207. {
  208. pRender->PushRenderMode( RENDER_MODE_WIREFRAME );
  209. SetRenderFrame( pRender->GetRenderFrame() );
  210. Vector o1, o2;
  211. GetOrigin( o1 );
  212. m_pNextKeyFrame->GetOrigin( o2 );
  213. CMeshBuilder meshBuilder;
  214. CMatRenderContextPtr pRenderContext( MaterialSystemInterface() );
  215. IMesh *pMesh = pRenderContext->GetDynamicMesh();
  216. // draw connecting line going from green to red
  217. meshBuilder.Begin( pMesh, MATERIAL_LINE_STRIP, MAX_LINE_POINTS );
  218. // start point
  219. meshBuilder.Color3f( 0, 1.0f, 0 );
  220. meshBuilder.Position3f( o1[0], o1[1], o1[2] );
  221. meshBuilder.AdvanceVertex();
  222. for ( int i = 0; i < MAX_LINE_POINTS; i++ )
  223. {
  224. float red = (float)(i+1) / (float)MAX_LINE_POINTS;
  225. meshBuilder.Color3f( red, 1.0f - red, 0 );
  226. meshBuilder.Position3f( m_LinePoints[i][0], m_LinePoints[i][1], m_LinePoints[i][2] );
  227. meshBuilder.AdvanceVertex();
  228. }
  229. meshBuilder.End();
  230. pMesh->Draw();
  231. pRender->PopRenderMode();
  232. }
  233. }
  234. }
  235. //-----------------------------------------------------------------------------
  236. // Purpose: Returns the total time remaining in the animation sequence in seconds.
  237. //-----------------------------------------------------------------------------
  238. float CMapKeyFrame::GetRemainingTime( CMapObjectList *pVisited )
  239. {
  240. CMapObjectList Visited;
  241. if ( pVisited == NULL )
  242. {
  243. pVisited = &Visited;
  244. }
  245. //
  246. // Check for circularities.
  247. //
  248. if ( pVisited->Find( this ) != -1 )
  249. {
  250. return 0.0f;
  251. }
  252. pVisited->AddToTail( this );
  253. if ( m_pNextKeyFrame )
  254. {
  255. return m_flMoveTime + m_pNextKeyFrame->GetRemainingTime( pVisited );
  256. }
  257. return 0.0f;
  258. }
  259. //-----------------------------------------------------------------------------
  260. // Purpose:
  261. // Output : CMapKeyFrame
  262. //-----------------------------------------------------------------------------
  263. CMapKeyFrame *CMapKeyFrame::NextKeyFrame( void )
  264. {
  265. if ( !m_pNextKeyFrame )
  266. return this;
  267. return m_pNextKeyFrame;
  268. }
  269. //-----------------------------------------------------------------------------
  270. // Purpose: Notifies that the entity this is attached to has had a key change
  271. // Input : key -
  272. // value -
  273. //-----------------------------------------------------------------------------
  274. void CMapKeyFrame::OnParentKeyChanged( const char* key, const char* value )
  275. {
  276. if ( !stricmp(key, "NextKey") )
  277. {
  278. m_bRebuildPath = true;
  279. }
  280. else if ( !stricmp(key, "NextTime") )
  281. {
  282. m_flMoveTime = atof( value );
  283. }
  284. else if ( !stricmp(key, "MoveSpeed") )
  285. {
  286. m_flSpeed = atof( value );
  287. m_bRebuildPath = true;
  288. }
  289. else if (!stricmp(key, "angles"))
  290. {
  291. sscanf(value, "%f %f %f", &m_Angles[PITCH], &m_Angles[YAW], &m_Angles[ROLL]);
  292. AngleQuaternion(m_Angles, m_qAngles);
  293. }
  294. if( m_pPositionInterpolator )
  295. {
  296. if( m_pPositionInterpolator->ProcessKey( key, value ) )
  297. m_bRebuildPath = true;
  298. }
  299. }
  300. //-----------------------------------------------------------------------------
  301. // Purpose: calculates the time the current key frame should take, given
  302. // the movement speed, and the distance to the next keyframe
  303. //-----------------------------------------------------------------------------
  304. void CMapKeyFrame::RecalculateTimeFromSpeed( void )
  305. {
  306. if ( m_flSpeed <= 0 )
  307. return;
  308. if ( !m_pNextKeyFrame )
  309. return;
  310. // calculate the distance to the next key
  311. Vector o1;
  312. m_pNextKeyFrame->GetOrigin( o1 );
  313. Vector o2 = o1 - m_Origin;
  314. float dist = VectorLength( o2 );
  315. // couldn't get time from distance, get it from rotation instead
  316. if ( !dist )
  317. {
  318. // speed is in degrees per second
  319. // find the largest rotation component and use that
  320. QAngle ang = m_Angles - m_pNextKeyFrame->m_Angles;
  321. dist = 0;
  322. for ( int i = 0; i < 3; i++ )
  323. {
  324. fixang( ang[i] );
  325. if ( ang[i] > 180 )
  326. ang[i] = ang[i] - 360;
  327. if ( abs(ang[i]) > dist )
  328. {
  329. dist = abs(ang[i]);
  330. }
  331. }
  332. }
  333. // time = distance / speed
  334. float newTime = dist / m_flSpeed;
  335. // set the new speed (99.99% of the time this is the same so don't
  336. // bother forcing it to rebuild the path).
  337. if( m_flMoveTime != newTime )
  338. {
  339. m_flMoveTime = newTime;
  340. // rebuild the path before we next render
  341. m_bRebuildPath = true;
  342. }
  343. // "NextTime" key removed until we get a real-time updating entity properties dialog
  344. /*
  345. CMapEntity *ent = dynamic_cast<CMapEntity*>( Parent );
  346. if ( ent )
  347. {
  348. char buf[16];
  349. sprintf( buf, "%.2f", newTime );
  350. ent->SetKeyValue( "NextTime", buf );
  351. ent->OnParentKeyChanged( "NextTime", buf );
  352. }
  353. */
  354. }
  355. //-----------------------------------------------------------------------------
  356. // Purpose: Builds the spline points between this keyframe and the previous
  357. // keyframe.
  358. // Input : pPrev -
  359. //-----------------------------------------------------------------------------
  360. void CMapKeyFrame::BuildPathSegment( CMapKeyFrame *pPrev )
  361. {
  362. RecalculateTimeFromSpeed();
  363. CMapAnimator *pAnim = GetAnimator();
  364. Quaternion qAngles;
  365. for ( int i = 0; i < MAX_LINE_POINTS; i++ )
  366. {
  367. if (pAnim != NULL)
  368. {
  369. CMapAnimator::GetAnimationAtTime( this, pPrev, MoveTime() * ( float )( i + 1 ) / (float)MAX_LINE_POINTS, m_LinePoints[i], qAngles, pAnim->m_iPositionInterpolator, pAnim->m_iRotationInterpolator );
  370. }
  371. else
  372. {
  373. // FIXME: If we aren't connected to an animator yet, just draw straight lines. This code is never hit, because
  374. // BuildPathSegment is only called from CMapAnimator. To make matters worse, we can only reliably find
  375. // pPrev through an animator.
  376. CMapAnimator::GetAnimationAtTime( this, pPrev, MoveTime() * (float)( i + 1) / (float)MAX_LINE_POINTS, m_LinePoints[i], qAngles, 0, 0 );
  377. }
  378. }
  379. // HACK: we shouldn't need to do this. CalcBounds alone should work (but it doesn't because of where we
  380. // call RebuildPath from). Make this work more like other objects.
  381. if ( m_pParent )
  382. {
  383. GetParent()->CalcBounds( true );
  384. }
  385. else
  386. {
  387. CalcBounds();
  388. }
  389. m_bRebuildPath = false;
  390. }
  391. //-----------------------------------------------------------------------------
  392. // Purpose: Called when an object that we depend on has changed.
  393. //-----------------------------------------------------------------------------
  394. void CMapKeyFrame::OnNotifyDependent(CMapClass *pObject, Notify_Dependent_t eNotifyType)
  395. {
  396. CMapClass::OnNotifyDependent(pObject, eNotifyType);
  397. if ((pObject == m_pAnimator) && (eNotifyType == Notify_Removed))
  398. {
  399. SetAnimator(NULL);
  400. }
  401. //
  402. // If our next keyframe was deleted, try to link to the one after it.
  403. //
  404. if ((pObject == m_pNextKeyFrame) && (eNotifyType == Notify_Removed))
  405. {
  406. CMapEntity *pNextParent = m_pNextKeyFrame->GetParentEntity();
  407. CMapEntity *pParent = GetParentEntity();
  408. if ( pNextParent && pParent )
  409. {
  410. const char *szNext = pNextParent->GetKeyValue("NextKey");
  411. pParent->SetKeyValue("NextKey", szNext);
  412. }
  413. }
  414. m_bRebuildPath = true;
  415. }
  416. //-----------------------------------------------------------------------------
  417. // Purpose: returns a pointer to our parent entity
  418. // Output : CMapEntity
  419. //-----------------------------------------------------------------------------
  420. CMapEntity *CMapKeyFrame::GetParentEntity( void )
  421. {
  422. return dynamic_cast<CMapEntity*>( m_pParent );
  423. }
  424. //-----------------------------------------------------------------------------
  425. // Purpose:
  426. // Output : Returns true on success, false on failure.
  427. //-----------------------------------------------------------------------------
  428. bool CMapKeyFrame::IsAnyKeyInSequenceSelected( void )
  429. {
  430. if ( m_pParent && m_pParent->IsSelected() )
  431. {
  432. return true;
  433. }
  434. // search forward
  435. for ( CMapKeyFrame *find = m_pAnimator; find != NULL; find = find->m_pNextKeyFrame )
  436. {
  437. if ( find->m_pParent && find->m_pParent->IsSelected() )
  438. {
  439. return true;
  440. }
  441. }
  442. // no selected items found
  443. return false;
  444. }
  445. //-----------------------------------------------------------------------------
  446. // Purpose:
  447. // Input : iInterpolator -
  448. // Output : IPositionInterpolator
  449. //-----------------------------------------------------------------------------
  450. IPositionInterpolator* CMapKeyFrame::SetupPositionInterpolator( int iInterpolator )
  451. {
  452. if( iInterpolator != m_iPositionInterpolator )
  453. {
  454. if( m_pPositionInterpolator )
  455. m_pPositionInterpolator->Release();
  456. m_pPositionInterpolator = Motion_GetPositionInterpolator( iInterpolator );
  457. m_iPositionInterpolator = iInterpolator;
  458. // Feed keys..
  459. CMapEntity *pEnt = GetParentEntity();
  460. if( pEnt )
  461. {
  462. for ( int i=pEnt->GetFirstKeyValue(); i != pEnt->GetInvalidKeyValue(); i=pEnt->GetNextKeyValue( i ) )
  463. {
  464. m_pPositionInterpolator->ProcessKey(
  465. pEnt->GetKey( i ),
  466. pEnt->GetKeyValue( i ) );
  467. }
  468. }
  469. }
  470. return m_pPositionInterpolator;
  471. }
  472. //-----------------------------------------------------------------------------
  473. // Purpose: Marks that we need to relink any pointers defined by target/targetname pairs
  474. //-----------------------------------------------------------------------------
  475. void CMapKeyFrame::UpdateDependencies(CMapWorld *pWorld, CMapClass *pObject)
  476. {
  477. CMapClass::UpdateDependencies(pWorld, pObject);
  478. m_bRebuildPath = true;
  479. }
  480. //-----------------------------------------------------------------------------
  481. // Purpose:
  482. //-----------------------------------------------------------------------------
  483. void CMapKeyFrame::SetAnimator(CMapAnimator *pAnimator)
  484. {
  485. m_pAnimator = (CMapAnimator *)UpdateDependency(m_pAnimator, pAnimator);
  486. }
  487. //-----------------------------------------------------------------------------
  488. // Purpose:
  489. //-----------------------------------------------------------------------------
  490. void CMapKeyFrame::SetNextKeyFrame(CMapKeyFrame *pNext)
  491. {
  492. m_pNextKeyFrame = (CMapKeyFrame *)UpdateDependency(m_pNextKeyFrame, pNext);
  493. }