Counter Strike : Global Offensive Source Code
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.

1787 lines
56 KiB

  1. //====== Copyright � 1996-2004, Valve Corporation, All rights reserved. =======
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "movieobjects/dmedag.h"
  7. #include "movieobjects/dmeshape.h"
  8. #include "datamodel/dmelementfactoryhelper.h"
  9. #include "movieobjects/dmetransform.h"
  10. #include "movieobjects/dmeoverlay.h"
  11. #include "movieobjects_interfaces.h"
  12. #include "movieobjects/dmedrawsettings.h"
  13. #include "movieobjects/dmeclip.h"
  14. #include "movieobjects/dmelog.h"
  15. #include "movieobjects/dmechannel.h"
  16. #include "movieobjects/dmerigconstraintoperators.h"
  17. #include "movieobjects/dmetransformcontrol.h"
  18. #include "movieobjects/dmeattributereference.h"
  19. #include "movieobjects/dmerig.h"
  20. // memdbgon must be the last include file in a .cpp file!!!
  21. #include "tier0/memdbgon.h"
  22. static const char OVERRIDE_PARENT[] = "overrideParent";
  23. //-----------------------------------------------------------------------------
  24. // Expose this class to the scene database
  25. //-----------------------------------------------------------------------------
  26. IMPLEMENT_ELEMENT_FACTORY( DmeDag, CDmeDag );
  27. //-----------------------------------------------------------------------------
  28. // Purpose:
  29. //-----------------------------------------------------------------------------
  30. CUtlStack<CDmeDag::TransformInfo_t> CDmeDag::s_TransformStack;
  31. bool CDmeDag::s_bDrawUsingEngineCoordinates = false;
  32. bool CDmeDag::s_bDrawZUp = false;
  33. //-----------------------------------------------------------------------------
  34. // Purpose:
  35. //-----------------------------------------------------------------------------
  36. void CDmeDag::OnConstruction()
  37. {
  38. m_Transform.InitAndCreate( this, "transform" );
  39. m_Shape.Init( this, "shape" );
  40. m_Visible.InitAndSet( this, "visible", true, FATTRIB_HAS_CALLBACK );
  41. m_Children.Init( this, "children" );
  42. m_bDisableOverrideParent.InitAndSet( this, "disableOverride", false, FATTRIB_DONTSAVE | FATTRIB_HIDDEN );
  43. }
  44. void CDmeDag::OnDestruction()
  45. {
  46. g_pDataModel->DestroyElement( m_Transform.GetHandle() );
  47. }
  48. void CDmeDag::Resolve()
  49. {
  50. // Since the overrideParent attribute is added dynamically we must update
  51. // its flags is it present when re-loaded since the flags are not stored.
  52. CDmAttribute *pAttribute = GetAttribute( OVERRIDE_PARENT );
  53. if ( pAttribute )
  54. {
  55. pAttribute->AddFlag( FATTRIB_NEVERCOPY );
  56. }
  57. }
  58. //-----------------------------------------------------------------------------
  59. // Accessors
  60. //-----------------------------------------------------------------------------
  61. CDmeTransform *CDmeDag::GetTransform() const
  62. {
  63. return m_Transform.GetElement();
  64. }
  65. CDmeShape *CDmeDag::GetShape()
  66. {
  67. return m_Shape.GetElement();
  68. }
  69. void CDmeDag::SetShape( CDmeShape *pShape )
  70. {
  71. m_Shape = pShape;
  72. }
  73. bool CDmeDag::IsVisible() const
  74. {
  75. return m_Visible;
  76. }
  77. void CDmeDag::SetVisible( bool bVisible )
  78. {
  79. m_Visible = bVisible;
  80. }
  81. //-----------------------------------------------------------------------------
  82. // Returns the visibility attribute for DmeRenderable support
  83. //-----------------------------------------------------------------------------
  84. CDmAttribute *CDmeDag::GetVisibilityAttribute()
  85. {
  86. return m_Visible.GetAttribute();
  87. }
  88. //-----------------------------------------------------------------------------
  89. // child helpers
  90. //-----------------------------------------------------------------------------
  91. const CUtlVector< DmElementHandle_t > &CDmeDag::GetChildren() const
  92. {
  93. return m_Children.Get();
  94. }
  95. int CDmeDag::GetChildCount() const
  96. {
  97. return m_Children.Count();
  98. }
  99. CDmeDag *CDmeDag::GetChild( int i ) const
  100. {
  101. if ( i < 0 || i >= m_Children.Count() )
  102. return NULL;
  103. return m_Children.Get( i );
  104. }
  105. bool CDmeDag::AddChild( CDmeDag* pDag )
  106. {
  107. if ( !pDag || pDag == this )
  108. return false;
  109. // Don't allow a cycle to be created
  110. if ( pDag->IsAncestorOfDag( this ) )
  111. return false;
  112. m_Children.AddToTail( pDag );
  113. return true;
  114. }
  115. void CDmeDag::RemoveChild( int i )
  116. {
  117. m_Children.FastRemove( i );
  118. }
  119. void CDmeDag::RemoveChild( const CDmeDag *pChild, bool bRecurse )
  120. {
  121. int i = FindChild( pChild );
  122. if ( i >= 0 )
  123. {
  124. RemoveChild( i );
  125. }
  126. }
  127. void CDmeDag::RemoveAllChildren()
  128. {
  129. m_Children.RemoveAll();
  130. }
  131. //-----------------------------------------------------------------------------
  132. // Sets the parent of this node to the specified parent. Removes any other
  133. // parent nodes
  134. //-----------------------------------------------------------------------------
  135. bool CDmeDag::SetParent( CDmeDag *pDmeDagParent )
  136. {
  137. if ( !pDmeDagParent || pDmeDagParent == this )
  138. return false;
  139. CUtlVector< CDmeDag * > parentList;
  140. FindAncestorsReferencingElement( this, parentList );
  141. for ( int i = 0; i < parentList.Count(); ++i )
  142. {
  143. if ( !parentList[ i ] )
  144. continue;
  145. parentList[ i ]->RemoveChild( this );
  146. }
  147. return pDmeDagParent->AddChild( this );
  148. }
  149. int CDmeDag::FindChild( const CDmeDag *pChild ) const
  150. {
  151. return m_Children.Find( pChild->GetHandle() );
  152. }
  153. // recursive
  154. int CDmeDag::FindChild( CDmeDag *&pParent, const CDmeDag *pChild )
  155. {
  156. int index = FindChild( pChild );
  157. if ( index >= 0 )
  158. {
  159. pParent = this;
  160. return index;
  161. }
  162. int nChildren = m_Children.Count();
  163. for ( int ci = 0; ci < nChildren; ++ci )
  164. {
  165. index = m_Children[ ci ]->FindChild( pParent, pChild );
  166. if ( index >= 0 )
  167. return index;
  168. }
  169. pParent = NULL;
  170. return -1;
  171. }
  172. int CDmeDag::FindChild( const char *name ) const
  173. {
  174. int nChildren = m_Children.Count();
  175. for ( int ci = 0; ci < nChildren; ++ci )
  176. {
  177. if ( V_strcmp( m_Children[ ci ]->GetName(), name ) == 0 )
  178. return ci;
  179. }
  180. return -1;
  181. }
  182. CDmeDag *CDmeDag::FindOrAddChild( const char *name )
  183. {
  184. int i = FindChild( name );
  185. if ( i >= 0 )
  186. return GetChild( i );
  187. CDmeDag *pChild = CreateElement< CDmeDag >( name, GetFileId() );
  188. AddChild( pChild );
  189. return pChild;
  190. }
  191. CDmeDag *CDmeDag::FindChildByName_R( const char *name ) const
  192. {
  193. int i = FindChild( name );
  194. if ( i >= 0 )
  195. return GetChild( i );
  196. int nChildren = m_Children.Count();
  197. for ( int ci = 0; ci < nChildren; ++ci )
  198. {
  199. CDmeDag *found = m_Children[ ci ]->FindChildByName_R( name );
  200. if ( found )
  201. return found;
  202. }
  203. return NULL;
  204. }
  205. //-----------------------------------------------------------------------------
  206. // Purpose: Return the number of steps ( levels, connections, etc...) between
  207. // the the node a the specified child node. If the provided node is not a
  208. // child of this node -1 will be returned.
  209. //-----------------------------------------------------------------------------
  210. int CDmeDag::StepsToChild( const CDmeDag *pChild ) const
  211. {
  212. int nSteps = 0;
  213. for ( const CDmeDag *pDag = pChild; pDag; pDag = pDag->GetParent(), ++nSteps )
  214. {
  215. if ( pDag == this )
  216. return nSteps;
  217. }
  218. return -1;
  219. }
  220. //-----------------------------------------------------------------------------
  221. // Recursively render the Dag hierarchy
  222. //-----------------------------------------------------------------------------
  223. void CDmeDag::PushDagTransform()
  224. {
  225. int i = s_TransformStack.Push();
  226. TransformInfo_t &info = s_TransformStack[i];
  227. info.m_pTransform = GetTransform();
  228. info.m_bComputedDagToWorld = false;
  229. }
  230. void CDmeDag::PopDagTransform()
  231. {
  232. Assert( s_TransformStack.Top().m_pTransform == GetTransform() );
  233. s_TransformStack.Pop();
  234. }
  235. //-----------------------------------------------------------------------------
  236. // Transform from DME to engine coordinates
  237. //-----------------------------------------------------------------------------
  238. void CDmeDag::DmeToEngineMatrix( matrix3x4_t& dmeToEngine, bool bZUp )
  239. {
  240. if ( bZUp )
  241. {
  242. VMatrix rotationZ;
  243. MatrixBuildRotationAboutAxis( rotationZ, Vector( 0, 0, 1 ), 90 );
  244. rotationZ.Set3x4( dmeToEngine );
  245. }
  246. else
  247. {
  248. VMatrix rotation, rotationZ;
  249. MatrixBuildRotationAboutAxis( rotation, Vector( 1, 0, 0 ), 90 );
  250. MatrixBuildRotationAboutAxis( rotationZ, Vector( 0, 1, 0 ), 90 );
  251. ConcatTransforms( rotation.As3x4(), rotationZ.As3x4(), dmeToEngine );
  252. }
  253. }
  254. //-----------------------------------------------------------------------------
  255. // Transform from engine to DME coordinates
  256. //-----------------------------------------------------------------------------
  257. void CDmeDag::EngineToDmeMatrix( matrix3x4_t& engineToDme, bool bZUp )
  258. {
  259. if ( bZUp )
  260. {
  261. VMatrix rotationZ;
  262. MatrixBuildRotationAboutAxis( rotationZ, Vector( 0, 0, 1 ), -90 );
  263. rotationZ.Set3x4( engineToDme );
  264. }
  265. else
  266. {
  267. VMatrix rotation, rotationZ;
  268. MatrixBuildRotationAboutAxis( rotation, Vector( 1, 0, 0 ), -90 );
  269. MatrixBuildRotationAboutAxis( rotationZ, Vector( 0, 1, 0 ), -90 );
  270. ConcatTransforms( rotationZ.As3x4(), rotation.As3x4(), engineToDme );
  271. }
  272. }
  273. void CDmeDag::GetShapeToWorldTransform( matrix3x4_t &mat )
  274. {
  275. int nCount = s_TransformStack.Count();
  276. if ( nCount == 0 )
  277. {
  278. if ( !s_bDrawUsingEngineCoordinates )
  279. {
  280. SetIdentityMatrix( mat );
  281. }
  282. else
  283. {
  284. DmeToEngineMatrix( mat, s_bDrawZUp );
  285. }
  286. return;
  287. }
  288. if ( s_TransformStack.Top().m_bComputedDagToWorld )
  289. {
  290. MatrixCopy( s_TransformStack.Top().m_DagToWorld, mat );
  291. return;
  292. }
  293. // Compute all uncomputed dag to worls
  294. int i;
  295. for ( i = 0; i < nCount; ++i )
  296. {
  297. TransformInfo_t &info = s_TransformStack[i];
  298. if ( !info.m_bComputedDagToWorld )
  299. break;
  300. }
  301. // Set up the initial transform
  302. if ( i == 0 )
  303. {
  304. if ( !s_bDrawUsingEngineCoordinates )
  305. {
  306. SetIdentityMatrix( mat );
  307. }
  308. else
  309. {
  310. DmeToEngineMatrix( mat, s_bDrawZUp );
  311. }
  312. }
  313. else
  314. {
  315. MatrixCopy( s_TransformStack[i-1].m_DagToWorld, mat );
  316. }
  317. // Compute all transforms
  318. for ( ; i < nCount; ++i )
  319. {
  320. matrix3x4_t localToParent;
  321. TransformInfo_t &info = s_TransformStack[i];
  322. info.m_pTransform->GetTransform( localToParent );
  323. ConcatTransforms( mat, localToParent, info.m_DagToWorld );
  324. info.m_bComputedDagToWorld = true;
  325. MatrixCopy( info.m_DagToWorld, mat );
  326. }
  327. }
  328. //-----------------------------------------------------------------------------
  329. //
  330. //-----------------------------------------------------------------------------
  331. void CDmeDag::GetLocalMatrix( matrix3x4_t &m ) const
  332. {
  333. CDmeTransform *pTransform = GetTransform();
  334. if ( pTransform )
  335. {
  336. pTransform->GetTransform( m );
  337. }
  338. else
  339. {
  340. SetIdentityMatrix( m );
  341. }
  342. }
  343. void CDmeDag::SetLocalMatrix( matrix3x4_t &mat )
  344. {
  345. CDmeTransform *pTransform = GetTransform();
  346. if ( !pTransform )
  347. return;
  348. pTransform->SetTransform( mat );
  349. }
  350. //-----------------------------------------------------------------------------
  351. // Get the transform matrix which converts from the space of the parent of the
  352. // dag node to world space. If the dag node has an override parent specified
  353. // it will be accounted for when generating the matrix.
  354. //-----------------------------------------------------------------------------
  355. void CDmeDag::GetParentWorldMatrix( matrix3x4_t &mParentToWorld ) const
  356. {
  357. CDmeDag *pParent = GetParent();
  358. if ( HasOverrideParent() )
  359. {
  360. bool bOverridePos = false;
  361. bool bOverrideRot = false;
  362. const CDmeDag *pOverrideParent = GetOverrideParent( bOverridePos, bOverrideRot );
  363. if ( bOverridePos && bOverrideRot )
  364. {
  365. pOverrideParent->GetAbsTransform( mParentToWorld );
  366. }
  367. else
  368. {
  369. if ( pParent )
  370. {
  371. pParent->GetAbsTransform( mParentToWorld );
  372. }
  373. else
  374. {
  375. SetIdentityMatrix( mParentToWorld );
  376. }
  377. Quaternion absOrientation;
  378. Vector absPosition;
  379. if ( bOverridePos )
  380. {
  381. // The desired result of a position only parent override is that no changes to the original parent in either
  382. // position or rotation will have any impact on the position of the dag. Furthermore we prefer rotations of
  383. // the original parent to pivot around the dag node's center, not the override parent's center. To accomplish
  384. // this we essentially want to compute the rotation normally, but then apply the local translation of the dag
  385. // to the position of the override dag in world space. In order to construct the a parent matrix that still
  386. // allows the local transform of the dag to be concatenated normally, we essentially do the whole transform
  387. // here when constructing the parent matrix and then apply the inverse of the local matrix, so we know when
  388. // the local matrix is concatenated later the result will be what we setup before applying the inverse of the
  389. // local matrix.
  390. CDmeTransform *pLocalTransform = GetTransform();
  391. if ( pLocalTransform )
  392. {
  393. Vector localPosition = pLocalTransform->GetPosition();
  394. Quaternion localOrientation = pLocalTransform->GetOrientation();
  395. // Compute the orientation normally as if there is no override parent
  396. // by concatenating the local orientation with the parent orientation.
  397. Quaternion parentOrientation;
  398. Quaternion worldOrientation;
  399. MatrixQuaternion( mParentToWorld, parentOrientation );
  400. QuaternionMult( parentOrientation, localOrientation, worldOrientation );
  401. // Compute the position by simply adding the local position to the world space
  402. // position of the override parent, this effectively make the local translation
  403. // of the dag a world space operation so it is never effected by rotation.
  404. Vector overridePosition;
  405. pOverrideParent->GetAbsPosition( overridePosition );
  406. Vector worldPosition = overridePosition + localPosition;
  407. // Compute the final world transform we will want for the dag
  408. // (i.e. this is the reuslt we want GetAbsTransform() to return)
  409. matrix3x4_t mWorldTransform;
  410. QuaternionMatrix( worldOrientation, worldPosition, mWorldTransform );
  411. // Now construct an apply the inverse of the local transform in order to get
  412. // an appropriate parent matrix that will yield the desired mWorldTransfom
  413. // when the local transform of the dag is applied to it.
  414. matrix3x4_t mLocalTransform;
  415. matrix3x4_t mInvLocalTransform;
  416. QuaternionMatrix( localOrientation, localPosition, mLocalTransform );
  417. MatrixInvert( mLocalTransform, mInvLocalTransform );
  418. ConcatTransforms( mWorldTransform, mInvLocalTransform, mParentToWorld );
  419. }
  420. }
  421. else if ( bOverrideRot )
  422. {
  423. // Rotation only override is much simpler than position, just construct a matrix with
  424. // the orientation of the override parent and the position of the original parent.
  425. pOverrideParent->GetAbsOrientation( absOrientation );
  426. MatrixPosition( mParentToWorld, absPosition );
  427. QuaternionMatrix( absOrientation, absPosition, mParentToWorld );
  428. }
  429. }
  430. }
  431. else if ( pParent )
  432. {
  433. pParent->GetAbsTransform( mParentToWorld );
  434. }
  435. else
  436. {
  437. SetIdentityMatrix( mParentToWorld );
  438. }
  439. }
  440. //-----------------------------------------------------------------------------
  441. // Get the matrix matrix for computing the position of the dag node. This is
  442. // the same as GetParentWorldMatrix except in the case where the dag node has
  443. // a position only override parent. This should be used when trying to apply a
  444. // translation to the dag and conversion from world space to the space of the
  445. // parent of the dag is required.
  446. //-----------------------------------------------------------------------------
  447. void CDmeDag::GetTranslationParentWorldMatrix( matrix3x4_t &mParentToWorld )
  448. {
  449. bool bOverridePos = false;
  450. bool bOverrideRot = false;
  451. const CDmeDag *pOverrideParent = GetOverrideParent( bOverridePos, bOverrideRot );
  452. if ( pOverrideParent && bOverridePos && !bOverrideRot )
  453. {
  454. Vector overridePosition;
  455. pOverrideParent->GetAbsPosition( overridePosition );
  456. SetIdentityMatrix( mParentToWorld );
  457. PositionMatrix( overridePosition, mParentToWorld );
  458. }
  459. else
  460. {
  461. GetParentWorldMatrix( mParentToWorld );
  462. }
  463. }
  464. //-----------------------------------------------------------------------------
  465. // Recursively render the Dag hierarchy
  466. //-----------------------------------------------------------------------------
  467. void CDmeDag::DrawUsingEngineCoordinates( bool bEnable )
  468. {
  469. s_bDrawUsingEngineCoordinates = bEnable;
  470. }
  471. //-----------------------------------------------------------------------------
  472. // Specify if the model is a Z Up Model
  473. //-----------------------------------------------------------------------------
  474. void CDmeDag::DrawZUp( bool bZUp )
  475. {
  476. s_bDrawZUp = bZUp;
  477. }
  478. //-----------------------------------------------------------------------------
  479. // Recursively render the Dag hierarchy
  480. //-----------------------------------------------------------------------------
  481. void CDmeDag::Draw( CDmeDrawSettings *pDrawSettings )
  482. {
  483. if ( !m_Visible )
  484. return;
  485. PushDagTransform();
  486. CDmeShape *pShape = GetShape();
  487. if ( pShape )
  488. {
  489. matrix3x4_t shapeToWorld;
  490. GetShapeToWorldTransform( shapeToWorld );
  491. pShape->Draw( shapeToWorld, pDrawSettings );
  492. }
  493. uint cn = m_Children.Count();
  494. for ( uint ci = 0; ci < cn; ++ci )
  495. {
  496. m_Children[ ci ]->Draw( pDrawSettings );
  497. }
  498. PopDagTransform();
  499. }
  500. //-----------------------------------------------------------------------------
  501. //
  502. //-----------------------------------------------------------------------------
  503. void CDmeDag::GetBoundingSphere( Vector &c0, float &r0, const matrix3x4_t &pMat ) const
  504. {
  505. matrix3x4_t lMat;
  506. m_Transform.GetElement()->GetTransform( lMat );
  507. matrix3x4_t wMat;
  508. ConcatTransforms( pMat, lMat, wMat );
  509. c0.Zero();
  510. r0 = 0.0f;
  511. Vector vTemp;
  512. const CDmeShape *pShape = m_Shape.GetElement();
  513. if ( pShape )
  514. {
  515. pShape->GetBoundingSphere( c0, r0 );
  516. VectorTransform( c0, lMat, vTemp );
  517. c0 = vTemp;
  518. }
  519. // No scale in Dme! :)
  520. VectorTransform( c0, pMat, vTemp );
  521. c0 = vTemp;
  522. const int nChildren = m_Children.Count();
  523. if ( nChildren > 0 )
  524. {
  525. Vector c1; // Child center
  526. float r1; // Child radius
  527. Vector v01; // c1 - c0
  528. float l01; // |v01|
  529. for ( int i = 0; i < nChildren; ++i )
  530. {
  531. m_Children[ i ]->GetBoundingSphere( c1, r1, wMat );
  532. if ( r0 == 0.0f )
  533. {
  534. c0 = c1;
  535. r0 = r1;
  536. continue;
  537. }
  538. v01 = c1 - c0;
  539. l01 = v01.NormalizeInPlace();
  540. if ( r0 < l01 + r1 )
  541. {
  542. // Current sphere doesn't contain both spheres
  543. if ( r1 < l01 + r0 )
  544. {
  545. // Child sphere doesn't contain both spheres
  546. c0 = c0 + 0.5f * ( r1 + l01 - r0 ) * v01;
  547. r0 = 0.5f * ( r0 + l01 + r1 );
  548. }
  549. else
  550. {
  551. // Child sphere contains both spheres
  552. c0 = c1;
  553. r0 = r1;
  554. }
  555. }
  556. }
  557. }
  558. }
  559. //-----------------------------------------------------------------------------
  560. // Purpose: Find the channels targeting the transform of the object either
  561. // directly or through a constraint
  562. //-----------------------------------------------------------------------------
  563. void CDmeDag::FindTransformChannels( CUtlVector< CDmeChannel * > &channelList ) const
  564. {
  565. // Find and channels targeting the transform of the dag node
  566. FindAncestorsReferencingElement( GetTransform(), channelList );
  567. // Find the slave instances targeting the specified node
  568. CUtlVector< CDmeConstraintSlave* > slaveList;
  569. FindAncestorsReferencingElement( this, slaveList );
  570. int nSlaves = slaveList.Count();
  571. for ( int iSlave = 0; iSlave < nSlaves; ++iSlave )
  572. {
  573. CDmeConstraintSlave *pSlave = slaveList[ iSlave ];
  574. if ( pSlave )
  575. {
  576. FindAncestorsReferencingElement( pSlave, channelList );
  577. }
  578. }
  579. }
  580. //-----------------------------------------------------------------------------
  581. // Purpose: Find the transform controls driving the dag node
  582. //-----------------------------------------------------------------------------
  583. CDmeTransformControl *CDmeDag::FindTransformControl() const
  584. {
  585. CUtlVector< CDmeChannel* > channelList( 0, 4 );
  586. FindTransformChannels( channelList );
  587. int nChannels = channelList.Count();
  588. for ( int iChannel = 0; iChannel < nChannels; ++iChannel )
  589. {
  590. CDmeChannel *pChannel = channelList[ iChannel ];
  591. if ( pChannel )
  592. {
  593. CDmeTransformControl *pTransformControl = CastElement< CDmeTransformControl >( pChannel->GetFromElement() );
  594. if ( pTransformControl )
  595. return pTransformControl;
  596. }
  597. }
  598. return NULL;
  599. }
  600. //-----------------------------------------------------------------------------
  601. // Purpose: Find the channels and operators which must be evaluated in order
  602. // to determine the state of the dag node. Note that this function returns only
  603. // the operators targeting this dag node, it does not include those targeting
  604. // the parent of this node, but it does return all operators that this node
  605. // is dependent on even if they are are connected to this node through other
  606. // operators.
  607. //-----------------------------------------------------------------------------
  608. void CDmeDag::FindLocalOperators( CUtlVector< CDmeOperator* > &operatorList ) const
  609. {
  610. // Find any operators directly targeting the transform of the dag node
  611. GatherOperatorsForElement( GetTransform(), operatorList );
  612. // Find the slave instances targeting the specified node
  613. for ( DmAttributeReferenceIterator_t it = g_pDataModel->FirstAttributeReferencingElement( GetHandle() );
  614. it != DMATTRIBUTE_REFERENCE_ITERATOR_INVALID;
  615. it = g_pDataModel->NextAttributeReferencingElement( it ) )
  616. {
  617. CDmAttribute *pAttr = g_pDataModel->GetAttribute( it );
  618. CDmElement *pElement = pAttr->GetOwner();
  619. if ( !g_pDataModel->GetElement( pElement->GetHandle() ) )
  620. continue;
  621. CDmeConstraintSlave *pConstraintSlave = CastElement< CDmeConstraintSlave >( pElement );
  622. if ( pConstraintSlave )
  623. {
  624. CDmeRigBaseConstraintOperator *pConstraint = pConstraintSlave->GetConstraint();
  625. if ( pConstraint )
  626. {
  627. if ( operatorList.Find( pConstraint ) == operatorList.InvalidIndex() )
  628. {
  629. pConstraint->GatherInputOperators( operatorList );
  630. operatorList.AddToTail( pConstraint );
  631. }
  632. }
  633. }
  634. }
  635. }
  636. //-----------------------------------------------------------------------------
  637. // Purpose: Find all of the operators on which dag node is dependent, this
  638. // recursively finds operators for the parents of the dag. The list of operators
  639. // that is returned represents all of the operators which must be evaluated in
  640. // order to determine the current state of the node. The list is returned in
  641. // the order that the operators should be run.
  642. //-----------------------------------------------------------------------------
  643. void CDmeDag::FindRelevantOperators( CUtlVector< CDmeOperator * > &operatorList ) const
  644. {
  645. const CDmeDag *pOverrideParent = GetOverrideParent();
  646. if ( pOverrideParent )
  647. {
  648. pOverrideParent->FindRelevantOperators( operatorList );
  649. }
  650. CDmeDag *pParent = GetParent();
  651. if ( pParent )
  652. {
  653. pParent->FindRelevantOperators( operatorList );
  654. }
  655. FindLocalOperators( operatorList );
  656. }
  657. //-----------------------------------------------------------------------------
  658. // Purpose: Find all of the operators on which the dag node is dependent,
  659. // splitting the channels into a separate list. This function merely calls
  660. // the FindRelvantOperators() which returns a single list of operators and
  661. // then creates a list of channels and a list of other operators. It is
  662. // preferable to just use the version which returns a single list of operators.
  663. //-----------------------------------------------------------------------------
  664. void CDmeDag::FindRelevantOperators( CUtlVector< CDmeChannel * > &channelList, CUtlVector< CDmeOperator * > &operatorList ) const
  665. {
  666. CUtlVector< CDmeOperator* > allOperatorsList( 0, 128 );
  667. FindRelevantOperators( allOperatorsList );
  668. int nTotalOperators = allOperatorsList.Count();
  669. channelList.EnsureCapacity( channelList.Count() + nTotalOperators );
  670. operatorList.EnsureCapacity( operatorList.Count() + nTotalOperators );
  671. for ( int iOperator = 0; iOperator < nTotalOperators; ++iOperator )
  672. {
  673. CDmeOperator *pOperator = allOperatorsList[ iOperator ];
  674. if ( pOperator == NULL )
  675. continue;
  676. CDmeChannel *pChannel = CastElement< CDmeChannel >( pOperator );
  677. if ( pChannel )
  678. {
  679. channelList.AddToTail( pChannel );
  680. }
  681. else
  682. {
  683. operatorList.AddToTail( pOperator );
  684. }
  685. }
  686. }
  687. void CDmeDag::GetBoundingBox( Vector &min, Vector &max, const matrix3x4_t &pMat ) const
  688. {
  689. matrix3x4_t lMat;
  690. m_Transform.GetElement()->GetTransform( lMat );
  691. matrix3x4_t wMat;
  692. ConcatTransforms( pMat, lMat, wMat );
  693. min.Zero();
  694. max.Zero();
  695. bool bHasBox = false;
  696. const CDmeShape *pShape = m_Shape.GetElement();
  697. if ( pShape )
  698. {
  699. Vector cmin, cmax;
  700. pShape->GetBoundingBox( cmin, cmax );
  701. if ( cmin != cmax )
  702. {
  703. Vector bmin( cmin ), bmax( cmax );
  704. VectorTransform( cmin, pMat, bmin );
  705. VectorTransform( cmax, pMat, bmax );
  706. for ( int kx = 0; kx < 2; ++ kx )
  707. for ( int ky = 0; ky < 2; ++ ky )
  708. for ( int kz = 0; kz < 2; ++ kz )
  709. {
  710. Vector tp(
  711. kx ? cmax.x : cmin.x,
  712. ky ? cmax.y : cmin.y,
  713. kz ? cmax.z : cmin.z );
  714. Vector vTemp;
  715. VectorTransform( tp, pMat, vTemp );
  716. bmin = bmin.Min( vTemp );
  717. bmax = bmax.Max( vTemp );
  718. }
  719. if ( !bHasBox )
  720. {
  721. min = bmin;
  722. max = bmax;
  723. }
  724. min = min.Min( bmin );
  725. max = max.Max( bmax );
  726. bHasBox = true;
  727. }
  728. }
  729. for ( int i = 0, nChildren = m_Children.Count(); i < nChildren; ++ i )
  730. {
  731. CDmeDag *pChild = m_Children[i];
  732. Vector cmin, cmax;
  733. pChild->GetBoundingBox( cmin, cmax, wMat );
  734. if ( cmin != cmax )
  735. {
  736. if ( !bHasBox )
  737. {
  738. min = cmin;
  739. max = cmax;
  740. }
  741. min = min.Min( cmin );
  742. max = max.Max( cmax );
  743. bHasBox = true;
  744. }
  745. }
  746. }
  747. Quaternion QuaternionTransform( const Quaternion &quat, const matrix3x4_t &mat )
  748. {
  749. matrix3x4_t quatmat;
  750. QuaternionMatrix( quat, quatmat );
  751. matrix3x4_t newmat;
  752. ConcatTransforms( mat, quatmat, newmat );
  753. Quaternion result;
  754. MatrixQuaternion( newmat, result );
  755. return result;
  756. }
  757. void CDmeDag::BakeStaticTransforms( bool bRecurse /*= true*/ )
  758. {
  759. // determine whether to bake this transform into its children
  760. if ( FindAncestorReferencingElement< CDmeChannel >( this ) || FindAncestorReferencingElement< CDmeConstraintSlave >( this ) )
  761. return; // don't bake, since it's transform isn't static
  762. if ( ( GetType() != CDmeDag::GetStaticTypeSymbol() ) && ( GetType() != CDmeRig::GetStaticTypeSymbol() ) )
  763. return; // don't bake CDmeGameModel's root transform into the child bones, CDmeParticleSystem's root transform into the control points, etc.
  764. int nChildrenFound = 0;
  765. int nChildren = GetChildCount();
  766. for ( int i = 0; i < nChildren; ++i )
  767. {
  768. CDmeDag *pChild = GetChild( i );
  769. if ( !pChild )
  770. continue;
  771. if ( FindAncestorReferencingElement< CDmeConstraintSlave >( pChild ) )
  772. return; // don't bake, since child's transform isn't static
  773. // TODO: it probably wouldn't be that hard to make this work with dags with overriden parents
  774. // the simplest path may be to unparent (and let the unparent do the conversion keeping everything in place), bake, and reparent
  775. // there are faster and less obtrusive ways, but we don't need this functionality now, so I'm not solving it yet
  776. if ( pChild->HasOverrideParent() )
  777. return; // don't bake
  778. ++nChildrenFound;
  779. }
  780. if ( nChildrenFound == 0 )
  781. return;
  782. // now, actually bake this transform into its children
  783. matrix3x4_t parentMat;
  784. GetLocalMatrix( parentMat );
  785. matrix3x4_t identityMat;
  786. SetIdentityMatrix( identityMat );
  787. SetLocalMatrix( identityMat );
  788. static CUtlSymbolLarge symToElement = g_pDataModel->GetSymbol( "toElement" );
  789. for ( int i = 0; i < nChildren; ++i )
  790. {
  791. CDmeDag *pChild = GetChild( i );
  792. if ( !pChild )
  793. continue;
  794. CDmeTransform *pTransform = pChild->GetTransform();
  795. if ( !pTransform )
  796. continue;
  797. CDmeVector3Log *pPosLog = NULL;
  798. CDmeQuaternionLog *pRotLog = NULL;
  799. CDmeTransformControl *pTransformControl = NULL;
  800. for ( CAttributeReferenceIterator it( pTransform ); it; ++it )
  801. {
  802. if ( CDmeChannel *pChannel = it.FilterReference< CDmeChannel >( symToElement, true, TD_ALL ) )
  803. {
  804. CDmAttribute *pToAttr = pChannel->GetToAttribute();
  805. if ( pToAttr == pTransform->GetPositionAttribute() )
  806. {
  807. pPosLog = CastElement< CDmeVector3Log >( pChannel->GetLog() );
  808. }
  809. else if ( pToAttr == pTransform->GetOrientationAttribute() )
  810. {
  811. pRotLog = CastElement< CDmeQuaternionLog >( pChannel->GetLog() );
  812. }
  813. if ( !pTransformControl )
  814. {
  815. pTransformControl = CastElement< CDmeTransformControl >( pChannel->GetFromElement() );
  816. }
  817. }
  818. }
  819. if ( pPosLog )
  820. {
  821. int bestLayer = pPosLog->GetTopmostLayer();
  822. CDmeVector3LogLayer *pPosLogLayer = bestLayer >= 0 ? pPosLog->GetLayer( bestLayer ) : NULL;
  823. if ( pPosLogLayer )
  824. {
  825. int nPosKeys = pPosLogLayer->GetKeyCount();
  826. for ( int i = 0; i < nPosKeys; ++i )
  827. {
  828. pPosLogLayer->SetKeyValue( i, VectorTransform( pPosLogLayer->GetKeyValue( i ), parentMat ) );
  829. }
  830. }
  831. pPosLog->SetDefaultValue( VectorTransform( pPosLog->GetDefaultValue(), parentMat ) ); // do we really want to transform the default???
  832. }
  833. if ( pRotLog )
  834. {
  835. int bestLayer = pRotLog->GetTopmostLayer();
  836. CDmeQuaternionLogLayer *pRotLogLayer = bestLayer >= 0 ? pRotLog->GetLayer( bestLayer ) : NULL;
  837. if ( pRotLogLayer )
  838. {
  839. int nRotKeys = pRotLogLayer->GetKeyCount();
  840. for ( int i = 0; i < nRotKeys; ++i )
  841. {
  842. pRotLogLayer->SetKeyValue( i, QuaternionTransform( pRotLogLayer->GetKeyValue( i ), parentMat ) );
  843. }
  844. }
  845. pRotLog->SetDefaultValue( QuaternionTransform( pRotLog->GetDefaultValue(), parentMat ) ); // do we really want to transform the default???
  846. }
  847. if ( pTransformControl )
  848. {
  849. // bake into transform control
  850. pTransformControl->SetPosition ( VectorTransform ( pTransformControl->GetPosition (), parentMat ) );
  851. pTransformControl->SetOrientation( QuaternionTransform( pTransformControl->GetOrientation(), parentMat ) );
  852. // we explicitly do NOT set the transform control's defaults, since the root default should still be the origin
  853. }
  854. // bake into transform
  855. pTransform->SetPosition ( VectorTransform ( pTransform->GetPosition (), parentMat ) );
  856. pTransform->SetOrientation( QuaternionTransform( pTransform->GetOrientation(), parentMat ) );
  857. if ( bRecurse )
  858. {
  859. pChild->BakeStaticTransforms( bRecurse );
  860. }
  861. }
  862. }
  863. //-----------------------------------------------------------------------------
  864. // Purpose: Attach the dag node to the specified parent node. If the dag node
  865. // is currently a child of another node it will be removed the from that node.
  866. // The local space transform of the dag node will be modified so that it will
  867. // have the same world space transform after being attached as before it was
  868. // attached. Passing in NULL for the parent effectively moves the dag node into
  869. // world space without any parents.
  870. //
  871. //-----------------------------------------------------------------------------
  872. void CDmeDag::OnAttachToDmeDag( CDmeDag *pParentDag, bool bFixupLogs /*= true*/ )
  873. {
  874. if ( GetParent() == pParentDag )
  875. return;
  876. CDmeTransform *pTransform = GetTransform();
  877. if ( !pTransform )
  878. return;
  879. CUndoScopeGuard guard( NOTIFY_SETDIRTYFLAG, "CDmeDag::OnAttachToDmeDag" );
  880. CDmeFilmClip *pFilmClip = NULL;
  881. if ( pParentDag != NULL )
  882. {
  883. pFilmClip = FindFilmClipContainingDag( pParentDag );
  884. }
  885. else
  886. {
  887. pFilmClip = FindFilmClipContainingDag( this );
  888. }
  889. matrix3x4_t cameraMat, parentMat, invParentMat, newCameraMat;
  890. GetAbsTransform( cameraMat );
  891. if ( pParentDag && pFilmClip )
  892. {
  893. pParentDag->GetAbsTransform( parentMat );
  894. }
  895. else
  896. {
  897. SetIdentityMatrix( parentMat );
  898. }
  899. MatrixInvert( parentMat, invParentMat );
  900. ConcatTransforms( invParentMat, cameraMat, newCameraMat );
  901. pTransform->SetTransform( newCameraMat );
  902. matrix3x4_t cameraParentMat, oldToNewCameraMat;
  903. GetParentWorldMatrix( cameraParentMat );
  904. ConcatTransforms( invParentMat, cameraParentMat, oldToNewCameraMat );
  905. CUtlVector< CDmeDag* > parents;
  906. FindAncestorsReferencingElement( this, parents );
  907. int nParents = parents.Count();
  908. for ( int i = 0; i < nParents; ++i )
  909. {
  910. parents[ i ]->RemoveChild( this );
  911. }
  912. if ( ( bFixupLogs ) && ( pFilmClip != NULL ) )
  913. {
  914. CDmeTransform *pTransform = GetTransform();
  915. CDmeChannel *pPosChannel = FindChannelTargetingElement( pFilmClip, pTransform, TRANSFORM_POSITION, NULL );
  916. if ( pPosChannel )
  917. {
  918. CDmeLog *pLog = pPosChannel->GetLog();
  919. if ( pLog )
  920. {
  921. CDmeLogLayer *pLayer = pLog->GetLayer( pLog->GetTopmostLayer() );
  922. CDmeTypedLogLayer< Vector > *pVectorLayer = CastElement< CDmeTypedLogLayer< Vector > >( pLayer );
  923. if ( pVectorLayer )
  924. {
  925. int nKeys = pVectorLayer->GetKeyCount();
  926. for ( int i = 0; i < nKeys; ++i )
  927. {
  928. Vector newvec, oldvec = pVectorLayer->GetKeyValue( i );
  929. VectorTransform( oldvec, oldToNewCameraMat, newvec );
  930. pVectorLayer->SetKeyValue( i, newvec );
  931. }
  932. }
  933. }
  934. }
  935. CDmeChannel *pRotChannel = FindChannelTargetingElement( pFilmClip, pTransform, TRANSFORM_ORIENTATION, NULL );
  936. if ( pRotChannel )
  937. {
  938. CDmeLog *pLog = pRotChannel->GetLog();
  939. if ( pLog )
  940. {
  941. CDmeLogLayer *pLayer = pLog->GetLayer( pLog->GetTopmostLayer() );
  942. CDmeTypedLogLayer< Quaternion > *pQuatLayer = CastElement< CDmeTypedLogLayer< Quaternion > >( pLayer );
  943. if ( pQuatLayer )
  944. {
  945. int nKeys = pQuatLayer->GetKeyCount();
  946. for ( int i = 0; i < nKeys; ++i )
  947. {
  948. matrix3x4_t oldmat, newmat;
  949. QuaternionMatrix( pQuatLayer->GetKeyValue( i ), oldmat );
  950. ConcatTransforms( oldToNewCameraMat, oldmat, newmat );
  951. Quaternion quat;
  952. MatrixQuaternion( newmat, quat );
  953. pQuatLayer->SetKeyValue( i, quat );
  954. }
  955. }
  956. }
  957. }
  958. }
  959. if ( pParentDag )
  960. {
  961. pParentDag->AddChild( this );
  962. }
  963. }
  964. //-----------------------------------------------------------------------------
  965. // Purpose: Modify the logs controlling the transform of this dag node so that
  966. // the transform maintains the same relative position and orientation to the
  967. // target dag node for the duration of the provided time period.
  968. // Input : pTargetDag - Pointer to the dag node whose transform the transform
  969. // of this dag node it to be bound to.
  970. // Input : timeSelection - Time selection for which the modifications are to
  971. // be applied, including falloffs.
  972. // Input : pMovie - Pointer to the movie to which the dag belongs
  973. // Input : offset - Offset relative to the dag where the offset is going to be
  974. // placed if the reset position flag is true.
  975. // Input : bPosition - flag indicating that the position of the dag node
  976. // should be modified.
  977. // Input : bOrientation - flag indicating that the orientation of the dag
  978. // node should be modified.
  979. // Input : bResetPosition - flag indicating that the position of the target
  980. // dag node should be repositioned.
  981. //-----------------------------------------------------------------------------
  982. void CDmeDag::BindTransformToDmeDag( const CDmeDag *pTargetDag, const DmeLog_TimeSelection_t &timeSelection, const CDmeClip* pMovie, const Vector& offset, bool bPosition, bool bOrientation, bool bMaintainOffset )
  983. {
  984. // Must specify a target dag and it must not be this dag.
  985. if ( ( pTargetDag == NULL ) || ( pTargetDag == this ) )
  986. {
  987. Assert( pTargetDag );
  988. return;
  989. }
  990. // Find the film clip for this dag and the target dag node and make sure they are the same
  991. CDmeFilmClip *pFilmClip = FindFilmClipContainingDag( this );
  992. if ( pFilmClip == NULL )
  993. {
  994. pFilmClip = FindReferringElement< CDmeFilmClip >( this, "camera" );
  995. }
  996. // Find the channels which must be updated in order to evaluate
  997. // transforms of both this dag node and the target dag node.
  998. CUtlVector< CDmeChannel* > localChannelList, targetChannelList;
  999. CUtlVector< CDmeOperator* > localOperatorList, targetOperatorList;
  1000. FindRelevantOperators( localChannelList, localOperatorList );
  1001. pTargetDag->FindRelevantOperators( targetChannelList, targetOperatorList );
  1002. // Build the clip stacks for the channel lists.
  1003. CUtlVector< DmeClipStack_t > localClipStackList, targetClipStackList;
  1004. CUtlVector< DmeTime_t > localChannelTimeList, targetChannelTimeList;
  1005. BuildClipStackList( localChannelList, localClipStackList, localChannelTimeList, pMovie, pFilmClip );
  1006. BuildClipStackList( targetChannelList, targetClipStackList, targetChannelTimeList, pMovie, pFilmClip );
  1007. // Construct the offset transform matrix which will be used to maintain the relative
  1008. // offset and orientation of the current dag to the target dag at the current time
  1009. CDmeTransform *pTransform = GetTransform();
  1010. matrix3x4_t targetMat;
  1011. matrix3x4_t invTargetMat;
  1012. pTargetDag->GetAbsTransform( targetMat );
  1013. MatrixInvert( targetMat, invTargetMat );
  1014. matrix3x4_t orginalTransform;
  1015. if ( bMaintainOffset )
  1016. {
  1017. GetAbsTransform( orginalTransform );
  1018. }
  1019. else
  1020. {
  1021. Vector basePosition;
  1022. Vector offsetPosition;
  1023. MatrixPosition( targetMat, basePosition );
  1024. offsetPosition = basePosition + offset;
  1025. orginalTransform = targetMat;
  1026. PositionMatrix( offsetPosition, orginalTransform );
  1027. }
  1028. matrix3x4_t offsetTransform;
  1029. ConcatTransforms( invTargetMat, orginalTransform, offsetTransform );
  1030. // Find the position and orientation channels associated with the transform
  1031. CDmeChannel *pLocalPosChannel = bPosition ? FindChannelTargetingElement( pFilmClip, pTransform, "position", NULL ) : NULL;
  1032. CDmeChannel *pLocalRotChannel = bOrientation ? FindChannelTargetingElement( pFilmClip, pTransform, "orientation", NULL ) : NULL;
  1033. if ( pLocalPosChannel || pLocalRotChannel )
  1034. {
  1035. // Start a new undo group for the operation
  1036. g_pDataModel->StartUndo( "Attach Transform", "Attach Transform" );
  1037. CDmeLog *pPosLog = ( pLocalPosChannel != NULL ) ? pLocalPosChannel->GetLog() : NULL;
  1038. CDmeLog *pRotLog = ( pLocalRotChannel != NULL ) ? pLocalRotChannel->GetLog() : NULL;
  1039. CDmeChannelsClip *pPosChannelsClip = ( pLocalPosChannel != NULL ) ? FindAncestorReferencingElement< CDmeChannelsClip >( pLocalPosChannel ) : NULL;
  1040. CDmeChannelsClip *pRotChannelsClip = ( pLocalRotChannel != NULL ) ? FindAncestorReferencingElement< CDmeChannelsClip >( pLocalRotChannel ) : NULL;
  1041. CDmeChannelsClip *pChannelsClip = ( pPosChannelsClip != NULL ) ? pPosChannelsClip : pRotChannelsClip;
  1042. Assert( pPosChannelsClip == pRotChannelsClip || pPosChannelsClip == NULL || pRotChannelsClip == NULL );
  1043. Assert( pPosLog != pRotLog );
  1044. Assert( pChannelsClip );
  1045. if ( pChannelsClip )
  1046. {
  1047. // Construct the clip stack from the movie down to the channels clip containing the channel
  1048. DmeClipStack_t clipStack;
  1049. if ( pPosChannelsClip )
  1050. {
  1051. pPosChannelsClip->BuildClipStack( &clipStack, pMovie, pFilmClip );
  1052. }
  1053. else
  1054. {
  1055. pRotChannelsClip->BuildClipStack( &clipStack, pMovie, pFilmClip );
  1056. }
  1057. // Add a new layer to the active logs, the new layer will contain the values
  1058. // required to position and orient the transform relative to the target.
  1059. CDmeLogLayer *pPosLayer = ( pPosLog != NULL ) ? pPosLog->AddNewLayer() : NULL;
  1060. CDmeLogLayer *pRotLayer = ( pRotLog != NULL ) ? pRotLog->AddNewLayer() : NULL;
  1061. CDmeTypedLogLayer< Vector > *pVectorLayer = CastElement< CDmeTypedLogLayer< Vector > >( pPosLayer );
  1062. CDmeTypedLogLayer< Quaternion > *pQuatLayer = CastElement< CDmeTypedLogLayer< Quaternion > >( pRotLayer );
  1063. // Iterate through the time selection based on the resample interval
  1064. // and generate keys in the active logs at each time time step.
  1065. DmeTime_t time = timeSelection.m_nTimes[ 0 ];
  1066. DmeTime_t endTime = timeSelection.m_nTimes[ 3 ];
  1067. bool done = false;
  1068. // Disable the undo, the only thing that is actually
  1069. // needed is the add new layer and the flatten layers.
  1070. CDisableUndoScopeGuard undosg;
  1071. while ( !done )
  1072. {
  1073. // Make sure the time does not pass the end of the time selection and set the
  1074. // done flag if it has. By setting the flag instead of breaking immediately we
  1075. // are guaranteed a sample will be made at the very end of the time selection.
  1076. if ( time >= endTime )
  1077. {
  1078. time = endTime;
  1079. done = true;
  1080. }
  1081. // Evaluate all of the channels relevant to the target dag and the local dag at the
  1082. // specified time so that the transform evaluations will correspond to the correct time.
  1083. PlayChannelsAtTime( time, targetChannelList, targetOperatorList, targetClipStackList );
  1084. PlayChannelsAtTime( time, localChannelList, localOperatorList, localClipStackList );
  1085. // Get the world space transform of the target
  1086. matrix3x4_t targetTransform;
  1087. pTargetDag->GetAbsTransform( targetTransform );
  1088. // Apply the offset transform to the target transform and make the
  1089. // result the world space transform of the current dag node.
  1090. matrix3x4_t finalTransform;
  1091. ConcatTransforms( targetTransform, offsetTransform, finalTransform );
  1092. SetAbsTransform( finalTransform );
  1093. // Calculate the time relative to the log
  1094. DmeTime_t logTime = clipStack.ToChildMediaTime( time );
  1095. // Add the position of the transform to the position log of the dag node's transform
  1096. if ( pVectorLayer )
  1097. {
  1098. Vector position = pTransform->GetPosition();
  1099. pVectorLayer->SetKey( logTime, position, SEGMENT_INTERPOLATE, CURVE_DEFAULT, false );
  1100. }
  1101. // Add the orientation of the transform to the orientation log of the dag node's transform
  1102. if ( pQuatLayer )
  1103. {
  1104. Quaternion rotation = pTransform->GetOrientation();
  1105. pQuatLayer->SetKey( logTime, rotation, SEGMENT_INTERPOLATE, CURVE_DEFAULT, false );
  1106. }
  1107. // Move the evaluation time up by the resample interval
  1108. time += timeSelection.m_nResampleInterval;
  1109. }
  1110. // Convert the time selection into the local time space of the log.
  1111. DmeLog_TimeSelection_t logTimeSelection = timeSelection;
  1112. clipStack.ToChildMediaTime( logTimeSelection.m_nTimes );
  1113. // Blend the top level log layers contain the new position and orientation with the base log
  1114. // layer according to the time selection parameters and then flatten the log layers.
  1115. if ( pPosLog )
  1116. {
  1117. pPosLog->BlendLayersUsingTimeSelection( logTimeSelection );
  1118. CEnableUndoScopeGuard undosg;
  1119. pPosLog->FlattenLayers( timeSelection.m_flThreshold, 0 );
  1120. }
  1121. if ( pRotLog )
  1122. {
  1123. pRotLog->BlendLayersUsingTimeSelection( logTimeSelection );
  1124. CEnableUndoScopeGuard undosg;
  1125. pRotLog->FlattenLayers( timeSelection.m_flThreshold, 0 );
  1126. }
  1127. // Restore all of the channels to the original times so that this operation does not have side effects.
  1128. PlayChannelsAtLocalTimes( targetChannelTimeList, targetChannelList, targetOperatorList );
  1129. PlayChannelsAtLocalTimes( localChannelTimeList, localChannelList, localOperatorList );
  1130. }
  1131. g_pDataModel->FinishUndo();
  1132. }
  1133. }
  1134. //-----------------------------------------------------------------------------
  1135. // Compute the absolute and the local transform of the dag node at the
  1136. // specified global time.
  1137. //-----------------------------------------------------------------------------
  1138. void CDmeDag::ComputeTransformAtTime( DmeTime_t globalTime, const CDmeClip* pMovie, matrix3x4_t &matAbsTransform, matrix3x4_t &localTransform )
  1139. {
  1140. // This operation should have no side effects and
  1141. // no entries should be added to the undo stack.
  1142. CDisableUndoScopeGuard disableUndoSG;
  1143. // Find the film clip containing this dag
  1144. CDmeFilmClip *pFilmClip = FindFilmClipContainingDag( this );
  1145. if ( pFilmClip == NULL )
  1146. {
  1147. pFilmClip = FindReferringElement< CDmeFilmClip >( this, "camera" );
  1148. }
  1149. // Get the transform associated with the dag
  1150. CDmeTransform *pTransform = GetTransform();
  1151. if ( ( pMovie == NULL ) || ( pFilmClip == NULL ) || ( pTransform == NULL ) )
  1152. return;
  1153. // Build a list of channels and other operators which must be
  1154. // evaluated in order to evaluate the transform of this dag node.
  1155. CUtlVector< CDmeChannel* > channelList;
  1156. CUtlVector< CDmeOperator* > operatorList;
  1157. CUtlVector< DmeClipStack_t > clipStackList;
  1158. CUtlVector< DmeTime_t > channelTimeList;
  1159. FindRelevantOperators( channelList, operatorList );
  1160. BuildClipStackList( channelList, clipStackList, channelTimeList, pMovie, pFilmClip );
  1161. // Evaluate the channels and operators relevant to the dag at the specified time
  1162. PlayChannelsAtTime( globalTime, channelList, operatorList, clipStackList );
  1163. // Get the absolute world transform and the local transform
  1164. GetAbsTransform( matAbsTransform );
  1165. pTransform->GetTransform( localTransform );
  1166. // Restore all of the channels to the original times so that this operation does not have side effects.
  1167. PlayChannelsAtLocalTimes( channelTimeList, channelList, operatorList );
  1168. }
  1169. //-----------------------------------------------------------------------------
  1170. // Move the the dag node to the position of the specified node at the current
  1171. // time, for the rest of the time selection apply the same world space offset
  1172. // that was required to move the dag to the target position at the current time.
  1173. //-----------------------------------------------------------------------------
  1174. void CDmeDag::MoveToTarget( const CDmeDag *pTargetDag, const DmeLog_TimeSelection_t &timeSelection, const CDmeClip *pMovie )
  1175. {
  1176. // Must specify a target dag and it must not be this dag.
  1177. if ( ( pTargetDag == NULL ) || ( pTargetDag == this ) )
  1178. {
  1179. Assert( pTargetDag );
  1180. return;
  1181. }
  1182. // Find the film clip for the dag
  1183. CDmeFilmClip *pFilmClip = FindFilmClipContainingDag( this );
  1184. if ( pFilmClip == NULL )
  1185. {
  1186. pFilmClip = FindReferringElement< CDmeFilmClip >( this, "camera" );
  1187. }
  1188. // Find the channels which must be updated in order to evaluate transforms of both this dag node.
  1189. CUtlVector< CDmeChannel* > channelList;
  1190. CUtlVector< CDmeOperator* > operatorList;
  1191. FindRelevantOperators( channelList,operatorList );
  1192. // Build the clip stacks for the channel lists.
  1193. CUtlVector< DmeClipStack_t > clipStackList;
  1194. CUtlVector< DmeTime_t > channelTimeList;
  1195. BuildClipStackList( channelList, clipStackList, channelTimeList, pMovie, pFilmClip );
  1196. // Compute the world space offset between the dag node and the target
  1197. Vector vWorldPos, vTargetPos;
  1198. GetAbsPosition( vWorldPos );
  1199. pTargetDag->GetAbsPosition( vTargetPos );
  1200. Vector vOffset = vTargetPos - vWorldPos;
  1201. // Find the position channel of driving the dag node which will be updated.
  1202. CDmeTransform *pTransform = GetTransform();
  1203. CDmeChannel *pLocalPosChannel = FindChannelTargetingElement( pFilmClip, pTransform, "position", NULL );
  1204. if ( pLocalPosChannel != NULL )
  1205. {
  1206. // Start a new undo group for the operation
  1207. g_pDataModel->StartUndo( "Move dag to target", "Move dag to target" );
  1208. CDmeLog *pPosLog = ( pLocalPosChannel != NULL ) ? pLocalPosChannel->GetLog() : NULL;
  1209. CDmeChannelsClip *pChannelsClip = FindAncestorReferencingElement< CDmeChannelsClip >( pLocalPosChannel );
  1210. Assert( pChannelsClip );
  1211. if ( pChannelsClip && pPosLog )
  1212. {
  1213. // Construct the clip stack from the movie down to the channels clip containing the channel
  1214. DmeClipStack_t clipStack;
  1215. pChannelsClip->BuildClipStack( &clipStack, pMovie, pFilmClip );
  1216. // Add a new layer to the active logs, the new layer will contain the values
  1217. // required to position and orient the transform relative to the target.
  1218. CDmeLogLayer *pPosLayer = pPosLog->AddNewLayer();
  1219. CDmeTypedLogLayer< Vector > *pVectorLayer = CastElement< CDmeTypedLogLayer< Vector > >( pPosLayer );
  1220. // Iterate through the time selection based on the resample interval
  1221. // and generate keys in the active logs at each time time step.
  1222. DmeTime_t time = timeSelection.m_nTimes[ 0 ];
  1223. DmeTime_t endTime = timeSelection.m_nTimes[ 3 ];
  1224. bool done = false;
  1225. // Disable the undo, the only thing that is actually
  1226. // needed is the add new layer and the flatten layers.
  1227. CDisableUndoScopeGuard undosg;
  1228. int nAproxNumTimes = ( ( endTime - time ) / timeSelection.m_nResampleInterval ) + 2;
  1229. CUtlVector< Vector > samplePositions( 0, nAproxNumTimes );
  1230. CUtlVector< DmeTime_t > sampleTimes( 0, nAproxNumTimes );
  1231. while ( !done )
  1232. {
  1233. // Make sure the time does not pass the end of the time selection and set the
  1234. // done flag if it has. By setting the flag instead of breaking immediately we
  1235. // are guaranteed a sample will be made at the very end of the time selection.
  1236. if ( time >= endTime )
  1237. {
  1238. time = endTime;
  1239. done = true;
  1240. }
  1241. // Evaluate all of the channels relevant to the target dag and the local dag at the
  1242. // specified time so that the transform evaluations will correspond to the correct time.
  1243. PlayChannelsAtTime( time, channelList, operatorList, clipStackList );
  1244. // Get the current world space position of the node
  1245. Vector vOriginalWorldPos;
  1246. GetAbsPosition( vOriginalWorldPos );
  1247. Vector vNewWorldPos = vOriginalWorldPos + vOffset;
  1248. SetAbsPosition( vNewWorldPos );
  1249. Vector vLocalPosition = pTransform->GetPosition();
  1250. // Store the sample time and the local position
  1251. samplePositions.AddToTail( vLocalPosition );
  1252. sampleTimes.AddToTail( time );
  1253. // Move the evaluation time up by the resample interval
  1254. time += timeSelection.m_nResampleInterval;
  1255. }
  1256. // Iterate through all of the samples and construct
  1257. int nNumSamples = sampleTimes.Count();
  1258. for ( int i = 0; i < nNumSamples; ++i )
  1259. {
  1260. // Calculate the time relative to the log
  1261. DmeTime_t logTime = clipStack.ToChildMediaTime( sampleTimes[ i ] );
  1262. // Add the position of the transform to the position log of the dag node's transform
  1263. if ( pVectorLayer )
  1264. {
  1265. Vector vLocalPosition = samplePositions[ i ];
  1266. pVectorLayer->SetKey( logTime, vLocalPosition, SEGMENT_INTERPOLATE, CURVE_DEFAULT, false );
  1267. }
  1268. }
  1269. // Convert the time selection into the local time space of the log.
  1270. DmeLog_TimeSelection_t logTimeSelection = timeSelection;
  1271. clipStack.ToChildMediaTime( logTimeSelection.m_nTimes );
  1272. // Blend the top level log layers contain the new position and orientation with the base log
  1273. // layer according to the time selection parameters and then flatten the log layers.
  1274. pPosLog->BlendLayersUsingTimeSelection( logTimeSelection );
  1275. {
  1276. CEnableUndoScopeGuard undosg;
  1277. pPosLog->FlattenLayers( timeSelection.m_flThreshold, 0 );
  1278. }
  1279. // Restore all of the channels to the original times so that this operation does not have side effects.
  1280. PlayChannelsAtLocalTimes( channelTimeList, channelList, operatorList );
  1281. }
  1282. g_pDataModel->FinishUndo();
  1283. }
  1284. }
  1285. void CDmeDag::GetAbsTransform( matrix3x4_t &matAbsTransform ) const
  1286. {
  1287. matrix3x4_t parentToWorld;
  1288. GetParentWorldMatrix( parentToWorld );
  1289. matrix3x4_t localMatrix;
  1290. GetLocalMatrix( localMatrix );
  1291. ConcatTransforms( parentToWorld, localMatrix, matAbsTransform );
  1292. }
  1293. void CDmeDag::SetAbsTransform( const matrix3x4_t &matAbsTransform )
  1294. {
  1295. CDmeTransform *pTransform = GetTransform();
  1296. if ( pTransform == NULL )
  1297. return;
  1298. matrix3x4_t parentToWorld;
  1299. GetParentWorldMatrix( parentToWorld );
  1300. matrix3x4_t worldToParent;
  1301. MatrixInvert( parentToWorld, worldToParent );
  1302. matrix3x4_t localSpace;
  1303. ConcatTransforms( worldToParent, matAbsTransform, localSpace );
  1304. Vector localPos;
  1305. Quaternion localRot;
  1306. MatrixAngles( localSpace, localRot, localPos );
  1307. // The position only override depends on the local transform when calculating the parent transform,
  1308. // meaning that simply inverting the parent to world matrix and concatenating it with the desired
  1309. // absolute transform does not produce the correct local matrix since changing the local matrix
  1310. // changes the result of GetParentWorldMatrix(). So when the position only override is enabled we
  1311. // must compute the rotation and position separately.
  1312. if ( HasOverrideParent() )
  1313. {
  1314. matrix3x4_t mTranslationParentToWorld;
  1315. GetTranslationParentWorldMatrix( mTranslationParentToWorld );
  1316. matrix3x4_t mTranslationWorldToParent;
  1317. MatrixInvert( mTranslationParentToWorld, mTranslationWorldToParent );
  1318. matrix3x4_t mTranslationLocalSpace;
  1319. ConcatTransforms( mTranslationWorldToParent, matAbsTransform, mTranslationLocalSpace );
  1320. MatrixPosition( mTranslationLocalSpace, localPos);
  1321. }
  1322. pTransform->SetPosition( localPos );
  1323. pTransform->SetOrientation( localRot );
  1324. }
  1325. CDmeDag *CDmeDag::GetParent() const
  1326. {
  1327. const static CUtlSymbolLarge symChildren = g_pDataModel->GetSymbol( "children" );
  1328. CDmeDag *pParent = FindReferringElement< CDmeDag >( this, symChildren, false );
  1329. return pParent;
  1330. }
  1331. //-----------------------------------------------------------------------------
  1332. // Determine if the dag has an override parent
  1333. //-----------------------------------------------------------------------------
  1334. bool CDmeDag::HasOverrideParent() const
  1335. {
  1336. if ( m_bDisableOverrideParent )
  1337. return false;
  1338. return ( GetValueElement< CDmeDag >( OVERRIDE_PARENT ) != NULL );
  1339. }
  1340. //-----------------------------------------------------------------------------
  1341. // Get the current override parent, returns NULL if no override parent is set
  1342. //-----------------------------------------------------------------------------
  1343. const CDmeDag *CDmeDag::GetOverrideParent( bool bIgnoreEnable ) const
  1344. {
  1345. if ( m_bDisableOverrideParent && !bIgnoreEnable )
  1346. return NULL;
  1347. return GetValueElement< CDmeDag >( OVERRIDE_PARENT );
  1348. }
  1349. //-----------------------------------------------------------------------------
  1350. // Get the current override parent, returns NULL if no override parent is set
  1351. //-----------------------------------------------------------------------------
  1352. const CDmeDag *CDmeDag::GetOverrideParent( bool &bPosition, bool &bRotation, bool bIgnoreEnable ) const
  1353. {
  1354. bPosition = false;
  1355. bRotation = false;
  1356. if ( m_bDisableOverrideParent && !bIgnoreEnable )
  1357. return NULL;
  1358. CDmeDag *pOverrideParent = GetValueElement< CDmeDag >( OVERRIDE_PARENT );
  1359. if ( pOverrideParent )
  1360. {
  1361. bPosition = GetValue< bool >( "overridePos", false );
  1362. bRotation = GetValue< bool >( "overrideRot", false );
  1363. }
  1364. if ( bPosition || bRotation )
  1365. {
  1366. return pOverrideParent;
  1367. }
  1368. return NULL;
  1369. }
  1370. //-----------------------------------------------------------------------------
  1371. // Set the current override parent, if the parameter is NULL the overrider
  1372. // parent will be cleared.
  1373. //-----------------------------------------------------------------------------
  1374. void CDmeDag::SetOverrideParent( const CDmeDag *pParentDag, bool bPosition, bool bRotation )
  1375. {
  1376. if ( ( pParentDag == NULL ) || ( !bPosition && !bRotation ) )
  1377. {
  1378. RemoveAttribute( OVERRIDE_PARENT );
  1379. RemoveAttribute( "overridePos" );
  1380. RemoveAttribute( "overrideRot" );
  1381. }
  1382. else
  1383. {
  1384. CDmAttribute *pOverrideAttr = SetValue( OVERRIDE_PARENT, pParentDag );
  1385. if ( pOverrideAttr )
  1386. {
  1387. // Set the never copy flag so that the reference
  1388. // will not be walked when deleting an animation set.
  1389. pOverrideAttr->AddFlag( FATTRIB_NEVERCOPY );
  1390. }
  1391. SetValue< bool >( "overridePos", bPosition );
  1392. SetValue< bool >( "overrideRot", bRotation );
  1393. }
  1394. }
  1395. //-----------------------------------------------------------------------------
  1396. // Set the flag which enables or disables the override parent
  1397. //-----------------------------------------------------------------------------
  1398. void CDmeDag::EnableOverrideParent( bool bEnable )
  1399. {
  1400. m_bDisableOverrideParent = !bEnable;
  1401. }
  1402. //-----------------------------------------------------------------------------
  1403. // Determine if the override parent is enabled. This only says if an override
  1404. // parent is allowed, not if the dag has an override parent)
  1405. //-----------------------------------------------------------------------------
  1406. bool CDmeDag::IsOverrideParentEnabled() const
  1407. {
  1408. return !m_bDisableOverrideParent;
  1409. }
  1410. //-----------------------------------------------------------------------------
  1411. // Determine if this dag node is ancestor of the specified dag
  1412. //-----------------------------------------------------------------------------
  1413. bool CDmeDag::IsAncestorOfDag( const CDmeDag *pDag ) const
  1414. {
  1415. if ( pDag == NULL )
  1416. return false;
  1417. const CDmeDag *pCurrentDag = pDag;
  1418. const CDmeDag *pParent = pDag->GetParent();
  1419. while ( pParent )
  1420. {
  1421. if ( pParent == this )
  1422. return true;
  1423. pCurrentDag = pParent;
  1424. pParent = pParent->GetParent();
  1425. }
  1426. return false;
  1427. }
  1428. //-----------------------------------------------------------------------------
  1429. // Purpose: Find the dag node which is the root of the tree the dag node is in.
  1430. //-----------------------------------------------------------------------------
  1431. CDmeDag *CDmeDag::FindRoot()
  1432. {
  1433. CDmeDag *pRoot = this;
  1434. CDmeDag *pParent = GetParent();
  1435. while ( pParent )
  1436. {
  1437. pRoot = pParent;
  1438. pParent = pParent->GetParent();
  1439. }
  1440. return pRoot;
  1441. }
  1442. void CDmeDag::GetAbsPosition( Vector &absPos ) const
  1443. {
  1444. matrix3x4_t abs;
  1445. GetAbsTransform( abs );
  1446. MatrixGetColumn( abs, 3, absPos );
  1447. }
  1448. void CDmeDag::SetAbsPosition( const Vector &absPos )
  1449. {
  1450. matrix3x4_t abs;
  1451. GetAbsTransform( abs );
  1452. MatrixSetColumn( absPos, 3, abs );
  1453. SetAbsTransform( abs );
  1454. }
  1455. void CDmeDag::GetAbsOrientation( Quaternion &absOrientation ) const
  1456. {
  1457. matrix3x4_t abs;
  1458. GetAbsTransform( abs );
  1459. Vector absPos;
  1460. MatrixQuaternion( abs, absOrientation );
  1461. }
  1462. void CDmeDag::SetAbsOrientation( const Quaternion &absOrientation )
  1463. {
  1464. matrix3x4_t abs;
  1465. GetAbsTransform( abs );
  1466. Vector absPos;
  1467. MatrixGetColumn( abs, 3, absPos );
  1468. QuaternionMatrix( absOrientation, absPos, abs );
  1469. SetAbsTransform( abs );
  1470. }
  1471. void RemoveDagFromParents( CDmeDag *pDag, bool bRecursivelyRemoveEmptyDagsFromParents /*= false*/ )
  1472. {
  1473. DmAttributeReferenceIterator_t hAttr = g_pDataModel->FirstAttributeReferencingElement( pDag->GetHandle() );
  1474. for ( ; hAttr != DMATTRIBUTE_REFERENCE_ITERATOR_INVALID; hAttr = g_pDataModel->NextAttributeReferencingElement( hAttr ) )
  1475. {
  1476. CDmAttribute *pAttr = g_pDataModel->GetAttribute( hAttr );
  1477. if ( !pAttr )
  1478. continue;
  1479. CDmeDag *pParent = CastElement< CDmeDag >( pAttr->GetOwner() );
  1480. if ( !pParent )
  1481. continue;
  1482. pParent->RemoveChild( pDag );
  1483. if ( bRecursivelyRemoveEmptyDagsFromParents && pParent->GetChildCount() == 0 )
  1484. {
  1485. RemoveDagFromParents( pParent );
  1486. }
  1487. }
  1488. }