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.

437 lines
10 KiB

  1. //========= Copyright 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_interfaces.h"
  11. #include "movieobjects/dmedrawsettings.h"
  12. // memdbgon must be the last include file in a .cpp file!!!
  13. #include "tier0/memdbgon.h"
  14. //-----------------------------------------------------------------------------
  15. // Expose this class to the scene database
  16. //-----------------------------------------------------------------------------
  17. IMPLEMENT_ELEMENT_FACTORY( DmeDag, CDmeDag );
  18. //-----------------------------------------------------------------------------
  19. // Purpose:
  20. //-----------------------------------------------------------------------------
  21. CUtlStack<CDmeDag::TransformInfo_t> CDmeDag::s_TransformStack;
  22. bool CDmeDag::s_bDrawUsingEngineCoordinates = false;
  23. //-----------------------------------------------------------------------------
  24. // Purpose:
  25. //-----------------------------------------------------------------------------
  26. void CDmeDag::OnConstruction()
  27. {
  28. m_Transform.InitAndCreate( this, "transform", GetName() );
  29. m_Shape.Init( this, "shape" );
  30. m_Visible.InitAndSet( this, "visible", true, FATTRIB_HAS_CALLBACK );
  31. m_Children.Init( this, "children" );
  32. }
  33. void CDmeDag::OnDestruction()
  34. {
  35. g_pDataModel->DestroyElement( m_Transform.Get() );
  36. }
  37. //-----------------------------------------------------------------------------
  38. // Accessors
  39. //-----------------------------------------------------------------------------
  40. CDmeTransform *CDmeDag::GetTransform()
  41. {
  42. return m_Transform.GetElement();
  43. }
  44. CDmeShape *CDmeDag::GetShape()
  45. {
  46. return m_Shape.GetElement();
  47. }
  48. void CDmeDag::SetShape( CDmeShape *pShape )
  49. {
  50. m_Shape = pShape;
  51. }
  52. bool CDmeDag::IsVisible() const
  53. {
  54. return m_Visible;
  55. }
  56. void CDmeDag::SetVisible( bool bVisible )
  57. {
  58. m_Visible = bVisible;
  59. }
  60. //-----------------------------------------------------------------------------
  61. // Returns the visibility attribute for DmeRenderable support
  62. //-----------------------------------------------------------------------------
  63. CDmAttribute *CDmeDag::GetVisibilityAttribute()
  64. {
  65. return m_Visible.GetAttribute();
  66. }
  67. //-----------------------------------------------------------------------------
  68. // child helpers
  69. //-----------------------------------------------------------------------------
  70. const CUtlVector< DmElementHandle_t > &CDmeDag::GetChildren() const
  71. {
  72. return m_Children.Get();
  73. }
  74. int CDmeDag::GetChildCount() const
  75. {
  76. return m_Children.Count();
  77. }
  78. CDmeDag *CDmeDag::GetChild( int i ) const
  79. {
  80. if ( i < 0 || i >= m_Children.Count() )
  81. return NULL;
  82. return m_Children.Get( i );
  83. }
  84. void CDmeDag::AddChild( CDmeDag* pDag )
  85. {
  86. m_Children.AddToTail( pDag );
  87. }
  88. void CDmeDag::RemoveChild( int i )
  89. {
  90. m_Children.FastRemove( i );
  91. }
  92. void CDmeDag::RemoveChild( const CDmeDag *pChild, bool bRecurse )
  93. {
  94. int i = FindChild( pChild );
  95. if ( i >= 0 )
  96. {
  97. RemoveChild( i );
  98. }
  99. }
  100. int CDmeDag::FindChild( const CDmeDag *pChild ) const
  101. {
  102. return m_Children.Find( pChild->GetHandle() );
  103. }
  104. // recursive
  105. int CDmeDag::FindChild( CDmeDag *&pParent, const CDmeDag *pChild )
  106. {
  107. int index = FindChild( pChild );
  108. if ( index >= 0 )
  109. {
  110. pParent = this;
  111. return index;
  112. }
  113. int nChildren = m_Children.Count();
  114. for ( int ci = 0; ci < nChildren; ++ci )
  115. {
  116. index = m_Children[ ci ]->FindChild( pParent, pChild );
  117. if ( index >= 0 )
  118. return index;
  119. }
  120. pParent = NULL;
  121. return -1;
  122. }
  123. int CDmeDag::FindChild( const char *name ) const
  124. {
  125. int nChildren = m_Children.Count();
  126. for ( int ci = 0; ci < nChildren; ++ci )
  127. {
  128. if ( V_strcmp( m_Children[ ci ]->GetName(), name ) == 0 )
  129. return ci;
  130. }
  131. return -1;
  132. }
  133. CDmeDag *CDmeDag::FindOrAddChild( const char *name )
  134. {
  135. int i = FindChild( name );
  136. if ( i >= 0 )
  137. return GetChild( i );
  138. CDmeDag *pChild = CreateElement< CDmeDag >( name, GetFileId() );
  139. AddChild( pChild );
  140. return pChild;
  141. }
  142. //-----------------------------------------------------------------------------
  143. // Recursively render the Dag hierarchy
  144. //-----------------------------------------------------------------------------
  145. void CDmeDag::PushDagTransform()
  146. {
  147. int i = s_TransformStack.Push();
  148. TransformInfo_t &info = s_TransformStack[i];
  149. info.m_pTransform = GetTransform();
  150. info.m_bComputedDagToWorld = false;
  151. }
  152. void CDmeDag::PopDagTransform()
  153. {
  154. Assert( s_TransformStack.Top().m_pTransform == GetTransform() );
  155. s_TransformStack.Pop();
  156. }
  157. //-----------------------------------------------------------------------------
  158. // Transform from DME to engine coordinates
  159. //-----------------------------------------------------------------------------
  160. void CDmeDag::DmeToEngineMatrix( matrix3x4_t& dmeToEngine )
  161. {
  162. VMatrix rotation, rotationZ;
  163. MatrixBuildRotationAboutAxis( rotation, Vector( 1, 0, 0 ), 90 );
  164. MatrixBuildRotationAboutAxis( rotationZ, Vector( 0, 1, 0 ), 90 );
  165. ConcatTransforms( rotation.As3x4(), rotationZ.As3x4(), dmeToEngine );
  166. }
  167. //-----------------------------------------------------------------------------
  168. // Transform from engine to DME coordinates
  169. //-----------------------------------------------------------------------------
  170. void CDmeDag::EngineToDmeMatrix( matrix3x4_t& engineToDme )
  171. {
  172. VMatrix rotation, rotationZ;
  173. MatrixBuildRotationAboutAxis( rotation, Vector( 1, 0, 0 ), -90 );
  174. MatrixBuildRotationAboutAxis( rotationZ, Vector( 0, 1, 0 ), -90 );
  175. ConcatTransforms( rotationZ.As3x4(), rotation.As3x4(), engineToDme );
  176. }
  177. void CDmeDag::GetShapeToWorldTransform( matrix3x4_t &mat )
  178. {
  179. int nCount = s_TransformStack.Count();
  180. if ( nCount == 0 )
  181. {
  182. if ( !s_bDrawUsingEngineCoordinates )
  183. {
  184. SetIdentityMatrix( mat );
  185. }
  186. else
  187. {
  188. DmeToEngineMatrix( mat );
  189. }
  190. return;
  191. }
  192. if ( s_TransformStack.Top().m_bComputedDagToWorld )
  193. {
  194. MatrixCopy( s_TransformStack.Top().m_DagToWorld, mat );
  195. return;
  196. }
  197. // Compute all uncomputed dag to worls
  198. int i;
  199. for ( i = 0; i < nCount; ++i )
  200. {
  201. TransformInfo_t &info = s_TransformStack[i];
  202. if ( !info.m_bComputedDagToWorld )
  203. break;
  204. }
  205. // Set up the initial transform
  206. if ( i == 0 )
  207. {
  208. if ( !s_bDrawUsingEngineCoordinates )
  209. {
  210. SetIdentityMatrix( mat );
  211. }
  212. else
  213. {
  214. DmeToEngineMatrix( mat );
  215. }
  216. }
  217. else
  218. {
  219. MatrixCopy( s_TransformStack[i-1].m_DagToWorld, mat );
  220. }
  221. // Compute all transforms
  222. for ( ; i < nCount; ++i )
  223. {
  224. matrix3x4_t localToParent;
  225. TransformInfo_t &info = s_TransformStack[i];
  226. info.m_pTransform->GetTransform( localToParent );
  227. ConcatTransforms( mat, localToParent, info.m_DagToWorld );
  228. info.m_bComputedDagToWorld = true;
  229. MatrixCopy( info.m_DagToWorld, mat );
  230. }
  231. }
  232. //-----------------------------------------------------------------------------
  233. //
  234. //-----------------------------------------------------------------------------
  235. void CDmeDag::GetLocalMatrix( matrix3x4_t &m )
  236. {
  237. CDmeTransform *pTransform = GetTransform();
  238. if ( pTransform )
  239. {
  240. pTransform->GetTransform( m );
  241. }
  242. else
  243. {
  244. SetIdentityMatrix( m );
  245. }
  246. }
  247. //-----------------------------------------------------------------------------
  248. //
  249. //-----------------------------------------------------------------------------
  250. void CDmeDag::GetWorldMatrix( matrix3x4_t &m )
  251. {
  252. GetLocalMatrix( m );
  253. const static UtlSymId_t symChildren = g_pDataModel->GetSymbol( "children" );
  254. CDmeDag *pParent = FindReferringElement< CDmeDag >( this, symChildren );
  255. if ( pParent )
  256. {
  257. matrix3x4_t localMatrix;
  258. GetLocalMatrix( localMatrix );
  259. matrix3x4_t parentWorldMatrix;
  260. pParent->GetWorldMatrix( parentWorldMatrix );
  261. ConcatTransforms( parentWorldMatrix, localMatrix, m );
  262. }
  263. else
  264. {
  265. GetLocalMatrix( m );
  266. }
  267. }
  268. //-----------------------------------------------------------------------------
  269. //
  270. //-----------------------------------------------------------------------------
  271. void CDmeDag::GetParentWorldMatrix( matrix3x4_t &m )
  272. {
  273. const static UtlSymId_t symChildren = g_pDataModel->GetSymbol( "children" );
  274. CDmeDag *pParent = FindReferringElement< CDmeDag >( this, symChildren );
  275. if ( pParent )
  276. {
  277. pParent->GetWorldMatrix( m );
  278. }
  279. else
  280. {
  281. SetIdentityMatrix( m );
  282. }
  283. }
  284. //-----------------------------------------------------------------------------
  285. // Recursively render the Dag hierarchy
  286. //-----------------------------------------------------------------------------
  287. void CDmeDag::DrawUsingEngineCoordinates( bool bEnable )
  288. {
  289. s_bDrawUsingEngineCoordinates = bEnable;
  290. }
  291. //-----------------------------------------------------------------------------
  292. // Recursively render the Dag hierarchy
  293. //-----------------------------------------------------------------------------
  294. void CDmeDag::Draw( CDmeDrawSettings *pDrawSettings )
  295. {
  296. if ( !m_Visible )
  297. return;
  298. PushDagTransform();
  299. CDmeShape *pShape = GetShape();
  300. if ( pShape )
  301. {
  302. matrix3x4_t shapeToWorld;
  303. GetShapeToWorldTransform( shapeToWorld );
  304. pShape->Draw( shapeToWorld, pDrawSettings );
  305. }
  306. uint cn = m_Children.Count();
  307. for ( uint ci = 0; ci < cn; ++ci )
  308. {
  309. m_Children[ ci ]->Draw( pDrawSettings );
  310. }
  311. PopDagTransform();
  312. }
  313. //-----------------------------------------------------------------------------
  314. //
  315. //-----------------------------------------------------------------------------
  316. void CDmeDag::GetBoundingSphere( Vector &c0, float &r0, const matrix3x4_t &pMat ) const
  317. {
  318. matrix3x4_t lMat;
  319. m_Transform.GetElement()->GetTransform( lMat );
  320. matrix3x4_t wMat;
  321. ConcatTransforms( pMat, lMat, wMat );
  322. c0.Zero();
  323. r0 = 0.0f;
  324. const CDmeShape *pShape = m_Shape.GetElement();
  325. if ( pShape )
  326. {
  327. pShape->GetBoundingSphere( c0, r0 );
  328. }
  329. // No scale in Dme! :)
  330. Vector vTemp;
  331. VectorTransform( c0, pMat, vTemp );
  332. const int nChildren = m_Children.Count();
  333. if ( nChildren > 0 )
  334. {
  335. Vector c1; // Child center
  336. float r1; // Child radius
  337. Vector v01; // c1 - c0
  338. float l01; // |v01|
  339. for ( int i = 0; i < nChildren; ++i )
  340. {
  341. m_Children[ i ]->GetBoundingSphere( c1, r1, wMat );
  342. if ( r0 == 0.0f )
  343. {
  344. c0 = c1;
  345. r0 = r1;
  346. continue;
  347. }
  348. v01 = c1 - c0;
  349. l01 = v01.NormalizeInPlace();
  350. if ( r0 < l01 + r1 )
  351. {
  352. // Current sphere doesn't contain both spheres
  353. if ( r1 < l01 + r0 )
  354. {
  355. // Child sphere doesn't contain both spheres
  356. c0 = c0 + 0.5f * ( r1 + l01 - r0 ) * v01;
  357. r0 = 0.5f * ( r0 + l01 + r1 );
  358. }
  359. else
  360. {
  361. // Child sphere contains both spheres
  362. c0 = c1;
  363. r0 = r1;
  364. }
  365. }
  366. }
  367. }
  368. }