1209 lines
No EOL
53 KiB
C++
1209 lines
No EOL
53 KiB
C++
#include "StdAfx.h"
|
||
#include "EtObject.h"
|
||
#include "EtConvexVolume.h"
|
||
#include "EtFindCollision.h"
|
||
#include "EtLoader.h"
|
||
#include "EtCustomParam.h"
|
||
#include "EtGenerateCollisionMesh.h"
|
||
#include "EtOptionController.h"
|
||
#include "EtCollisionMng.h"
|
||
#include "EtWater.h"
|
||
#include "EtEngine.h"
|
||
#include "EtFrustum.h"
|
||
#include "EtSkyBoxRTT.h"
|
||
|
||
#if !defined( USE_BOOST_MEMPOOL )
|
||
#ifdef _DEBUG
|
||
#define new new(_NORMAL_BLOCK,__FILE__,__LINE__)
|
||
#endif
|
||
#endif
|
||
|
||
using namespace EternityEngine;
|
||
|
||
DECL_SMART_PTR_STATIC( CEtObject, 3000 )
|
||
CEtOctree< CEtObject * > *CEtObject::s_pDynamicOctree = NULL;
|
||
float CEtOctreeNode< CEtObject * >::s_fMinRadius = 1000.0f;
|
||
bool CEtObject::m_bSkipDrawCollision = false;
|
||
|
||
CEtObject::CEtObject(void)
|
||
: CSmartPtrBase< CEtObject >()
|
||
{
|
||
SetChild( false );
|
||
ShowObject( true );
|
||
EnableObject( true );
|
||
EnableCull( true );
|
||
EnableShadowCast( false );
|
||
m_bShadowReceive = false;
|
||
m_bLightMapInfluence = false;
|
||
EnableLightMapCast( false );
|
||
EnableWaterCast( false );
|
||
ShowBoundingBox( false );
|
||
ShowCollisionPrimitive( false );
|
||
EtMatrixIdentity( &m_WorldMat );
|
||
m_WorldMat._41 = m_WorldMat._42 = m_WorldMat._43 = FLT_MAX;
|
||
m_PrevWorldMat._11 = FLT_MAX;
|
||
|
||
EtMatrixIdentity( &m_LinkOffsetMat );
|
||
m_nLinkBoneIndex = -1;
|
||
m_nSaveMatIndex = -1;
|
||
m_bValidSaveMatIndex = false;
|
||
m_pSkinInstance = NULL;
|
||
|
||
m_fObjectAlpha = 1.0f;
|
||
|
||
m_pCurOctreeNode = NULL;
|
||
m_BoundingBox.Min = EtVector3( 0.f, 0.f, 0.f );
|
||
m_BoundingBox.Max = EtVector3( 0.f, 0.f, 0.f );
|
||
m_OriginalBoundingBox.Min = EtVector3( 0.f, 0.f, 0.f );
|
||
m_OriginalBoundingBox.Max = EtVector3( 0.f, 0.f, 0.f );
|
||
|
||
m_RenderType = RT_SCREEN;
|
||
m_bAniObject = false;
|
||
m_LinkType = LT_BONE;
|
||
m_nFrustumMask = 0;
|
||
}
|
||
|
||
CEtObject::~CEtObject(void)
|
||
{
|
||
if( m_hParent )
|
||
{
|
||
m_hParent->RemoveChild( GetMySmartPtr() );
|
||
}
|
||
if( m_pCurOctreeNode )
|
||
{
|
||
s_pDynamicOctree->Remove( this, m_pCurOctreeNode );
|
||
}
|
||
SAFE_DELETE( m_pSkinInstance );
|
||
|
||
Clear();
|
||
}
|
||
|
||
void CEtObject::Clear()
|
||
{
|
||
SAFE_RELEASE_SPTR( m_hSkin );
|
||
}
|
||
|
||
void CEtObject::InitializeClass()
|
||
{
|
||
s_pDynamicOctree = new CEtOctree< CEtObject * >;
|
||
}
|
||
|
||
void CEtObject::FinalizeClass()
|
||
{
|
||
SAFE_DELETE( s_pDynamicOctree );
|
||
}
|
||
|
||
int CEtObject::Initialize( EtSkinHandle hSkin )
|
||
{
|
||
Clear();
|
||
m_hSkin = hSkin;
|
||
m_pSkinInstance = new CEtSkinInstance();
|
||
|
||
if( !m_hSkin->AddCallback( this ) )
|
||
{
|
||
CommonInitialize();
|
||
}
|
||
|
||
return ET_OK;
|
||
}
|
||
|
||
void CEtObject::CommonInitialize()
|
||
{ CreateSkinInstance();
|
||
|
||
if( m_hSkin->GetMeshHandle() )
|
||
CEtCollisionEntity::Initialize( *m_hSkin->GetMeshHandle()->GetCollisionPrimitive(), *m_hSkin->GetMeshHandle()->GetCollisionPrimitiveParentIndex() );
|
||
|
||
UpdateCollisionPrimitive( m_WorldMat );
|
||
GetMeshBoundingBox( m_OriginalBoundingBox );
|
||
GetMeshBoundingSphere( m_OriginalBoundingSphere );
|
||
}
|
||
|
||
void CEtObject::CreateSkinInstance()
|
||
{
|
||
if( m_hSkin )
|
||
{
|
||
if( m_pSkinInstance == NULL )
|
||
{
|
||
m_pSkinInstance = new CEtSkinInstance();
|
||
}
|
||
m_pSkinInstance->CopySkinInfo( m_hSkin );
|
||
if( m_pSkinInstance->IsSkyBox() )
|
||
{
|
||
CEtSkyBoxRTT::GetInstance().AddObject( m_MySmartPtr );
|
||
CEtSkyBoxRTT::GetInstance().SetRenderFrameCount( -1 );
|
||
}
|
||
}
|
||
}
|
||
|
||
RenderType CEtObject::SetRenderType( RenderType Type )
|
||
{
|
||
RenderType Ret = m_RenderType;
|
||
m_RenderType = Type;
|
||
return Ret;
|
||
}
|
||
|
||
void CEtObject::SetParent( EtObjectHandle hObject, const char *pLinkBoneName, EtMatrix *pOffsetMat )
|
||
{
|
||
EtMeshHandle hMesh = hObject->GetMesh();
|
||
int nLinkBoneIndex = -1;
|
||
if( hMesh )
|
||
{
|
||
nLinkBoneIndex = hMesh->FindDummy( pLinkBoneName );
|
||
if( nLinkBoneIndex != -1 )
|
||
{
|
||
SetParent( hObject, nLinkBoneIndex, pOffsetMat, LT_MESH_DUMMY );
|
||
return;
|
||
}
|
||
nLinkBoneIndex = hMesh->FindBone( pLinkBoneName );
|
||
if( nLinkBoneIndex != -1 )
|
||
{
|
||
SetParent( hObject, nLinkBoneIndex, pOffsetMat, LT_BONE );
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
|
||
void CEtObject::SetParent( EtObjectHandle hObject, int nBoneIndex, EtMatrix *pOffsetMat, LinkType Type )
|
||
{
|
||
if ( hObject == GetMySmartPtr() )
|
||
{
|
||
ASSERT( false && "hObject == GetMySmartPtr()" );
|
||
return;
|
||
}
|
||
|
||
// 함수 돌고 있을때 오브젝트 삭제되면 위험!!!
|
||
ScopeLock<CSyncLock> Lock( s_SmartPtrLock );
|
||
|
||
if( m_hParent )
|
||
{
|
||
m_hParent->RemoveChild( GetMySmartPtr() );
|
||
}
|
||
if( hObject )
|
||
{
|
||
m_hParent = hObject;
|
||
m_nLinkBoneIndex = nBoneIndex;
|
||
m_LinkType = Type;
|
||
if( pOffsetMat )
|
||
{
|
||
m_LinkOffsetMat = *pOffsetMat;
|
||
}
|
||
m_hParent->AddChild( GetMySmartPtr() );
|
||
EnableShadowCast( m_hParent->IsShadowCast() );
|
||
EnableShadowReceive( m_hParent->IsShadowReceive() );
|
||
EnableLightMapInfluence( m_hParent->IsLightMapInfluence() );
|
||
SetObjectAlpha( m_hParent->GetObjectAlpha() );
|
||
SetChild( true );
|
||
|
||
int nItemIndex, nParentItemIndex;
|
||
|
||
nItemIndex = GetMyItemIndex();
|
||
nParentItemIndex = m_hParent->GetMyItemIndex();
|
||
if( nItemIndex < nParentItemIndex )
|
||
{
|
||
SwapItemIndex( nItemIndex, nParentItemIndex );
|
||
}
|
||
}
|
||
else
|
||
{
|
||
m_hParent.Identity();
|
||
m_nLinkBoneIndex = -1;
|
||
EtMatrixIdentity( &m_LinkOffsetMat );
|
||
SetChild( false );
|
||
}
|
||
|
||
}
|
||
|
||
void CEtObject::AddChild( EtObjectHandle hObject )
|
||
{
|
||
ScopeLock<CSyncLock> Lock( s_SmartPtrLock );
|
||
m_vecChild.push_back( hObject );
|
||
if( m_hSkin->IsReady() )
|
||
{
|
||
RecalcBoundingBox();
|
||
RecalcBoundingSphere();
|
||
}
|
||
}
|
||
|
||
void CEtObject::RemoveChild( EtObjectHandle hObject )
|
||
{
|
||
ScopeLock<CSyncLock> Lock( s_SmartPtrLock );
|
||
|
||
int i;
|
||
|
||
for( i = 0; i < ( int )m_vecChild.size(); i++ )
|
||
{
|
||
if( m_vecChild[ i ] == hObject )
|
||
{
|
||
m_vecChild.erase( m_vecChild.begin() + i );
|
||
RecalcBoundingBox();
|
||
RecalcBoundingSphere();
|
||
return;
|
||
}
|
||
}
|
||
ASSERT( 0 && "지워야할 child가 없다" );
|
||
}
|
||
|
||
bool CEtObject::IsShow()
|
||
{
|
||
if( !m_hSkin ) return false;
|
||
return m_bShow && m_hSkin->IsReady();
|
||
}
|
||
|
||
void CEtObject::EnableLightMapInfluence( bool bEnable )
|
||
{
|
||
m_bLightMapInfluence = bEnable;
|
||
CalcLightMapInfluence();
|
||
}
|
||
|
||
void CEtObject::ShowSubmesh( int nSubmeshIndex, bool bShow )
|
||
{
|
||
if( m_pSkinInstance )
|
||
{
|
||
m_pSkinInstance->GetSkinRenderInfo( nSubmeshIndex )->bShowSubmesh = bShow;
|
||
}
|
||
}
|
||
|
||
bool CEtObject::IsShowSubmesh( int nSubmeshIndex )
|
||
{
|
||
if( m_pSkinInstance )
|
||
{
|
||
return m_pSkinInstance->GetSkinRenderInfo( nSubmeshIndex )->bShowSubmesh;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
void CEtObject::SetFrustumMask( int nMask )
|
||
{
|
||
m_nFrustumMask = nMask;
|
||
}
|
||
|
||
void CEtObject::AddFrustumMask( int nMask )
|
||
{
|
||
m_nFrustumMask |= nMask;
|
||
int i, nCount;
|
||
nCount = ( int )m_vecChild.size();
|
||
for( i = 0; i < nCount; i++ )
|
||
{
|
||
EtObjectHandle hObject = m_vecChild[ i ];
|
||
hObject->AddFrustumMask( nMask );
|
||
}
|
||
}
|
||
|
||
void CEtObject::EnableShadowCast( bool bEnable )
|
||
{
|
||
ScopeLock<CSyncLock> Lock( s_SmartPtrLock );
|
||
m_bShadowCast = bEnable;
|
||
|
||
int i, nCount;
|
||
nCount = ( int )m_vecChild.size();
|
||
for( i = 0; i < nCount; i++ )
|
||
{
|
||
EtObjectHandle hObject = m_vecChild[ i ];
|
||
hObject->EnableShadowCast( bEnable );
|
||
}
|
||
}
|
||
|
||
void CEtObject::EnableShadowReceive( bool bEnable )
|
||
{
|
||
ScopeLock<CSyncLock> Lock( s_SmartPtrLock );
|
||
m_bShadowReceive = bEnable;
|
||
|
||
int i, nCount;
|
||
nCount = ( int )m_vecChild.size();
|
||
for( i = 0; i < nCount; i++ )
|
||
{
|
||
EtObjectHandle hObject = m_vecChild[ i ];
|
||
hObject->EnableShadowReceive( bEnable );
|
||
}
|
||
}
|
||
|
||
void CEtObject::SetObjectAlpha( float fAlpha )
|
||
{
|
||
ScopeLock<CSyncLock> Lock( s_SmartPtrLock );
|
||
m_fObjectAlpha = fAlpha;
|
||
|
||
int i, nCount;
|
||
nCount = ( int )m_vecChild.size();
|
||
for( i = 0; i < nCount; i++ )
|
||
{
|
||
EtObjectHandle hObject = m_vecChild[ i ];
|
||
hObject->SetObjectAlpha( fAlpha );
|
||
}
|
||
}
|
||
|
||
void CEtObject::Update( EtMatrix *pWorldMat )
|
||
{
|
||
SSphere Sphere;
|
||
|
||
if( m_PrevWorldMat._11 == FLT_MAX )
|
||
{
|
||
m_PrevWorldMat = *pWorldMat;
|
||
m_bUpdateNeeded = true;
|
||
}
|
||
else
|
||
{
|
||
m_PrevWorldMat = m_WorldMat;
|
||
if( memcmp ( &m_PrevWorldMat, pWorldMat , sizeof(EtMatrix) ) != 0 ) {
|
||
m_bUpdateNeeded = true;
|
||
}
|
||
}
|
||
m_WorldMat = *pWorldMat;
|
||
|
||
UpdateBoundingPrimitive();
|
||
CalcLightInfluence();
|
||
CalcLightMapInfluence();
|
||
if( ( m_hSkin ) && ( !IsChild() ) )
|
||
{
|
||
UpdateCollisionPrimitive( m_WorldMat, m_bUpdateNeeded );
|
||
GetBoundingSphere( Sphere );
|
||
if( GetCollisionGroup() >= COLLISION_GROUP_DYNAMIC( 2 ) ) // 다이나믹 컬리젼 타입인 애들만 옥트리에 넣어서 체크 스태틱은 KdTree로 구현.
|
||
{
|
||
if( m_pCurOctreeNode )
|
||
{
|
||
m_pCurOctreeNode = s_pDynamicOctree->Update( this, Sphere, m_pCurOctreeNode );
|
||
}
|
||
else
|
||
{
|
||
m_pCurOctreeNode = s_pDynamicOctree->Insert( this, Sphere );
|
||
}
|
||
}
|
||
}
|
||
m_bUpdateNeeded = false;
|
||
}
|
||
|
||
void CEtObject::CalcParentBoneMat()
|
||
{
|
||
EtMatrix LinkMat, *pBoneMat;
|
||
|
||
EtMatrixMultiply( &LinkMat, m_hParent->GetWorldMat(), &m_LinkOffsetMat );
|
||
if( m_nLinkBoneIndex != -1 )
|
||
{
|
||
if( m_LinkType == LT_BONE )
|
||
{
|
||
pBoneMat = m_hParent->GetBoneTransMat( m_nLinkBoneIndex );
|
||
}
|
||
else
|
||
{
|
||
pBoneMat = m_hParent->GetDummyTransMat( m_nLinkBoneIndex );
|
||
}
|
||
if( pBoneMat )
|
||
{
|
||
EtMatrixMultiply( &LinkMat, pBoneMat, &LinkMat );
|
||
}
|
||
}
|
||
Update( &LinkMat );
|
||
}
|
||
|
||
void CEtObject::InitRender( int nSaveMatIndex )
|
||
{
|
||
if( !IsShow() )
|
||
{
|
||
return;
|
||
}
|
||
|
||
if( m_hParent )
|
||
{
|
||
CalcParentBoneMat();
|
||
}
|
||
|
||
int i;
|
||
|
||
for( i = 0; i < ( int )m_vecChild.size(); i++ )
|
||
{
|
||
m_vecChild[ i ]->InitRender( nSaveMatIndex );
|
||
}
|
||
}
|
||
|
||
void CEtObject::Render()
|
||
{
|
||
if( !IsShow() )
|
||
{
|
||
return;
|
||
}
|
||
if( IsShowBoundingBox() )
|
||
{
|
||
DrawBoundingBox();
|
||
}
|
||
|
||
if( m_pSkinInstance )
|
||
{
|
||
m_pSkinInstance->Render( m_WorldMat, m_PrevWorldMat, m_fObjectAlpha, m_vecInfluenceLight, m_bShadowReceive, m_nSaveMatIndex );
|
||
}
|
||
}
|
||
|
||
void CEtObject::RenderImmediate( bool bRenderChild )
|
||
{
|
||
if( !IsShow() )
|
||
{
|
||
return;
|
||
}
|
||
if( m_pSkinInstance )
|
||
{
|
||
m_pSkinInstance->RenderImmediate( m_WorldMat, m_WorldMat, m_fObjectAlpha, m_vecInfluenceLight, m_bShadowReceive, false, m_nSaveMatIndex );
|
||
}
|
||
|
||
if( bRenderChild )
|
||
{
|
||
int i;
|
||
for( i = 0; i < ( int )m_vecChild.size(); i++ )
|
||
{
|
||
if( m_vecChild[ i ] )
|
||
{
|
||
m_vecChild[ i ]->RenderImmediate( bRenderChild );
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
void CEtObject::RenderAlphaImmediate( bool bRenderChild )
|
||
{
|
||
if( !IsShow() )
|
||
{
|
||
return;
|
||
}
|
||
if( m_pSkinInstance )
|
||
{
|
||
m_pSkinInstance->RenderImmediate( m_WorldMat, m_WorldMat, m_fObjectAlpha, m_vecInfluenceLight, m_bShadowReceive, true, m_nSaveMatIndex );
|
||
}
|
||
|
||
if( bRenderChild )
|
||
{
|
||
int i;
|
||
for( i = 0; i < ( int )m_vecChild.size(); i++ )
|
||
{
|
||
if( m_vecChild[ i ] )
|
||
{
|
||
m_vecChild[ i ]->RenderAlphaImmediate( bRenderChild );
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
void CEtObject::RenderShadow()
|
||
{
|
||
if( !IsShow() )
|
||
{
|
||
return;
|
||
}
|
||
|
||
if( m_pSkinInstance )
|
||
{
|
||
m_pSkinInstance->RenderShadow( m_WorldMat, m_nSaveMatIndex );
|
||
}
|
||
}
|
||
|
||
void CEtObject::RenderWater( int index )
|
||
{
|
||
if( !IsShow() )
|
||
{
|
||
return;
|
||
}
|
||
|
||
if( m_pSkinInstance )
|
||
{
|
||
if( !m_hParent )
|
||
{
|
||
InitRender();
|
||
m_pSkinInstance->RenderWater( index, m_WorldMat, m_PrevWorldMat, m_fObjectAlpha, m_vecInfluenceLight, m_bShadowReceive, m_nSaveMatIndex );
|
||
}
|
||
}
|
||
}
|
||
|
||
void CEtObject::SetSaveMatIndex( int nIndex )
|
||
{
|
||
m_nSaveMatIndex = nIndex;
|
||
int i;
|
||
for( i = 0; i < ( int )m_vecChild.size(); i++ )
|
||
{
|
||
m_vecChild[ i ]->SetSaveMatIndex( nIndex );
|
||
}
|
||
}
|
||
|
||
void CEtObject::GetMeshBoundingBox( SAABox &AABox )
|
||
{
|
||
if( m_hSkin )
|
||
{
|
||
EtMeshHandle hMesh = m_hSkin->GetMeshHandle();
|
||
if( hMesh )
|
||
{
|
||
hMesh->GetBoundingBox( AABox );
|
||
}
|
||
return;
|
||
}
|
||
|
||
AABox.Min = EtVector3( -1.0f, -1.0f, -1.0f );
|
||
AABox.Max = EtVector3( 1.0f, 1.0f, 1.0f );
|
||
}
|
||
|
||
void CEtObject::GetMeshBoundingSphere( SSphere &Sphere )
|
||
{
|
||
if( m_hSkin )
|
||
{
|
||
EtMeshHandle hMesh = m_hSkin->GetMeshHandle();
|
||
if( hMesh )
|
||
{
|
||
hMesh->GetBoundingSphere( Sphere );
|
||
}
|
||
return;
|
||
}
|
||
|
||
Sphere.Center = EtVector3( 0.0f, 0.0f, 0.0f );
|
||
Sphere.fRadius = 1.0f;
|
||
}
|
||
|
||
void CEtObject::RecalcBoundingBox()
|
||
{
|
||
SAABox BoundingBox;
|
||
|
||
GetMeshBoundingBox( m_OriginalBoundingBox );
|
||
// 서버에서는 차일드가 없이 계산하고 있어서 서버랑 동기를 맞추기 위해서 삭제한다. 문제 생길지도 모름..
|
||
/* for( int i = 0; i < ( int )m_vecChild.size(); i++ )
|
||
{
|
||
m_vecChild[ i ]->GetMeshBoundingBox( BoundingBox );
|
||
m_OriginalBoundingBox.AddPoint( BoundingBox.Max );
|
||
m_OriginalBoundingBox.AddPoint( BoundingBox.Min );
|
||
}*/
|
||
}
|
||
|
||
void CEtObject::RecalcBoundingSphere()
|
||
{
|
||
int i;
|
||
EtVector3 vDirection, vOriginalEnd, vChildEnd;
|
||
SSphere BoundingSphere;
|
||
|
||
GetMeshBoundingSphere( m_OriginalBoundingSphere );
|
||
for( i = 0; i < ( int )m_vecChild.size(); i++ )
|
||
{
|
||
m_vecChild[ i ]->GetMeshBoundingSphere( BoundingSphere );
|
||
if( m_OriginalBoundingSphere.IsInside( BoundingSphere ) )
|
||
{
|
||
continue;
|
||
}
|
||
vDirection = BoundingSphere.Center - m_OriginalBoundingSphere.Center;
|
||
EtVec3Normalize( &vDirection, &vDirection );
|
||
vOriginalEnd = m_OriginalBoundingSphere.Center - vDirection * m_OriginalBoundingSphere.fRadius;
|
||
vChildEnd = BoundingSphere.Center + vDirection * BoundingSphere.fRadius;
|
||
m_OriginalBoundingSphere.Center = ( vOriginalEnd + vChildEnd ) * 0.5f;
|
||
m_OriginalBoundingSphere.fRadius = EtVec3Length( &( vOriginalEnd - vChildEnd ) ) * 0.5f;
|
||
}
|
||
}
|
||
|
||
void CEtObject::DrawBoundingBox( DWORD dwColor )
|
||
{
|
||
int i;
|
||
static short s_LineIndices[] =
|
||
{
|
||
0, 1, 1, 3, 3, 2, 2, 0,
|
||
4, 5, 5, 7, 7, 6, 6, 4,
|
||
0, 4, 1, 5, 3, 7, 2, 6,
|
||
};
|
||
|
||
SOBB OBBox;
|
||
|
||
OBBox.Init( m_OriginalBoundingBox, m_WorldMat );
|
||
|
||
for( i = 0; i < sizeof( s_LineIndices ) / sizeof( short ) / 2; i++ )
|
||
{
|
||
DrawLine3D( OBBox.Vertices[ s_LineIndices[ i * 2 ] ], OBBox.Vertices[ s_LineIndices[ i * 2 + 1 ] ], dwColor );
|
||
}
|
||
}
|
||
|
||
void CEtObject::UpdateBoundingPrimitive()
|
||
{
|
||
if( !m_hSkin )
|
||
{
|
||
return;
|
||
}
|
||
|
||
if( !m_bUpdateNeeded ) { // Static Object 의 경우는 매번 계산 해줄 필요 없다.
|
||
return;
|
||
}
|
||
|
||
if( !m_OriginalBoundingBox.IsValid() ) {
|
||
return;
|
||
}
|
||
|
||
m_BoundingBox.Reset();
|
||
SOBB OBBox;
|
||
OBBox.Init( m_OriginalBoundingBox, m_WorldMat );
|
||
for( int i = 0; i < 8; i++) {
|
||
m_BoundingBox.AddPoint( OBBox.Vertices[i] );
|
||
}
|
||
|
||
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, bool bUpdate )
|
||
{
|
||
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 );
|
||
}
|
||
else {
|
||
CEtCollisionEntity::UpdateCollisionPrimitive( i, *pBoneMat, bUpdate );
|
||
}
|
||
}
|
||
}
|
||
|
||
bool CEtObject::FindDynamicCollision( EtMatrix &WorldMat, DNVector(SCollisionResponse) &vecResponse, bool bCalcContactTime, bool bUpdaetPrimitive)
|
||
{
|
||
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( bUpdaetPrimitive )
|
||
{
|
||
UpdateCollisionPrimitive( WorldMat );
|
||
m_bUpdateNeeded = true;
|
||
}
|
||
return _FindDynamicCollision( BoundingBox, vMove, vecResponse, bCalcContactTime );
|
||
}
|
||
|
||
bool CEtObject::_FindDynamicCollision( SAABox &BoundingBox, EtVector3 &vMove, DNVector(SCollisionResponse) &vecResponse, bool bCalcContactTime)
|
||
{
|
||
static DNVector(CEtObject *) vecPickObject;
|
||
|
||
bool bRet = false;
|
||
vecPickObject.clear();
|
||
s_pDynamicOctree->Pick( BoundingBox, vecPickObject );
|
||
if( !vecPickObject.empty() )
|
||
{
|
||
int i;
|
||
|
||
for( i = 0; i < ( int )vecPickObject.size(); i++ )
|
||
{
|
||
std::vector< SCollisionPrimitive * > *pTargetPrimitive;
|
||
|
||
if( !vecPickObject[ i ]->IsEnableCollision() )
|
||
{
|
||
continue;
|
||
}
|
||
if( ( vecPickObject[ i ]->GetCollisionGroup() & GetTargetCollisionGroup() ) == 0 )
|
||
{
|
||
continue;
|
||
}
|
||
pTargetPrimitive = 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 bUpdaetPrimitive)
|
||
{
|
||
if( !IsEnableCollision() )
|
||
{
|
||
return false;
|
||
}
|
||
|
||
SAABox BoundingBox;
|
||
EtVector3 vMove;
|
||
bool bResult;
|
||
|
||
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( bUpdaetPrimitive )
|
||
{
|
||
UpdateCollisionPrimitive( WorldMat );
|
||
m_bUpdateNeeded = true;
|
||
}
|
||
|
||
bResult = CEtCollisionMng::GetInstance().FindCollision( m_vecPrimitive, BoundingBox, vMove, vecResponse, bCalcContactTime );
|
||
|
||
if( _FindDynamicCollision( BoundingBox, vMove, vecResponse, bCalcContactTime ) )
|
||
{
|
||
bResult = true;
|
||
}
|
||
|
||
return bResult;
|
||
}
|
||
|
||
bool CEtObject::FindCollision( EtObjectHandle hObject, std::vector< SCollisionResponse > &vecResponse, bool bCalcContactTime )
|
||
{
|
||
int i, j;
|
||
SCollisionResponse Response;
|
||
bool bResult = false;
|
||
std::vector< SCollisionPrimitive * > &vecTragetPrimitive = *hObject->GetCollisionPrimitive();
|
||
|
||
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;
|
||
}
|
||
}
|
||
}
|
||
|
||
return bResult;
|
||
}
|
||
|
||
int CEtObject::AddCustomParam( const char *pParamName )
|
||
{
|
||
if( m_pSkinInstance )
|
||
{
|
||
return m_pSkinInstance->AddCustomParam( pParamName );
|
||
}
|
||
return -1;
|
||
}
|
||
|
||
bool CEtObject::SetCustomParam( int nParamIndex, void *pValue, int nSubMeshIndex )
|
||
{
|
||
if( m_pSkinInstance )
|
||
{
|
||
return m_pSkinInstance->SetCustomParam( nParamIndex, pValue, nSubMeshIndex );
|
||
}
|
||
return false;
|
||
}
|
||
|
||
void CEtObject::RestoreCustomParam( int nParamIndex, int nSubMeshIndex )
|
||
{
|
||
if( m_pSkinInstance )
|
||
{
|
||
m_pSkinInstance->RestoreCustomParam( nParamIndex, nSubMeshIndex );
|
||
}
|
||
}
|
||
|
||
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::ClearFrustumMask()
|
||
{
|
||
ScopeLock<CSyncLock> Lock( s_SmartPtrLock );
|
||
int i, nCount;
|
||
|
||
nCount = GetItemCount();
|
||
for( i = 0; i < nCount; i++ )
|
||
{
|
||
GetItem( i )->SetFrustumMask( 0 );
|
||
}
|
||
}
|
||
|
||
void CEtObject::MaskFrustumObjectList( CEtConvexVolume *pFrustum, int nFrustumMask )
|
||
{
|
||
int i, j, nCount;
|
||
|
||
int nWaterCount = GetEtWater()->GetWaterCount();
|
||
std::vector<CEtConvexVolume> ReflectFrustumList;
|
||
ReflectFrustumList.resize( nWaterCount );
|
||
|
||
for( i = 0; i < nWaterCount; i++) {
|
||
ReflectFrustumList[i].Initialize( GetEtWater()->GetViewProjMat( i ) );
|
||
}
|
||
|
||
ScopeLock<CSyncLock> Lock( s_SmartPtrLock );
|
||
|
||
nCount = GetItemCount();
|
||
for( i = 0; i < nCount; i++ )
|
||
{
|
||
EtVector3 Origin, Extent;
|
||
EtObjectHandle hHandle;
|
||
hHandle = GetItem( i );
|
||
if( !hHandle )
|
||
{
|
||
continue;
|
||
}
|
||
CEtObject *pObject = hHandle.GetPointer();
|
||
if( !pObject->IsEnable() )
|
||
{
|
||
continue;
|
||
}
|
||
if( pObject->IsChild() )
|
||
{
|
||
continue;
|
||
}
|
||
if( !pObject->IsShow() )
|
||
{
|
||
continue;
|
||
}
|
||
pObject->GetExtent( Origin, Extent );
|
||
|
||
if( ( !pObject->IsEnableCull() ) || pFrustum->TesToBox( Origin, Extent ) )
|
||
{
|
||
pObject->AddFrustumMask( nFrustumMask );
|
||
}
|
||
if( pObject->IsWaterCast() )
|
||
{
|
||
for( j = 0; j < nWaterCount; j++)
|
||
{
|
||
if( GetEtWater()->GetWaterIgnoreBake( j ) )
|
||
continue;
|
||
|
||
if( ( !pObject->IsEnableCull() ) || ( ReflectFrustumList[j].TesToBox( Origin, Extent ) ) )
|
||
{
|
||
pObject->RenderWater( j );
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
void CEtObject::InitRenderObjectList()
|
||
{
|
||
ScopeLock<CSyncLock> Lock( s_SmartPtrLock );
|
||
|
||
int i, nCount;
|
||
|
||
nCount = GetItemCount();
|
||
for( i = 0; i < nCount; i++ )
|
||
{
|
||
EtObjectHandle hHandle;
|
||
hHandle = GetItem( i );
|
||
if( !hHandle )
|
||
{
|
||
continue;
|
||
}
|
||
if( hHandle->IsChild() )
|
||
{
|
||
continue;
|
||
}
|
||
if( hHandle->GetFrustumMask() )
|
||
{
|
||
hHandle->InitRender();
|
||
}
|
||
}
|
||
}
|
||
|
||
void CEtObject::RenderObjectList( int nMask )
|
||
{
|
||
ScopeLock<CSyncLock> Lock( s_SmartPtrLock );
|
||
|
||
int i, nCount;
|
||
|
||
nCount = GetItemCount();
|
||
for( i = 0; i < nCount; i++ )
|
||
{
|
||
EtObjectHandle hHandle;
|
||
hHandle = GetItem( i );
|
||
if( !hHandle )
|
||
{
|
||
continue;
|
||
}
|
||
if( hHandle->GetRenderType() != CT_SCREEN )
|
||
{
|
||
continue;
|
||
}
|
||
if( hHandle->GetFrustumMask() & nMask )
|
||
{
|
||
hHandle->Render();
|
||
}
|
||
}
|
||
}
|
||
|
||
void CEtObject::RenderShadowObjectList( int nMask, float fShadowRange )
|
||
{
|
||
int i, nCount;
|
||
CEtConvexVolume Frustum;
|
||
EtMatrix ProjMat;
|
||
EtCameraHandle hCamera;
|
||
|
||
hCamera = CEtCamera::GetActiveCamera();
|
||
EtMatrixPerspectiveFovLH( &ProjMat, hCamera->GetFOV(), hCamera->GetAspectRatio(), hCamera->GetCameraNear(), fShadowRange );
|
||
EtMatrixMultiply( &ProjMat, hCamera->GetViewMat(), &ProjMat );
|
||
Frustum.Initialize( ProjMat );
|
||
|
||
ScopeLock<CSyncLock> Lock( s_SmartPtrLock );
|
||
|
||
nCount = GetItemCount();
|
||
for( i = 0; i < nCount; i++ )
|
||
{
|
||
EtObjectHandle hHandle = GetItem( i );
|
||
if( !hHandle )
|
||
{
|
||
continue;
|
||
}
|
||
if( hHandle->GetRenderType() != CT_SCREEN )
|
||
{
|
||
continue;
|
||
}
|
||
if( ( hHandle->GetFrustumMask() & nMask ) && ( hHandle->IsShadowCast() ) && ( hHandle->GetObjectAlpha() > 0.5f ) )
|
||
{
|
||
EtVector3 Origin, Extent;
|
||
|
||
hHandle->GetExtent( Origin, Extent );
|
||
if( ( !hHandle->IsEnableCull() ) || Frustum.TesToBox( Origin, Extent ) )
|
||
{
|
||
hHandle->RenderShadow();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
void CEtObject::DrawCollisionList( int nMask )
|
||
{
|
||
if( m_bSkipDrawCollision ) { // 그려지는것이 하나도 없다면 쓸데없이 루프를 도는 것을 피한다.
|
||
return;
|
||
}
|
||
|
||
ScopeLock<CSyncLock> Lock( s_SmartPtrLock );
|
||
|
||
int i, nCount;
|
||
nCount = GetItemCount();
|
||
bool bDraw = false;
|
||
for( i = 0; i < nCount; i++ )
|
||
{
|
||
EtObjectHandle hHandle;
|
||
hHandle = GetItem( i );
|
||
if( !hHandle )
|
||
{
|
||
continue;
|
||
}
|
||
if( hHandle->GetRenderType() != CT_SCREEN )
|
||
{
|
||
continue;
|
||
}
|
||
if( hHandle->IsShowCollisionPrimitive() ) bDraw = true;
|
||
if( hHandle->GetFrustumMask() & nMask )
|
||
{
|
||
hHandle->DrawCollisionPrimitive();
|
||
}
|
||
}
|
||
|
||
if( !bDraw ) {
|
||
m_bSkipDrawCollision = true;
|
||
}
|
||
}
|
||
|
||
void CEtObject::CalcLightInfluence()
|
||
{
|
||
if( !m_bUpdateNeeded ) {
|
||
return;
|
||
}
|
||
|
||
m_vecInfluenceLight.clear();
|
||
CEtLight::CalcLightInfluence( m_BoundingSphere, m_vecInfluenceLight, m_MySmartPtr );
|
||
|
||
struct CompareFunc {
|
||
EtVector3 m_vOffset;
|
||
CompareFunc( EtVector3 &vOffset ) : m_vOffset(vOffset) {}
|
||
bool operator () ( CEtLight *pLight1, CEtLight *pLight2 ) const
|
||
{
|
||
float fLength1 = EtVec3LengthSq( &EtVector3( pLight1->GetLightInfo()->Position - m_vOffset ) );
|
||
float fLength2 = EtVec3LengthSq( &EtVector3( pLight2->GetLightInfo()->Position - m_vOffset ) );
|
||
return fLength1 < fLength2;
|
||
}
|
||
};
|
||
|
||
std::sort( m_vecInfluenceLight.begin(), m_vecInfluenceLight.end(), CompareFunc( m_BoundingSphere.Center ) );
|
||
|
||
int nMaxLightCount = MAX_POINT_LIGHT_COUNT + MAX_SPOT_LIGHT_COUNT - 1;
|
||
if( ( int )m_vecInfluenceLight.size() > nMaxLightCount )
|
||
{
|
||
m_vecInfluenceLight.erase( m_vecInfluenceLight.begin() + nMaxLightCount, m_vecInfluenceLight.end() );
|
||
}
|
||
}
|
||
|
||
void CEtObject::CalcLightInfluenceList( bool bForce )
|
||
{
|
||
ScopeLock<CSyncLock> Lock( s_SmartPtrLock );
|
||
|
||
int i, nCount;
|
||
|
||
nCount = GetItemCount();
|
||
for( i = 0; i < nCount; i++ )
|
||
{
|
||
EtObjectHandle hHandle;
|
||
hHandle = GetItem( i );
|
||
if( !hHandle )
|
||
{
|
||
continue;
|
||
}
|
||
if( bForce ) hHandle->SetUpdateNeeded( true );
|
||
hHandle->CalcLightInfluence();
|
||
}
|
||
}
|
||
|
||
void CEtObject::CalcLightMapInfluence()
|
||
{
|
||
if( m_pSkinInstance )
|
||
{
|
||
if( m_bLightMapInfluence )
|
||
{
|
||
if( m_bUpdateNeeded ) {
|
||
float fInfluence = CEtTerrainArea::CalcLightMapInfluence( m_WorldMat._41, m_WorldMat._43 );
|
||
m_pSkinInstance->SetDirLightAttenuation( fInfluence );
|
||
}
|
||
}
|
||
else
|
||
{
|
||
m_pSkinInstance->SetDirLightAttenuation( 1.0f );
|
||
}
|
||
}
|
||
}
|
||
|
||
void CEtObject::RecalcLightMapInfluence()
|
||
{
|
||
ScopeLock<CSyncLock> Lock( s_SmartPtrLock );
|
||
|
||
int i, nCount;
|
||
|
||
nCount = GetItemCount();
|
||
for( i = 0; i < nCount; i++ )
|
||
{
|
||
EtObjectHandle hHandle;
|
||
hHandle = GetItem( i );
|
||
if( !hHandle )
|
||
{
|
||
continue;
|
||
}
|
||
hHandle->SetUpdateNeeded( true );
|
||
hHandle->CalcLightMapInfluence();
|
||
}
|
||
}
|
||
|
||
void CEtObject::SetWorldSize( EtVector3 &WorldCenter, float fRadius )
|
||
{
|
||
CEtLight::SetWorldSize( WorldCenter, fRadius );
|
||
s_pDynamicOctree->Initialize( WorldCenter, fRadius );
|
||
|
||
int i, nItemCount;
|
||
|
||
ScopeLock<CSyncLock> Lock( s_SmartPtrLock );
|
||
|
||
nItemCount = GetItemCount();
|
||
for( i = 0; i < nItemCount; i++ )
|
||
{
|
||
EtObjectHandle hHandle;
|
||
hHandle = GetItem( i );
|
||
if( !hHandle )
|
||
{
|
||
continue;
|
||
}
|
||
hHandle->m_pCurOctreeNode = NULL;
|
||
}
|
||
}
|
||
|
||
EtObjectHandle CEtObject::Pick( int nX, int nY, int nCameraIndex )
|
||
{
|
||
CEtObject *pPickObject;
|
||
EtVector3 Position, Direction;
|
||
|
||
CEtCamera::GetItem( nCameraIndex )->CalcPositionAndDir( nX, nY, Position, Direction );
|
||
pPickObject = NULL;
|
||
s_pDynamicOctree->Pick( Position, Direction, pPickObject );
|
||
if( pPickObject )
|
||
{
|
||
return pPickObject->GetMySmartPtr();
|
||
}
|
||
else
|
||
{
|
||
EtObjectHandle Identity;
|
||
return Identity;
|
||
}
|
||
}
|
||
|
||
void CEtObject::OnLoadComplete( CBackgroundLoader *pLoader )
|
||
{
|
||
CommonInitialize();
|
||
RecalcBoundingBox();
|
||
RecalcBoundingSphere();
|
||
Update( &m_WorldMat );
|
||
|
||
CBackgroundLoaderCallback::OnLoadComplete( pLoader );
|
||
}
|
||
|
||
void CEtObject::AddCollisionMeshToKdTree()
|
||
{
|
||
if( ( !m_hSkin ) || ( ( m_nCollisionGroup & COLLISION_TYPE_STATIC ) == 0 ) )
|
||
{
|
||
return;
|
||
}
|
||
|
||
int i;
|
||
EtMeshHandle hMesh;
|
||
|
||
hMesh = m_hSkin->GetMeshHandle();
|
||
if( hMesh )
|
||
{
|
||
for( i = 0; i < hMesh->GetCollisionPrimitiveCount(); i++ )
|
||
{
|
||
CEtCollisionMng::GetInstance().AddCollisionMeshToKdTree( *( *hMesh->GetCollisionPrimitive() )[ i ], m_WorldMat, m_vScale );
|
||
}
|
||
}
|
||
}
|
||
|
||
void CEtObject::BuildKdTree()
|
||
{
|
||
int i, nCount;
|
||
|
||
CEtCollisionMng::GetInstance().Clear();
|
||
|
||
ScopeLock<CSyncLock> Lock( s_SmartPtrLock );
|
||
|
||
nCount = GetItemCount();
|
||
for( i = 0; i < nCount; i++ )
|
||
{
|
||
EtObjectHandle hHandle;
|
||
|
||
hHandle = GetItem( i );
|
||
if( hHandle )
|
||
{
|
||
if( !hHandle->IsEnableCollision() ) {
|
||
continue;
|
||
}
|
||
hHandle->UpdateCollisionPrimitive( *hHandle->GetWorldMat() );
|
||
hHandle->AddCollisionMeshToKdTree();
|
||
}
|
||
}
|
||
CEtCollisionMng::GetInstance().BuildCollisionTree();
|
||
} |