#include "StdAfx.h" #include "EtObject.h" #include "EtFindCollision.h" #include "EtLoader.h" #include "PerfCheck.h" #include "EtCollisionMng.h" using namespace EternityEngine; DECL_MULTISMART_PTR_STATIC( CEtObject, MAX_SESSION_COUNT, 1000 ) STATIC_DECL_INIT( CEtObject, CEtOctree< CEtObject * >, s_DynamicOctree ); float CEtOctreeNode< CEtObject * >::s_fMinRadius = 1000.0f; CEtObject::CEtObject( CMultiRoom *pRoom ) : CMultiSmartPtrBase< CEtObject, MAX_SESSION_COUNT >(pRoom) { EtMatrixIdentity( &m_WorldMat ); m_pCurOctreeNode = NULL; m_BoundingBox.Reset(); } CEtObject::~CEtObject(void) { if( m_pCurOctreeNode ) { STATIC_INSTANCE(s_DynamicOctree).Remove( this, m_pCurOctreeNode ); } Clear(); } void CEtObject::Clear() { SAFE_RELEASE_SPTR( m_hSkin ); } int CEtObject::Initialize( EtSkinHandle hSkin ) { Clear(); m_hSkin = hSkin; CommonInitialize(); return ET_OK; } void CEtObject::CommonInitialize() { if( !m_hSkin || !m_hSkin->GetMeshHandle() ) { _ASSERT(0); return; } CEtCollisionEntity::Initialize( *m_hSkin->GetMeshHandle()->GetCollisionPrimitive(), *m_hSkin->GetMeshHandle()->GetCollisionPrimitiveParentIndex() ); UpdateCollisionPrimitive( m_WorldMat ); GetMeshBoundingBox( m_OriginalBoundingBox ); GetMeshBoundingSphere( m_OriginalBoundingSphere ); } void CEtObject::Update( EtMatrix *pWorldMat ) { SSphere Sphere; m_WorldMat = *pWorldMat; UpdateBoundingPrimitive(); if( m_hSkin ) { UpdateCollisionPrimitive( m_WorldMat ); GetBoundingSphere( Sphere ); if( GetCollisionGroup() >= COLLISION_GROUP_DYNAMIC( 2 ) ) // ´ÙÀ̳ª¹Í Äø®Á¯ ŸÀÔÀÎ ¾Öµé¸¸ ¿ÁÆ®¸®¿¡ ³Ö¾î¼­ üũ ½ºÅÂÆ½Àº KdTree·Î ±¸Çö. { if( m_pCurOctreeNode ) { m_pCurOctreeNode = STATIC_INSTANCE(s_DynamicOctree).Update( this, Sphere, m_pCurOctreeNode ); } else { m_pCurOctreeNode = STATIC_INSTANCE(s_DynamicOctree).Insert( this, Sphere ); } } } } void CEtObject::GetMeshBoundingBox( SAABox &AABox ) { EtMeshHandle hMesh; hMesh = m_hSkin->GetMeshHandle(); if( hMesh ) { hMesh->GetBoundingBox( AABox ); } else { AABox.Min = EtVector3( -1.0f, -1.0f, -1.0f ); AABox.Max = EtVector3( 1.0f, 1.0f, 1.0f ); } } void CEtObject::GetMeshBoundingSphere( SSphere &Sphere ) { EtMeshHandle hMesh; hMesh = m_hSkin->GetMeshHandle(); if( hMesh ) { hMesh->GetBoundingSphere( Sphere ); } else { Sphere.Center = EtVector3( 0.0f, 0.0f, 0.0f ); Sphere.fRadius = 1.0f; } } void CEtObject::RecalcBoundingBox() { GetMeshBoundingBox( m_OriginalBoundingBox ); } void CEtObject::RecalcBoundingSphere() { EtVector3 vDirection, vOriginalEnd, vChildEnd; SSphere BoundingSphere; GetMeshBoundingSphere( m_OriginalBoundingSphere ); } void CEtObject::UpdateBoundingPrimitive() { if( !m_hSkin ) { return; } int i; EtMatrix OutputMat; EtMatrixScaling( &OutputMat, m_vScale.x, m_vScale.y, m_vScale.z ); EtMatrixMultiply( &OutputMat, &OutputMat, &m_WorldMat ); m_BoundingBox.Reset(); for( i = 0; i < 8; i ++ ) { EtVector3 vPoint; m_OriginalBoundingBox.GetVertex( i, vPoint ); EtVec3TransformCoord( &vPoint, &vPoint, &OutputMat ); m_BoundingBox.AddPoint( vPoint ); } m_BoundingSphere = m_OriginalBoundingSphere; EtVec3TransformCoord( &m_BoundingSphere.Center, &m_OriginalBoundingSphere.Center, &m_WorldMat ); m_BoundingSphere.fRadius *= max( max( m_vScale.x, m_vScale.y ), m_vScale.z ); } void CEtObject::UpdateCollisionPrimitive( EtMatrix &WorldMat ) { if( !IsEnableCollision() ) { return; } int i; EtMatrix *pBoneMat, AniMat; for( i = 0; i < ( int )m_vecPrimitive.size(); i++ ) { pBoneMat = &WorldMat; if( m_vecPrimitiveParentIndex[ i ] != -1 ) { pBoneMat = GetBoneMat( m_vecPrimitiveParentIndex[ i ] ); if( pBoneMat ) { pBoneMat = EtMatrixMultiply( &AniMat, pBoneMat, &WorldMat ); } else { pBoneMat = &WorldMat; } } CEtCollisionEntity::UpdateCollisionPrimitive( i, *pBoneMat ); } } bool CEtObject::FindDynamicCollision( EtMatrix &WorldMat, DNVector(SCollisionResponse) &vecResponse, bool bCalcContactTime, bool bUpdatePrimitive ) { SAABox BoundingBox; EtVector3 vMove; vMove.x = WorldMat._41 - m_WorldMat._41; vMove.y = WorldMat._42 - m_WorldMat._42; vMove.z = WorldMat._43 - m_WorldMat._43; GetBoundingBox( BoundingBox ); BoundingBox.Max += vMove; BoundingBox.Min += vMove; if( bUpdatePrimitive ) { UpdateCollisionPrimitive( WorldMat ); } return _FindDynamicCollision( BoundingBox, vMove, vecResponse, bCalcContactTime ); } bool CEtObject::_FindDynamicCollision( SAABox &BoundingBox, EtVector3 &vMove, DNVector(SCollisionResponse) &vecResponse, bool bCalcContactTime ) { STATIC_DECL( DNVector(CEtObject*) vecPickObject ); bool bRet = false; STATIC_INSTANCE( vecPickObject ).clear(); STATIC_INSTANCE( s_DynamicOctree ).Pick( BoundingBox, STATIC_INSTANCE( vecPickObject ) ); if( !STATIC_INSTANCE( vecPickObject ).empty() ) { int i; for( i = 0; i < ( int )STATIC_INSTANCE( vecPickObject ).size(); i++ ) { std::vector< SCollisionPrimitive * > *pTargetPrimitive; if( !STATIC_INSTANCE( vecPickObject )[ i ]->IsEnableCollision() ) { continue; } if( ( STATIC_INSTANCE( vecPickObject )[ i ]->GetCollisionGroup() & GetTargetCollisionGroup() ) == 0 ) { continue; } pTargetPrimitive = STATIC_INSTANCE( vecPickObject )[ i ]->GetCollisionPrimitive(); if( !pTargetPrimitive ) { continue; } if( CEtCollisionEntity::FindCollision( *pTargetPrimitive, vMove, vecResponse, bCalcContactTime ) ) { bRet = true; } } } return bRet; } bool CEtObject::FindCollision( EtMatrix &WorldMat, DNVector(SCollisionResponse) &vecResponse, bool bCalcContactTime, bool bUpdaePrimitive ) { if( !IsEnableCollision() ) { return false; } SAABox BoundingBox; EtVector3 vMove; bool bResult; PROFILE_TIME_TEST_BLOCK_START( "FindCollision1" ); vMove.x = WorldMat._41 - m_WorldMat._41; vMove.y = WorldMat._42 - m_WorldMat._42; vMove.z = WorldMat._43 - m_WorldMat._43; GetBoundingBox( BoundingBox ); BoundingBox.Max += vMove; BoundingBox.Min += vMove; if( bUpdaePrimitive ) { UpdateCollisionPrimitive( WorldMat ); } bResult = CEtCollisionMng::GetInstance(GetRoom()).FindCollision( m_vecPrimitive, BoundingBox, vMove, vecResponse, bCalcContactTime ); if( _FindDynamicCollision( BoundingBox, vMove, vecResponse, bCalcContactTime ) ) { bResult = true; } PROFILE_TIME_TEST_BLOCK_END(); return bResult; } bool CEtObject::FindCollision( EtObjectHandle hObject, DNVector(SCollisionResponse) &vecResponse, bool bCalcContactTime ) { int i, j; SCollisionResponse Response; bool bResult = false; std::vector< SCollisionPrimitive * > &vecTragetPrimitive = *hObject->GetCollisionPrimitive(); PROFILE_TIME_TEST_BLOCK_START( "FindCollision2" ); for( i = 0; i < ( int )m_vecPrimitive.size(); i++ ) { if( !m_vecPrimitiveEnable[ i ] ) { continue; } for( j = 0; j < ( int )vecTragetPrimitive.size(); j++ ) { if( !hObject->IsEnableCollision( vecTragetPrimitive[ j ] ) ) { continue; } if( CEtCollisionFinder::GetInstance().FindCollision( *m_vecPrimitive[ i ], *vecTragetPrimitive[ j ], Response, bCalcContactTime ) ) { Response.pCollisionPrimitive = vecTragetPrimitive[ j ]; vecResponse.push_back( Response ); if( Response.vExtraNormal.x != FLT_MAX ) { Response.vNormal = Response.vExtraNormal; vecResponse.push_back( Response ); } bResult = true; } } } PROFILE_TIME_TEST_BLOCK_END(); return bResult; } void CEtObject::GetExtent( EtVector3 &Origin, EtVector3 &Extent ) { Origin = ( m_BoundingBox.Max + m_BoundingBox.Min ) / 2; Extent = ( m_BoundingBox.Max - m_BoundingBox.Min ) / 2; } void CEtObject::SetWorldSize( CMultiRoom *pRoom, EtVector3 &WorldCenter, float fRadius ) { STATIC_INSTANCE_(s_DynamicOctree).Initialize( WorldCenter, fRadius ); STATIC_INSTANCE_(s_DynamicOctree).UseLock( false ); int i, nItemCount; nItemCount = GetItemCount(pRoom); for( i = 0; i < nItemCount; i++ ) { EtObjectHandle hObject = GetItem( pRoom, i ); if( hObject ) hObject->m_pCurOctreeNode = NULL; } }