|
|
//========= 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; } } } } }
|