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.
438 lines
10 KiB
438 lines
10 KiB
//========= 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; |
|
} |
|
} |
|
} |
|
} |
|
} |