diff options
Diffstat (limited to 'movieobjects/dmedag.cpp')
| -rw-r--r-- | movieobjects/dmedag.cpp | 438 |
1 files changed, 438 insertions, 0 deletions
diff --git a/movieobjects/dmedag.cpp b/movieobjects/dmedag.cpp new file mode 100644 index 0000000..79eb21d --- /dev/null +++ b/movieobjects/dmedag.cpp @@ -0,0 +1,438 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= +#include "movieobjects/dmedag.h" +#include "movieobjects/dmeshape.h" +#include "datamodel/dmelementfactoryhelper.h" +#include "movieobjects/dmetransform.h" +#include "movieobjects_interfaces.h" +#include "movieobjects/dmedrawsettings.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +//----------------------------------------------------------------------------- +// Expose this class to the scene database +//----------------------------------------------------------------------------- +IMPLEMENT_ELEMENT_FACTORY( DmeDag, CDmeDag ); + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CUtlStack<CDmeDag::TransformInfo_t> CDmeDag::s_TransformStack; +bool CDmeDag::s_bDrawUsingEngineCoordinates = false; + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDmeDag::OnConstruction() +{ + m_Transform.InitAndCreate( this, "transform", GetName() ); + m_Shape.Init( this, "shape" ); + m_Visible.InitAndSet( this, "visible", true, FATTRIB_HAS_CALLBACK ); + m_Children.Init( this, "children" ); +} + +void CDmeDag::OnDestruction() +{ + g_pDataModel->DestroyElement( m_Transform.Get() ); +} + + +//----------------------------------------------------------------------------- +// Accessors +//----------------------------------------------------------------------------- +CDmeTransform *CDmeDag::GetTransform() +{ + return m_Transform.GetElement(); +} + +CDmeShape *CDmeDag::GetShape() +{ + return m_Shape.GetElement(); +} + +void CDmeDag::SetShape( CDmeShape *pShape ) +{ + m_Shape = pShape; +} + + +bool CDmeDag::IsVisible() const +{ + return m_Visible; +} + +void CDmeDag::SetVisible( bool bVisible ) +{ + m_Visible = bVisible; +} + + +//----------------------------------------------------------------------------- +// Returns the visibility attribute for DmeRenderable support +//----------------------------------------------------------------------------- +CDmAttribute *CDmeDag::GetVisibilityAttribute() +{ + return m_Visible.GetAttribute(); +} + + +//----------------------------------------------------------------------------- +// child helpers +//----------------------------------------------------------------------------- +const CUtlVector< DmElementHandle_t > &CDmeDag::GetChildren() const +{ + return m_Children.Get(); +} + +int CDmeDag::GetChildCount() const +{ + return m_Children.Count(); +} + +CDmeDag *CDmeDag::GetChild( int i ) const +{ + if ( i < 0 || i >= m_Children.Count() ) + return NULL; + + return m_Children.Get( i ); +} + +void CDmeDag::AddChild( CDmeDag* pDag ) +{ + m_Children.AddToTail( pDag ); +} + +void CDmeDag::RemoveChild( int i ) +{ + m_Children.FastRemove( i ); +} + +void CDmeDag::RemoveChild( const CDmeDag *pChild, bool bRecurse ) +{ + int i = FindChild( pChild ); + if ( i >= 0 ) + { + RemoveChild( i ); + } +} + +int CDmeDag::FindChild( const CDmeDag *pChild ) const +{ + return m_Children.Find( pChild->GetHandle() ); +} + +// recursive +int CDmeDag::FindChild( CDmeDag *&pParent, const CDmeDag *pChild ) +{ + int index = FindChild( pChild ); + if ( index >= 0 ) + { + pParent = this; + return index; + } + + int nChildren = m_Children.Count(); + for ( int ci = 0; ci < nChildren; ++ci ) + { + index = m_Children[ ci ]->FindChild( pParent, pChild ); + if ( index >= 0 ) + return index; + } + + pParent = NULL; + return -1; +} + +int CDmeDag::FindChild( const char *name ) const +{ + int nChildren = m_Children.Count(); + for ( int ci = 0; ci < nChildren; ++ci ) + { + if ( V_strcmp( m_Children[ ci ]->GetName(), name ) == 0 ) + return ci; + } + return -1; +} + +CDmeDag *CDmeDag::FindOrAddChild( const char *name ) +{ + int i = FindChild( name ); + if ( i >= 0 ) + return GetChild( i ); + + CDmeDag *pChild = CreateElement< CDmeDag >( name, GetFileId() ); + AddChild( pChild ); + return pChild; +} + + +//----------------------------------------------------------------------------- +// Recursively render the Dag hierarchy +//----------------------------------------------------------------------------- +void CDmeDag::PushDagTransform() +{ + int i = s_TransformStack.Push(); + TransformInfo_t &info = s_TransformStack[i]; + info.m_pTransform = GetTransform(); + info.m_bComputedDagToWorld = false; +} + +void CDmeDag::PopDagTransform() +{ + Assert( s_TransformStack.Top().m_pTransform == GetTransform() ); + s_TransformStack.Pop(); +} + + +//----------------------------------------------------------------------------- +// Transform from DME to engine coordinates +//----------------------------------------------------------------------------- +void CDmeDag::DmeToEngineMatrix( matrix3x4_t& dmeToEngine ) +{ + VMatrix rotation, rotationZ; + MatrixBuildRotationAboutAxis( rotation, Vector( 1, 0, 0 ), 90 ); + MatrixBuildRotationAboutAxis( rotationZ, Vector( 0, 1, 0 ), 90 ); + ConcatTransforms( rotation.As3x4(), rotationZ.As3x4(), dmeToEngine ); +} + +//----------------------------------------------------------------------------- +// Transform from engine to DME coordinates +//----------------------------------------------------------------------------- +void CDmeDag::EngineToDmeMatrix( matrix3x4_t& engineToDme ) +{ + VMatrix rotation, rotationZ; + MatrixBuildRotationAboutAxis( rotation, Vector( 1, 0, 0 ), -90 ); + MatrixBuildRotationAboutAxis( rotationZ, Vector( 0, 1, 0 ), -90 ); + ConcatTransforms( rotationZ.As3x4(), rotation.As3x4(), engineToDme ); +} + + +void CDmeDag::GetShapeToWorldTransform( matrix3x4_t &mat ) +{ + int nCount = s_TransformStack.Count(); + if ( nCount == 0 ) + { + if ( !s_bDrawUsingEngineCoordinates ) + { + SetIdentityMatrix( mat ); + } + else + { + DmeToEngineMatrix( mat ); + } + return; + } + + if ( s_TransformStack.Top().m_bComputedDagToWorld ) + { + MatrixCopy( s_TransformStack.Top().m_DagToWorld, mat ); + return; + } + + // Compute all uncomputed dag to worls + int i; + for ( i = 0; i < nCount; ++i ) + { + TransformInfo_t &info = s_TransformStack[i]; + if ( !info.m_bComputedDagToWorld ) + break; + } + + // Set up the initial transform + if ( i == 0 ) + { + if ( !s_bDrawUsingEngineCoordinates ) + { + SetIdentityMatrix( mat ); + } + else + { + DmeToEngineMatrix( mat ); + } + } + else + { + MatrixCopy( s_TransformStack[i-1].m_DagToWorld, mat ); + } + + // Compute all transforms + for ( ; i < nCount; ++i ) + { + matrix3x4_t localToParent; + TransformInfo_t &info = s_TransformStack[i]; + info.m_pTransform->GetTransform( localToParent ); + ConcatTransforms( mat, localToParent, info.m_DagToWorld ); + info.m_bComputedDagToWorld = true; + MatrixCopy( info.m_DagToWorld, mat ); + } +} + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CDmeDag::GetLocalMatrix( matrix3x4_t &m ) +{ + CDmeTransform *pTransform = GetTransform(); + if ( pTransform ) + { + pTransform->GetTransform( m ); + } + else + { + SetIdentityMatrix( m ); + } +} + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CDmeDag::GetWorldMatrix( matrix3x4_t &m ) +{ + GetLocalMatrix( m ); + const static UtlSymId_t symChildren = g_pDataModel->GetSymbol( "children" ); + CDmeDag *pParent = FindReferringElement< CDmeDag >( this, symChildren ); + if ( pParent ) + { + matrix3x4_t localMatrix; + GetLocalMatrix( localMatrix ); + + matrix3x4_t parentWorldMatrix; + pParent->GetWorldMatrix( parentWorldMatrix ); + ConcatTransforms( parentWorldMatrix, localMatrix, m ); + } + else + { + GetLocalMatrix( m ); + } +} + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CDmeDag::GetParentWorldMatrix( matrix3x4_t &m ) +{ + const static UtlSymId_t symChildren = g_pDataModel->GetSymbol( "children" ); + CDmeDag *pParent = FindReferringElement< CDmeDag >( this, symChildren ); + if ( pParent ) + { + pParent->GetWorldMatrix( m ); + } + else + { + SetIdentityMatrix( m ); + } +} + + +//----------------------------------------------------------------------------- +// Recursively render the Dag hierarchy +//----------------------------------------------------------------------------- +void CDmeDag::DrawUsingEngineCoordinates( bool bEnable ) +{ + s_bDrawUsingEngineCoordinates = bEnable; +} + + +//----------------------------------------------------------------------------- +// Recursively render the Dag hierarchy +//----------------------------------------------------------------------------- +void CDmeDag::Draw( CDmeDrawSettings *pDrawSettings ) +{ + if ( !m_Visible ) + return; + + PushDagTransform(); + + CDmeShape *pShape = GetShape(); + if ( pShape ) + { + matrix3x4_t shapeToWorld; + GetShapeToWorldTransform( shapeToWorld ); + pShape->Draw( shapeToWorld, pDrawSettings ); + } + + uint cn = m_Children.Count(); + for ( uint ci = 0; ci < cn; ++ci ) + { + m_Children[ ci ]->Draw( pDrawSettings ); + } + + PopDagTransform(); +} + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CDmeDag::GetBoundingSphere( Vector &c0, float &r0, const matrix3x4_t &pMat ) const +{ + matrix3x4_t lMat; + m_Transform.GetElement()->GetTransform( lMat ); + matrix3x4_t wMat; + ConcatTransforms( pMat, lMat, wMat ); + + c0.Zero(); + r0 = 0.0f; + + const CDmeShape *pShape = m_Shape.GetElement(); + if ( pShape ) + { + pShape->GetBoundingSphere( c0, r0 ); + } + + // No scale in Dme! :) + Vector vTemp; + VectorTransform( c0, pMat, vTemp ); + + const int nChildren = m_Children.Count(); + if ( nChildren > 0 ) + { + Vector c1; // Child center + float r1; // Child radius + + Vector v01; // c1 - c0 + float l01; // |v01| + + for ( int i = 0; i < nChildren; ++i ) + { + m_Children[ i ]->GetBoundingSphere( c1, r1, wMat ); + + if ( r0 == 0.0f ) + { + c0 = c1; + r0 = r1; + continue; + } + + v01 = c1 - c0; + l01 = v01.NormalizeInPlace(); + + if ( r0 < l01 + r1 ) + { + // Current sphere doesn't contain both spheres + if ( r1 < l01 + r0 ) + { + // Child sphere doesn't contain both spheres + c0 = c0 + 0.5f * ( r1 + l01 - r0 ) * v01; + r0 = 0.5f * ( r0 + l01 + r1 ); + } + else + { + // Child sphere contains both spheres + c0 = c1; + r0 = r1; + } + } + } + } +}
\ No newline at end of file |