Files
2026-06-01 12:46:52 +02:00

2005 lines
53 KiB
C++

#include "stdafx.h"
#include "KViewport.h"
#include "KRenderObjectMesh.h"
#include "KSeqForm.h"
#include "KSeqAvatar.h"
#include "KSeqAvatarEx.h"
#include "KSeqModel.h"
#include "TerrainDefine.h"
#include "TerrainProp.h"
#include "TerrainPropInfo.h"
#include <mmo/ArTime.h>
//#include "Util.h"
#include "KSeqSpeedTree.h"
#include "SSpeedTreeManager.h"
#include "SCobManager.h"
#include "KRenderObjectEtc.h"
#include <toolkit/XStringUtil.h>
#include <kfile/KFileManager.h>
#include <list>
/// 2010.11.10 - prodongi
#include "SItemDB.h"
#include "SGameLobbyDefine.h"
//#include "SDebug_Util.h"
namespace
{
const char* c_szDefault = "default";
const char* c_szDefaultLod01 = "default_lod01";
const char* c_szCollisionCube = "ev_3dcol";
const char* c_szAttributeCube = "ev_attr";
const float c_fDummyCubeHalfLength = 1.f;
template< typename T >
T& findname( T& a, T& b, const char* szName )
{
while( a != b )
{
if( strcmp( (*a)->GetName(), szName ) == 0 )
{
return a;
}
++a;
}
return b;
}
};
float CTerrainProp::m_fLodMax = 1.0f;
float CTerrainProp::m_fLodDist = 1.0f;
bool CTerrainProp::m_bHeightRender = false;
bool CTerrainProp::m_bSetSkipVisibility = false;
bool CTerrainProp::m_bCameraCollisionRender = false; // [sonador][COLLIDABLE_CAMERA]
float CTerrainProp::m_fCameraCollisionVisibility = 0.5f; // [sonador][7.1.5]테스트용 클라이언트 제작 및 충돌 프랍 투명화 적용
float CTerrainProp::m_fGrassVisRange = 1.0f;
float CTerrainProp::m_fSpeedTreeVisRange = 1.0f;
float CTerrainProp::m_fPropSmallVisRange = 1.0f;
float CTerrainProp::m_fPropLargeVisRange = 1.0f;
float CTerrainProp::m_fBuildingSmallVisRange = 1.0f;
float CTerrainProp::m_fBuildingLargeVisRange = 1.0f;
volatile bool CTerrainProp::s_bStopThread = false;
static XCriticalSection s_propLoadingLock;
static std::list< CTerrainProp* > s_lstThreadLoadingProp;
namespace
{
struct PropTri
{
X2D::Point<float> v[3];
float z[3]; //높이
K3DPlane plane; //접선의 방정식 -_-
};
template< typename T >
inline bool COLLISION( const PropTri& lh, const X2D::Point<T>& rh )
{
X2D::CCW_RESULT ret = X2D::CheckClockWise(lh.v[0], lh.v[1], rh);
return ret == X2D::CheckClockWise(lh.v[1], lh.v[2], rh) && ret == X2D::CheckClockWise(lh.v[2], lh.v[0], rh);
}
template< typename T >
inline bool COLLISION( const X2D::Rect<T>& lh, const PropTri& rh )
{
// 하나라도 안에 있으면
for(size_t i = 0; i < 3; ++i)
{
if(lh.IsCollision(rh.v[i]) )
return true;
X2D::Line<float> line(rh.v[i%3], rh.v[(i+1)%3] );
if(lh.IsCollision(line))
return true;
}
X2D::Point<float> pt[4];
pt[0].x = lh.GetLeft(); pt[0].y = lh.GetTop();
pt[1].x = lh.GetLeft(); pt[1].y = lh.GetBottom();
pt[2].x = lh.GetRight(); pt[2].y = lh.GetTop();
pt[3].x = lh.GetRight(); pt[3].y = lh.GetBottom();
for(size_t i = 0; i < 4; ++i)
{
if(COLLISION(rh, pt[i]) )
return true;
}
return false;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// STriangleIndex Implement
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class STriangleIndex
{
public:
STriangleIndex(float left, float top, float width, float height, size_t triSize, size_t numOfTesselX = 0, size_t numOfTesselY = 0)
: m_Area(left,top,width,height)
{
m_NumOfTesselX = numOfTesselX;
m_NumOfTesselY = numOfTesselY;
if(m_NumOfTesselX == 0 && m_NumOfTesselY == 0)
{
m_NumOfTesselX = static_cast<size_t>( ::sqrtf(static_cast<float>(triSize) ) );
m_NumOfTesselY = triSize / m_NumOfTesselX;
}
m_ppBlock = new triVector*[m_NumOfTesselY];
for(size_t i = 0; i < m_NumOfTesselY; ++i)
{
m_ppBlock[i] = new triVector[m_NumOfTesselX];
}
m_WidthUnit = m_Area.GetWidth() / m_NumOfTesselX;
m_HeightUnit = m_Area.GetHeight() / m_NumOfTesselY;
}
~STriangleIndex()
{
for(size_t i = 0; i < m_NumOfTesselY; ++i)
{
SAFE_DELETE_ARRAY(m_ppBlock[i]);
}
SAFE_DELETE_ARRAY(m_ppBlock);
}
void AddTri(const PropTri& tri)
{
bool bColision = false;
for(size_t y = 0; y < m_NumOfTesselY; ++y)
{
for(size_t x = 0; x < m_NumOfTesselX; ++x)
{
X2D::Rect<float> rect;
rect.Set(m_Area.GetLeft() + m_WidthUnit * x, m_Area.GetTop() + m_HeightUnit * y, m_WidthUnit, m_HeightUnit);
if( COLLISION(rect, tri) )
{
m_ppBlock[y][x].push_back(tri);
bColision = true;
}
}
}
//if(false == bColision)
// _oprint("Cannot Add Tri : [0] (%.3f, %.3f), [1] (%.3f, %.3f), [2] (%.3f, %.3f)\n", tri.v[0].x,tri.v[0].y,
// tri.v[1].x,tri.v[1].y, tri.v[2].x,tri.v[2].y);
}
void GetCollisionTriList(float x, float y, std::vector<PropTri*>* pTriVector)
{
float offsetX = x - m_Area.GetLeft();
float offsetY = y - m_Area.GetTop();
int blockX = static_cast<int>( offsetX / m_WidthUnit );
int blockY = static_cast<int>( offsetY / m_HeightUnit );
// 오버플로 방지
if( blockY > m_NumOfTesselY-1 )
blockY = m_NumOfTesselY-1;
if( blockX > m_NumOfTesselX-1 )
blockX = m_NumOfTesselX-1;
triVector& tris = m_ppBlock[blockY][blockX];
X2D::Point<float> pt(x,y);
for(size_t i = 0; i < tris.size(); ++i)
{
if( COLLISION(tris[i], pt))
pTriVector->push_back( &(tris[i]));
}
//if( 0 != HIBYTE(GetAsyncKeyState(VK_LMENU)) )
// _oprint("Count is %d, Find is %d\n", tris.size(), pTriVector->size() );
}
private:
size_t m_NumOfTesselX, m_NumOfTesselY;
X2D::Rect<float> m_Area;
float m_WidthUnit;
float m_HeightUnit;
typedef std::vector<PropTri> triVector;
triVector** m_ppBlock;
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CTerrainProp Implement
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void CTerrainProp::removeFromLoadingList()
{
THREAD_SYNCRONIZE( s_propLoadingLock );
if( !m_bIsThreadPending ) return;
std::list< CTerrainProp* >::iterator it;
for( it = s_lstThreadLoadingProp.begin(); it != s_lstThreadLoadingProp.end(); ++it )
{
if( *it == this )
{
s_lstThreadLoadingProp.erase( it );
return;
}
}
}
void CTerrainProp::addToLoadingList()
{
THREAD_SYNCRONIZE( s_propLoadingLock );
if( m_bIsRealLoad ) return;
#ifdef _DEBUG
std::list< CTerrainProp* >::iterator it;
for( it = s_lstThreadLoadingProp.begin(); it != s_lstThreadLoadingProp.end(); ++it )
{
if( *it == this )
{
assert( 0 );
return;
}
}
#endif
m_bIsThreadPending = true;
s_lstThreadLoadingProp.push_back( this );
}
void CTerrainProp::PendLoading()
{
if( m_bIsThreadPending ) return;
addToLoadingList();
}
unsigned int __stdcall CTerrainProp::prop_loader( void* pArg )
{
while( !s_bStopThread )
{
CTerrainProp *pProp = NULL;
{
s_propLoadingLock.Lock();
if( s_lstThreadLoadingProp.empty() )
{
s_propLoadingLock.UnLock();
Sleep( 100 );
continue;
}
pProp = s_lstThreadLoadingProp.front();
s_lstThreadLoadingProp.pop_front();
pProp->StartThreadLoading();
s_propLoadingLock.UnLock();
}
pProp->Load_Real( true );
}
s_bStopThread = false;
return 0;
}
void CTerrainProp::BeginPropLoadingThread()
{
unsigned dwThreadID;
HANDLE hThread = reinterpret_cast< HANDLE >( _beginthreadex( NULL, 0, CTerrainProp::prop_loader, NULL, 0, &dwThreadID ) );
CloseHandle( hThread );
}
void CTerrainProp::EndPropLoadingThread()
{
_oprint( "**THREAD INFO : CTerrainProp::EndPropLoadingThread\n" );
s_bStopThread = true;
while( s_bStopThread ) Sleep( 1 );
}
CTerrainProp::CTerrainProp( const K3DVector& rPos, const K3DVector& rRotate, const K3DVector& rScale, float fZOffset, WORD wPropNum, const CTerrainPropInfo* pPropInfo, bool bLockHeight ,
int segmentIdx, int propIdx, bool bEnableLightmap, short texturegroupindex )
: m_Pos( rPos )
, m_Rotate( rRotate )
, m_Scale( rScale )
, m_fZOffset( fZOffset )
, m_wPropNum( wPropNum )
, m_pModel( NULL )
, m_pBoundCube( NULL )
, m_pOriginCorrection( NULL )
, m_ptCurrentOriginCorrection( K3DVertex( 0.f, 0.f, 0.f ) )
, m_fVisibility( 1.f )
, m_nLodLevel( 0 )
, m_bLodExist( false )
//, m_bVisible(false)
//, m_bDrawTestWire(true)
, m_bDrawTestWire( false ) // [sonador][COLLIDABLE_CAMERA]
//, m_bTestWireCreated(false)
, m_bTestWireCreated( true ) // [sonador][COLLIDABLE_CAMERA]
, m_bIsThreadPending( false )
, m_bIsThreadLoading( false )
, m_pIndexTri(NULL)
, m_bLockHeight( bLockHeight )
, m_segmentIdx(segmentIdx)
, m_propIdx(propIdx)
, m_bEnableLightmap(bEnableLightmap)
, m_pCameraCollision( NULL )
, m_nTextureGroupIndex( texturegroupindex )
{
m_bIsClip = false;
m_bIsRealLoad = false;
m_pModelHeight = NULL;
//test
m_dwTime = 0;
UpdateTransform();
switch( pPropInfo->GetPropRenderType( m_wPropNum ) )
{
default:
case CTerrainPropInfo::PROPRENDER_GENERAL: m_nRenderType = KRenderObject::RENDEREFX_PROP; break;
case CTerrainPropInfo::PROPRENDER_BUILDING: m_nRenderType = KRenderObject::RENDEREFX_BUILDING; break;
}
m_nShadowFlag = pPropInfo->GetShadowFlag( m_wPropNum );
m_nRenderFlag = MAKELONG( m_nRenderType, m_nShadowFlag );
//#ifndef NDEBUG
m_strFileName = pPropInfo->GetPropFileName( m_wPropNum ); //화일 이름, 디버그 용
//#endif
// _oprint( "PROP_INFO : %d, %s\n", m_wPropNum, pPropInfo->GetPropFileName( m_wPropNum ) );
if( true )
{
LoadCOB( m_strFileName.c_str(), m_matTransform );
//case CTerrainPropInfo::PROP_USE_NX3:
// {
// std::string strFileName = pPropInfo->GetPropFileName( m_wPropNum );
// m_pModel = CreateNAFModel( strFileName.c_str() );
// //건물일 경우 _lod%d 를 추가해서 읽는다. 현재 단계는 _lod01 까지 만들어져 있다.
// if( m_nRenderType == KRenderObject::RENDEREFX_BUILDING ||
// m_nRenderType == KRenderObject::RENDEREFX_BUILDING_HAS_STOOL )
// {
// XStringUtil::Replace( strFileName, ".", "_lod01." );
// if ( KFileManager::Instance().IsValidResource( strFileName.c_str() ) )
// {
// m_pModel->AddAnimation( c_szDefaultLod01, strFileName.c_str() );
// m_bLodExist = true;
// }
// }
// }
// break;
//case CTerrainPropInfo::PROP_SPEEDTREE:
// {
// K3DMatrix mat;
// m_pModel = CreateSpeedTreeModel( pPropInfo->GetPropFileName( m_wPropNum ), m_matTransform );
// }
// break;
////.cob 화일 읽는 곳
//case CTerrainPropInfo::PROP_NPC:
// m_pModel = CreateNPCModel( pPropInfo->GetPropFileName( m_wPropNum ) );
// m_pModel->SetTransform( m_matTransform ); //KAvatarSeqEx 의 버그 때문에 넣은 것임. KAvatarSeqEx의 SetParentTransform 이 제대로 안됨.
// break;
// }
}
//if( NULL == m_pModel )
// m_pBoundCube = CreateDummyBoundCube();
RefreshAllTransform();
// CreateStools();
SetVisibility( 1.f );
}
CTerrainProp::~CTerrainProp()
{
Destroy();
}
void CTerrainProp::Destroy()
{
// 운나쁘게 쓰레드 로딩 중이라면 로딩 끝날때까지 기다림
while( m_bIsThreadLoading )
{
Sleep( 50 );
}
removeFromLoadingList();
SAFE_DELETE( m_pBoundCube );
SAFE_DELETE( m_pModel );
SAFE_DELETE( m_pModelHeight );
SAFE_DELETE( m_pIndexTri);
SAFE_DELETE( m_pCameraCollision );
iterator_texture_group_list itTextureGroup = m_vTextureGroupData.begin();
while( itTextureGroup != m_vTextureGroupData.end() )
{
SAFE_DELETE( (*itTextureGroup) );
itTextureGroup = m_vTextureGroupData.erase( itTextureGroup );
}
}
bool CTerrainProp::IsSizeCull()
{
if( m_pBoundCube )
{
const K3DVertex* pCube = m_pBoundCube->GetVertices();
K3DVertex cubeValue = pCube[7]-pCube[0];
//기본 플레이어 캐릭터의 크기는 20
if( cubeValue.x > 200 || cubeValue.y > 200 || cubeValue.z > 200 )
return false;
}
return true;
}
void CTerrainProp::SetVisibility( float fVisible )
{
if( m_bSetSkipVisibility ) return;
if( fVisible < 0.f ) fVisible = 0.f;
if( fVisible > 1.f ) fVisible = 1.f;
m_fVisibility = fVisible;
if( NULL != m_pModel )
{
m_pModel->SetVisibility( m_fVisibility );
// m_pModel->SetLodLevel( m_fVisibility );
}
}
// 스피드 트리만 쓰고 있음
void CTerrainProp::SetFloatLod(float fCameraDist, float fVisRange)
{
bool bLongDist = false;
fVisRange *= m_fLodDist;
if ( fVisRange > 800.0f && m_fLodDist < 1.0f )
{
fVisRange = 800.0f;
bLongDist = true;
}
float fLod = 1.0f - (fCameraDist / fVisRange);
if( bLongDist )
fLod *= 0.1f;
if (fLod < 0.0f) fLod = 0.0f;
//스피드 트리 버그 관련 수정
// lod 레벨 0-1.0 사이로 고정
//2009-12-23 : hunee
//if (fLod > m_fLodMax) fLod = m_fLodMax;
if (fLod > 1.0f) fLod = 1.0f;
if(m_pModel)
{
m_pModel->SetLodLevel(fLod);
}
}
//void CTerrainProp::SetVisible(float fCameraDist, float fVisRange)
//{
// float fRatio = 0.0f;
//
// switch(m_dwPropCategory)
// {
// case TYPE_GRASS:
// fRatio = m_fGrassVisRange;
// break;
//
// case TYPE_SPEEDTREE:
// fRatio = m_fSpeedTreeVisRange;
// break;
//
// case TYPE_PROPSMALL:
// fRatio = m_fPropSmallVisRange;
// break;
//
// case TYPE_PROPLARGE:
// fRatio = m_fPropLargeVisRange;
// break;
//
// case TYPE_NPC:
// break;
//
// case TYPE_BUILDINGSMALL:
// fRatio = m_fBuildingSmallVisRange;
// break;
//
// case TYPE_BUILDINGLARGE:
// fRatio = m_fBuildingLargeVisRange;
// break;
//
// default:
// assert(0 && "잘못된 프랍 타입");
// break;
// }
//
// if(fCameraDist < fVisRange * fRatio) m_bVisible = true;
// else m_bVisible = false;
//}
void CTerrainProp::SetGrassVisRange(float fRange)
{
m_fGrassVisRange = fRange;
}
void CTerrainProp::SetSpeedTreeVisRange(float fRange)
{
m_fSpeedTreeVisRange = fRange;
}
void CTerrainProp::SetPropSmallVisRange(float fRange)
{
m_fPropSmallVisRange = fRange;
}
void CTerrainProp::SetPropLargeVisRange(float fRange)
{
m_fPropLargeVisRange = fRange;
}
//void CTerrainProp::SetNpcVisRange(float fRange)
//{
// m_fNpcVisRange = fRange;
//}
void CTerrainProp::SetBuildingSmallVisRange(float fRange)
{
m_fBuildingSmallVisRange = fRange;
}
void CTerrainProp::SetBuildingLargeVisRange(float fRange)
{
m_fBuildingLargeVisRange = fRange;
}
float CTerrainProp::GetVisRatio()
{
float fRatio = 1.0f;
switch(m_dwPropCategory)
{
case TYPE_GRASS:
fRatio = m_fGrassVisRange;
break;
case TYPE_SPEEDTREE:
fRatio = m_fSpeedTreeVisRange;
break;
case TYPE_PROPSMALL:
fRatio = m_fPropSmallVisRange;
break;
case TYPE_PROPLARGE:
fRatio = m_fPropLargeVisRange;
break;
case TYPE_NPC:
break;
case TYPE_BUILDINGSMALL:
fRatio = m_fBuildingSmallVisRange;
break;
case TYPE_BUILDINGLARGE:
fRatio = m_fBuildingLargeVisRange;
break;
default:
//assert(0 && "잘못된 프랍 타입"); - 임시로 없앤다. 나중에 타입이 제대로 들어오면 다시 살릴 것. by blackfish
break;
}
return fRatio;
}
void CTerrainProp::SetLodLevel( int nLevel )
{
if( !m_pModel ) return;
if( nLevel < 0 ) nLevel = 0;
if( nLevel > 1 ) nLevel = 1;
if( m_nLodLevel != nLevel )
{
m_nLodLevel = nLevel;
if( m_nRenderType == KRenderObject::RENDEREFX_BUILDING ||
m_nRenderType == KRenderObject::RENDEREFX_BUILDING_HAS_STOOL )
{
if( IsLodExist() )
{
//_oprint( "Building LOD Level : %d\n", m_nLodLevel );
switch( m_nLodLevel )
{
default:
case 0: m_pModel->PlayAnimation( GetSafeTickCount(), c_szDefault, KSeqModel::SEQTYPE_LOOP ); break;
case 1: m_pModel->PlayAnimation( GetSafeTickCount(), c_szDefaultLod01, KSeqModel::SEQTYPE_LOOP ); break;
}
}
}
}
}
int CTerrainProp::Process( DWORD dwTime )
{
if( !m_bIsRealLoad ) return true;
if( m_dwTime == dwTime ) return true;
m_dwTime = dwTime;
//if( NULL != m_pOriginCorrection )
//{
// if( m_ptCurrentOriginCorrection != *m_pOriginCorrection )
// {
// m_ptCurrentOriginCorrection = *m_pOriginCorrection;
// UpdateCorrectedTransform();
// }
//}
return (NULL != m_pModel) ? m_pModel->Process( dwTime ) : KSeqForm::SEQINFO_NOP;
}
const K3DBoundRotCube* CTerrainProp::GetBoundCube() const
{
// if( m_pModel ) return m_pModel->GetBoundCube();
return m_pBoundCube;
}
// { [sonador][COLLIDABLE_CAMERA]
bool CTerrainProp::CheckPolygonCollisionWithCollisionMesh
( const K3DVector& rayStart
, const K3DVector& rayEnd
, float& fNearestT
, K3DVector& vCollidedPoint
#ifdef _DEBUG
, K3DVector* pCollidedPolygon
#endif
)
{
if( m_CameraCollisionResource.empty( ) ) return 1.0f;
if( ( (int)m_CameraCollisionResource.size( ) % 3 ) != 0 ) return 1.0f;
K3DVector vCandidateCollidedPoint, vTempCollidedPoint, vRay;
vRay = rayEnd - rayStart;
bool bFound = false;
float fT = 1.0f;
std::vector< K3DVector >::iterator it = m_CameraCollisionResource.begin( ), itEnd = m_CameraCollisionResource.end( );
for( ; it != itEnd; )
{
K3DVector& v1 = *it++;
K3DVector& v2 = *it++;
K3DVector& v3 = *it++;
K3DVector tv1, tv2, tv3, tvNormal;
K3DVectorTransform( tv1, v1, m_matTransform );
K3DVectorTransform( tv2, v2, m_matTransform );
K3DVectorTransform( tv3, v3, m_matTransform );
K3DVectorCross( tvNormal, tv3 - tv1, tv2 - tv1 );
if(!m_bTestWireCreated)
{
K3DVector vPolygonNormal( tvNormal.x, tvNormal.y, tvNormal.z ), vWeightCenter;
vPolygonNormal.Normalize( 30 );
vWeightCenter = ( tv1 + tv2 + tv3 ) / 3;
m_prTestWire.AddLine( tv1, tv2, KColor(0,0,0,255) );
m_prTestWire.AddLine( tv2, tv3, KColor(0,0,0,255) );
m_prTestWire.AddLine( tv3, tv1, KColor(0,0,0,255) );
m_prTestWire.AddLine( vWeightCenter, vWeightCenter + vPolygonNormal, KColor(0,0,255,255) );
}
if( K3DVectorDot( vRay, tvNormal ) < 0.f ) // 은면제거
{
fT = KPCCP::triangle_collide_edge_twosides(
tv1, tv2, tv3, rayStart, rayEnd, vTempCollidedPoint );
if( fNearestT > fT )
{
bFound = true;
fNearestT = fT;
vCandidateCollidedPoint = vTempCollidedPoint;
#ifdef _DEBUG
pCollidedPolygon[ 0 ] = tv1;
pCollidedPolygon[ 1 ] = tv2;
pCollidedPolygon[ 2 ] = tv3;
#endif
}
}
}
m_bTestWireCreated = true;
if( bFound )
{
vCollidedPoint = vCandidateCollidedPoint;
}
return bFound;
}
// }
// { [sonador][7.1.7]충돌 처리 개선(Swept Shpere Collision Detection)
bool CTerrainProp::CheckPolygonEllipsoidCollisionWithCollisionMesh
( const K3DVector& rayStart
, const K3DVector& rayEnd
, const K3DMatrix& matCBM
, float& fNearestT
, K3DVector& vCollidedPoint
#ifdef _DEBUG
, K3DVector* pCollidedPolygon
#endif
)
{
// 모든 파라메터는 ellipsoid vecter space 에 놓여있다고 가정된 구현 코드입니다!!!
if( m_CameraCollisionResource.empty( ) ) return 1.0f;
if( ( (int)m_CameraCollisionResource.size( ) % 3 ) != 0 ) return 1.0f;
K3DVector vCandidateCollidedPoint, vRay;
vRay = rayEnd - rayStart;
bool bFound = false;
float fT = 1.0f;
std::vector< K3DVector >::iterator it = m_CameraCollisionResource.begin( ), itEnd = m_CameraCollisionResource.end( );
for( ; it != itEnd; )
{
K3DMatrix matWorld;
K3DMatrixMultiply( matWorld, m_matTransform, matCBM );
K3DVector& v1 = *it++;
K3DVector& v2 = *it++;
K3DVector& v3 = *it++;
K3DVector tv1, tv2, tv3, tvNormal;
K3DVectorTransform( tv1, v1, matWorld );
K3DVectorTransform( tv2, v2, matWorld );
K3DVectorTransform( tv3, v3, matWorld );
K3DVectorCross( tvNormal, tv3 - tv1, tv2 - tv1 );
if(!m_bTestWireCreated)
{
K3DVector vPolygonNormal( tvNormal.x, tvNormal.y, tvNormal.z ),
vWeightCenter;
vPolygonNormal.Normalize( 30 );
vWeightCenter = ( tv1 + tv2 + tv3 ) / 3;
m_prTestWire.AddLine( tv1, tv2, KColor(0,0,0,255) );
m_prTestWire.AddLine( tv2, tv3, KColor(0,0,0,255) );
m_prTestWire.AddLine( tv3, tv1, KColor(0,0,0,255) );
m_prTestWire.AddLine(
vWeightCenter, vWeightCenter + vPolygonNormal, KColor(0,0,255,255) );
}
if( K3DVectorDot( vRay, tvNormal ) < 0.f ) // 은면제거
{
if( KPCCP::triangle_collide_swept_unit_sphere( tv1, tv2, tv3, rayStart, vRay, vCandidateCollidedPoint, fT ) && ( fNearestT > fT ) )
{
bFound = true;
fNearestT = fT;
vCollidedPoint = vCandidateCollidedPoint;
#ifdef _DEBUG
pCollidedPolygon[ 0 ] = tv1;
pCollidedPolygon[ 1 ] = tv2;
pCollidedPolygon[ 2 ] = tv3;
#endif
}
}
}
m_bTestWireCreated = true;
return bFound;
}
// }
float CTerrainProp::CheckPolygonCollision( const K3DVector& rNear, const K3DVector& rFar, K3DVector& rPickedPoint )
{
if(!m_pModel) return false;
_CID( GETMESH_VERTEXBUFFERS );
_CID( GETMESH_INDEXBUFFERS );
KMsgGET_MESHVERTEXBUFFERS msgGMVB;
m_pModel->Perform(id_GETMESH_VERTEXBUFFERS, msgGMVB);
KMsgGET_MESHINDEXBUFFERS msgGMIB;
m_pModel->Perform(id_GETMESH_INDEXBUFFERS, msgGMIB);
//float fDistance = 0.0f;
//float fOriginalDistance = Magnitude(K3DVector(rFar - rNear));
//float fSmallestDistance = fOriginalDistance;
K3DVector rCandidatePickedPoint, rTempPickedPoint;
int size = (int)msgGMVB.vVbStruct.size();
if(size != msgGMIB.vIbStruct.size())
{
assert(0);
}
float fT = 1.0f;
float fSmallestT = 1.0f;
for(int k = 0; k < size; k++)
{
if(msgGMVB.vVbStruct[k]->nVBCount != msgGMIB.vIbStruct[k]->nIBCount) continue;
for(int i = 0; i < msgGMVB.vVbStruct[k]->nVBCount; i++)
{
K3DVertexBufferDX* pVb = (K3DVertexBufferDX*) msgGMVB.vVbStruct[k]->pVBs[i];
K3DIndexBufferDX* pIb = (K3DIndexBufferDX*) msgGMIB.vIbStruct[k]->pIBs[i];
byte *pVtxData = NULL, *pIdxData = NULL;
int nVtxCount = pVb->GetVertexCount();
int nVtxStride = pVb->GetVertexStride();
int nIdxCount = pIb->GetIndexCount();
int nIdxFormat = pIb->GetFormat();
int crap;
//pVb->Lock((void**) &pVtxData, crap);
//pIb->Lock((void**) &pIdxData, crap);
//pVb->Lock((void**) &pVtxData, crap, D3DLOCK_READONLY);
//pIb->Lock((void**) &pIdxData, crap, D3DLOCK_READONLY);
pVb->Lock((void**) &pVtxData, crap, D3DLOCK_NOOVERWRITE);
assert(pVtxData && "pVb->Lock((void**) &pVtxData, crap, D3DLOCK_NOOVERWRITE);");
pIb->Lock((void**) &pIdxData, crap, D3DLOCK_NOOVERWRITE);
assert(pIdxData && "pIb->Lock((void**) &pIdxData, crap, D3DLOCK_NOOVERWRITE);");
unsigned short* pIdx16 = NULL;
unsigned int* pIdx32 = NULL;
K3DVertex v1, v2, v3;
K3DPlane plane;
for(int j = 0; j < nIdxCount / 3; j += 3)
{
if(nIdxFormat == D3DFMT_INDEX16)
{
pIdx16 = &((unsigned short*) pIdxData)[j];
v1 = *((K3DVertex*) (pVtxData + ((*pIdx16) * nVtxStride)));
++pIdx16;
v2 = *((K3DVertex*) (pVtxData + ((*pIdx16) * nVtxStride)));
++pIdx16;
v3 = *((K3DVertex*) (pVtxData + ((*pIdx16) * nVtxStride)));
++pIdx16;
}
else if(nIdxFormat == D3DFMT_INDEX32)
{
pIdx32 = &((unsigned int*) pIdxData)[j];
v1 = *((K3DVertex*) (pVtxData + ((*pIdx32) * nVtxStride)));
++pIdx32;
v2 = *((K3DVertex*) (pVtxData + ((*pIdx32) * nVtxStride)));
++pIdx32;
v3 = *((K3DVertex*) (pVtxData + ((*pIdx32) * nVtxStride)));
++pIdx32;
}
else
{
assert(0);
}
K3DVertex tv1, tv2, tv3;
K3DMatrix matRes;
K3DMatrixMultiply( matRes, msgGMVB.vVbStruct[k]->matLocal, m_matTransform );
K3DVectorTransform(tv1, v1, matRes);
K3DVectorTransform(tv2, v2, matRes);
K3DVectorTransform(tv3, v3, matRes);
//if(m_bDrawTestWire && !m_bTestWireCreated)
if(!m_bTestWireCreated)
{
m_prTestWire.AddLine( tv1, tv2, KColor(0,0,0,255) );
m_prTestWire.AddLine( tv2, tv3, KColor(0,0,0,255) );
m_prTestWire.AddLine( tv3, tv1, KColor(0,0,0,255) );
}
//if( KPCCP::triangle_collide_edge( tv1, tv2, tv3, rNear, rFar ) )
//{
// if( K3DPlaneFromPoints( &plane, &tv1, &tv2, &tv3 ) )
// {
// if( K3DPlaneIntersectLine( &rTempPickedPoint, &plane, &rNear, &rFar ) )
// {
// fT = Magnitude(rTempPickedPoint - rNear) / Magnitude(K3DVector(rFar - rNear));
// if(fSmallestT > fT)
// {
// fSmallestT = fT;
// rCandidatePickedPoint = rTempPickedPoint;
// }
// }
// }
//}
//if( KPCCP::triangle_collide_edge( tv1, tv3, tv2, rNear, rFar ) )
//{
// if( K3DPlaneFromPoints( &plane, &tv1, &tv3, &tv2 ) )
// {
// if( K3DPlaneIntersectLine( &rTempPickedPoint, &plane, &rNear, &rFar ) )
// {
// fT = Magnitude(rTempPickedPoint - rNear) / Magnitude(K3DVector(rFar - rNear));
// if(fSmallestT > fT)
// {
// fSmallestT = fT;
// rCandidatePickedPoint = rTempPickedPoint;
// }
// }
// }
//}
fT = KPCCP::triangle_collide_edge_twosides( tv1, tv2, tv3, rNear, rFar, rTempPickedPoint );
if( fSmallestT > fT )
{
fSmallestT = fT;
rCandidatePickedPoint = rTempPickedPoint;
}
}
pVb->Unlock();
pIb->Unlock();
}
}
m_bTestWireCreated = true;
if(fSmallestT < 1.0f)
{
rPickedPoint = rCandidatePickedPoint;
//return true;
}
//return false;
return fSmallestT;
}
void CTerrainProp::ClipTest( const K3DVector* pFrustum)
{
if( m_pBoundCube )
m_bIsClip = !KPCCP::nonuniformcube_collide_nonuniformcube(pFrustum, m_pBoundCube->GetVertices());
}
bool CTerrainProp::GetIsClip()
{
return m_bIsClip;
}
void CTerrainProp::Render( KViewportObject* pViewport )
{
//if(!m_bVisible) return;
if( !m_bIsRealLoad ) return;
//if( GetKeyState( VK_SCROLL ) > 0 )
//{
// for( TERRAINSTOOL_VECTOR::iterator itStool = m_StoolVector.begin(); itStool != m_StoolVector.end(); itStool++ )
// (*itStool).Render( pViewport );
//}
//else
//{
if( NULL != m_pModel )
{
if( m_fVisibility > 0.f )
{
m_pModel->Render( pViewport, m_nRenderFlag );
/// 2010.11.10 - prodongi
//#ifdef _DEV
if (g_UserInfo.isMonkeyTail())
{
// { 툴에서는 g_bDebugMode 는 무시해도 됨
extern bool g_bDebugMode;
if( g_bDebugMode && ( GetKeyState( VK_SCROLL ) & 0x0001 ) && ( GetKeyState( VK_SHIFT ) & 0x8000 ) )
{
if( m_pBoundCube ) m_pBoundCube->Render( pViewport );
}
}
//#endif
// }
}
}
if( m_bCameraCollisionRender )
{
if( m_pCameraCollision )
{
m_pCameraCollision->SetVisibility( m_fCameraCollisionVisibility ); //[sonador][7.1.5]테스트용 클라이언트 제작 및 충돌 프랍 투명화 적용
m_pCameraCollision->Render( pViewport );
}
}
//높이 화일
if( m_bHeightRender )
{
if( m_pModelHeight && m_fVisibility > 0.f )
{
if( m_pBoundCube ) m_pBoundCube->Render( pViewport );
m_pModelHeight->Render( pViewport, m_nRenderFlag );
pViewport->RegisterWire( &m_WirePrimitive );
}
}
//
if(m_bDrawTestWire)
{
pViewport->RegisterWire( &m_prTestWire );
}
}
bool CTerrainProp::IsLoadCompleted() const
{
if( m_pModel )
{
if( !m_pModel->IsLoadCompleted() )
_oprint( "CTerrainProp::IsLoadCompleted() m_pModel->IsLoadCompleted() == false %d\n", m_wPropNum );
// assert( false && "CTerrainProp::IsLoadCompleted() 리소스 파일을 찾을수 없기때문에 Render에서 제외됨 리소스 관리자에게 문의 하세요" );
}
else
{
_oprint( "CTerrainProp::IsLoadCompleted() m_pModel == NULL %d\n", m_wPropNum );
//assert( false && "CTerrainProp::IsLoadCompleted() m_pModel == NULL 리소스 관리자에게 문의 하세요" );
}
return true;
//nx3 파일 리소스가 존재 하지 않을시 로딩 화면에서 멈추는 현상이 발생될수 있음 - by metarrgear
/* if( m_pModel && m_pModel->IsLoadCompleted() == false )
{
m_pModel->TryPlayAnimation();
}
return (NULL != m_pModel) ? m_pModel->IsLoadCompleted() : true;*/
}
void CTerrainProp::GetAttrbuteCubes( std::vector<K3DBoundRotCube>& rCubeVector ) const
{
if( NULL != m_pModel )
{
// 속성 큐브를 구한다.
_CID( REQ_EVBOX );
KMsgREQ_EVBOX msg;
if( NULL != m_pModel->Perform( id_REQ_EVBOX, msg ) )
{
const K3DMatrix& rPropMatrix = m_matTransform;
int nBoxCount = msg.GetBoxCount();
for( int n( 0 ); n < nBoxCount; ++n )
{
KEventBoxSeq* pEvBoxSeq = msg.GetBox( n );
if( 0 == ::_stricmp( pEvBoxSeq->GetName(), c_szAttributeCube ) )
{
K3DBoundRotCube cube = pEvBoxSeq->GetCube();
cube.AddTransform( rPropMatrix );
rCubeVector.push_back( cube );
}
}
}
}
}
void CTerrainProp::Load_Real( bool bSlowLoad )
{
if( m_bIsRealLoad ) return;
//실제 보이는 프랍 로딩.
//높이 화일 우선 로딩 대상.
//Main 로딩 우선 순위 영향.
//Lod 로딩 우선 순위 영향.
struct _FlagRemover
{
_FlagRemover( volatile bool* volatile f ) : pFlag( f ) {}
~_FlagRemover() { *pFlag = false; }
volatile bool* volatile pFlag;
};
volatile _FlagRemover _remover01( &m_bIsThreadLoading );
volatile _FlagRemover _remover02( &m_bIsThreadPending );
if( m_strFileName.length() <= 0 )
{ //프랍 이름 없는 것들
m_bIsRealLoad = true;
return;
}
std::vector<COBSET *>* coblist = COBManager::GetManager()->Load( m_strFileName.c_str() );
if( coblist == NULL )
{
m_bIsRealLoad = true;
return;
}
if( bSlowLoad ) Sleep( 10 );
std::vector<COBSET *>::iterator it = coblist->begin();
if( it != coblist->end() )
{
COBSET * pPropSet = (*it);
//Prop 이 아니면 로딩 안 됨
if( pPropSet->nClan != GCLAN_PROP_NX3 &&
pPropSet->nClan != GCLAN_PROP_SPEED &&
pPropSet->nClan != GCLAN_PROP_COB )
{
m_bIsRealLoad = true;
return;
}
if( pPropSet->m_AniList.empty() ) return;
if( pPropSet->nClan == GCLAN_PROP_NX3 )
{
KSeqModel* pSeqNX3 = new KSeqModel;
pSeqNX3->Initialize();
NX3LoadPack loadpack;
loadpack.Init();
const char* nx3FileName = "";
for( unsigned int i(0); pPropSet->m_AniList.size()>i; i++ ) //NX3
{
nx3FileName = pPropSet->m_AniList[i].c_str();
pSeqNX3->AddAnimation( c_szDefault, nx3FileName, KNX3Manager::SEQTYPE_ALL, &loadpack );
break;
}
if( bSlowLoad ) Sleep( 1 );
for( unsigned int i(0); pPropSet->m_LodList.size()>i; i++ ) //Lod
{
pSeqNX3->AddAnimation( c_szDefaultLod01, pPropSet->m_LodList[i].strName.c_str(), KNX3Manager::SEQTYPE_ALL, &loadpack );
m_bLodExist = true;
break;
}
if( bSlowLoad ) Sleep( 1 );
if( !pSeqNX3->PlayAnimation( GetSafeTickCount(), c_szDefault, KSeqModel::SEQTYPE_LOOP ) )
{
SAFE_DELETE( pSeqNX3 );
SAFE_DELETE( m_pBoundCube );
m_pBoundCube = CreateDummyBoundCube();
m_bIsRealLoad = true;
return;
}
if( bSlowLoad ) Sleep( 1 );
m_pModel = pSeqNX3;
m_nx3FileName = nx3FileName;
// Lightmap Set
THREAD_SYNCRONIZE(m_LightmapSetLock);
_SetLightmap();
}
else if( pPropSet->nClan == GCLAN_PROP_SPEED )
{
for( unsigned int i(0); pPropSet->m_AniList.size()>i; i++ ) //Spt 화일
{
m_pModel = SpeedTreeManager::GetManager()->Load( pPropSet->m_AniList[i].c_str(), m_matTransform, m_matTransform._11 );
if( bSlowLoad ) Sleep( 1 );
break;
}
}
else if( pPropSet->nClan == GCLAN_PROP_COB )
{
KSeqAvatar* pSeqNAF = new KSeqAvatar;
pSeqNAF->Initialize();
for( unsigned int i(0); pPropSet->m_AniList.size()>i; i++ ) //Naf
{
pSeqNAF->AddAnimation( pPropSet->m_AniList[i].c_str(), TRUE );
break; //한개만 추가
}
if( bSlowLoad ) Sleep( 1 );
assert( pPropSet->m_MeshList.size() && "그래픽 리소스 에러 : Prop Mesh 가 없다." );
for( unsigned int i(0); pPropSet->m_MeshList.size()>i; i++ ) //NX3
{
pSeqNAF->AddMesh( MPART_HAIR, pPropSet->m_MeshList[i].c_str() );
break; //한개만 추가
}
if( bSlowLoad ) Sleep( 1 );
pSeqNAF->PlayAnimation( GetSafeTickCount(), c_szDefault, KSeqModel::SEQTYPE_LOOP );
if( bSlowLoad ) Sleep( 1 );
m_pModel = pSeqNAF;
}
else
assert( false && "pPropSet->nClan 알수없는 타입임" );
// { [sonador][COLLIDABLE_CAMERA]
if( pPropSet->m_strCameraCollisionFile.empty( ) || _stricmp( pPropSet->m_strCameraCollisionFile.c_str(), "empty" ) == 0 )
{
//cob에 cacol이 저장되있지 않다면 수동으로 ㅡ.,ㅡ
pPropSet->m_strCameraCollisionFile = m_strFileName;
size_t pos = pPropSet->m_strCameraCollisionFile.find( "." );
if(pos > 0 )
{
pPropSet->m_strCameraCollisionFile.erase( pos, 4 );
pPropSet->m_strCameraCollisionFile += "_cacol.nx3";
}
}
// }
if( pPropSet->m_strCameraCollisionFile.length() > 0 && _stricmp( pPropSet->m_strCameraCollisionFile.c_str(), "empty" ) != 0 ) //카메라 충돌용 메쉬
{
SAFE_DELETE( m_pCameraCollision );
KSeqModel* pSeqNX3 = new KSeqModel;
pSeqNX3->Initialize();
NX3LoadPack loadpack;
loadpack.Init();
pSeqNX3->AddAnimation( "default", pPropSet->m_strCameraCollisionFile.c_str(), KNX3Manager::SEQTYPE_ALL, &loadpack );
if( bSlowLoad ) Sleep( 1 );
pSeqNX3->PlayAnimation( GetSafeTickCount(), "default", KSeqModel::SEQTYPE_LOOP );
if( bSlowLoad ) Sleep( 1 );
m_pCameraCollision = pSeqNX3;
// { [sonador][COLLIDABLE_CAMERA]
KSeqObject* pSeqObj = m_pCameraCollision->GetCurrentAnimation();
if( pSeqObj ) pSeqObj->realizeTime();
// }
CreateCameraCollisionSource( );
#ifndef _DEBUG //디버그 버전도 아니고
#ifndef _DEV //개발용 버전도 아니면
SAFE_DELETE( m_pCameraCollision ); //배포용이므로 지우자
#endif
#endif
}
if( pPropSet->m_strHeightFile.length() > 0 && _stricmp( pPropSet->m_strHeightFile.c_str(), "empty" ) != 0 ) //높이 화일
{
KSeqModel* pSeqNX3 = new KSeqModel;
pSeqNX3->Initialize();
//TODO
NX3LoadPack loadpack;
loadpack.Init();
loadpack.bLoad_PolyGon = true;
pSeqNX3->AddAnimation( c_szDefault, pPropSet->m_strHeightFile.c_str(), KNX3Manager::SEQTYPE_ALL, &loadpack );
if( bSlowLoad ) Sleep( 1 );
pSeqNX3->PlayAnimation( GetSafeTickCount(), c_szDefault, KSeqModel::SEQTYPE_LOOP );
if( bSlowLoad ) Sleep( 1 );
_CID( GETMESH_TRI );
KMsgGET_GETMESH_TRI msg;
msg.mat = m_matTransform;
msg.pListTriangles = &m_listTrianglesHeight;
pSeqNX3->Perform( id_GETMESH_TRI, msg );
#ifndef NDEBUG
for(int i = 0; i < (int)m_listTrianglesHeight.size(); i += 3)
{
K3DVector &v1 = m_listTrianglesHeight[i+0];
K3DVector &v2 = m_listTrianglesHeight[i+1];
K3DVector &v3 = m_listTrianglesHeight[i+2];
m_WirePrimitive.AddLine( v1, v2, KColor(255,255,0,255) );
m_WirePrimitive.AddLine( v2, v3, KColor(0,255,255,255) );
m_WirePrimitive.AddLine( v3, v1, KColor(255,0,255,255) );
}
#endif
CreateTriangleIndex();
#ifdef _DEBUG
m_pModelHeight = pSeqNX3;
#else
delete pSeqNX3;
#endif
//높이 벡터 만들기
}
//텍스처 그룹 설정
if( pPropSet->m_TextureGroupList[0].empty() == false )
{
iterator_texture_group_list itTextureGroupResult;
iterator_texture_group_list itTextureGroup = pPropSet->m_TextureGroupList[0].begin();
if( itTextureGroup != pPropSet->m_TextureGroupList[0].end() )
{
iterator_seq_list itSeqList = (*itTextureGroup)->vSeqList.begin();
for( ; itSeqList != (*itTextureGroup)->vSeqList.end(); ++itSeqList )
{
for( int nTexGroupIndex = 0; nTexGroupIndex < TEXTURE_GROUP_INDEX_MAX; ++nTexGroupIndex )
{
int nTexUsingIndex = 0;
std::vector< std::string >::iterator itStr = (*itSeqList)->vTextureIndex[nTexGroupIndex].begin();
for( ; itStr != (*itSeqList)->vTextureIndex[nTexGroupIndex].end(); ++itStr, ++nTexUsingIndex )
{
itTextureGroupResult = findname( m_vTextureGroupData.begin(), m_vTextureGroupData.end(), (*itTextureGroup)->GetName() );
if( itTextureGroupResult != m_vTextureGroupData.end() )
{
iterator_seq_list itSeqResult;
itSeqResult = findname( (*itTextureGroupResult)->vSeqList.begin(), (*itTextureGroupResult)->vSeqList.end(), (*itSeqList)->GetName() );
if( itSeqResult != (*itTextureGroupResult)->vSeqList.end() )
{
if( nTexUsingIndex < (int)(*itSeqResult)->vTextureIndex[nTexGroupIndex].size() )
(*itSeqResult)->vTextureIndex[nTexGroupIndex][nTexUsingIndex] = (*itStr).c_str();
else
{
(*itSeqResult)->vTextureIndex[nTexGroupIndex].resize( nTexUsingIndex + 1, "" );
(*itSeqResult)->vTextureIndex[nTexGroupIndex][nTexUsingIndex] = (*itStr).c_str();
}
}
else
{
TEXTURE_GROUP_LIST::Seq_list* seq = new TEXTURE_GROUP_LIST::Seq_list;
seq->strSeqName = (*itSeqList)->strSeqName.c_str();
seq->vTextureIndex[nTexGroupIndex].resize( nTexUsingIndex + 1, "" );
seq->vTextureIndex[nTexGroupIndex][nTexUsingIndex] = (*itStr).c_str();
(*itTextureGroupResult)->vSeqList.push_back( seq );
}
}
else
{
TEXTURE_GROUP_LIST* texture_data = new TEXTURE_GROUP_LIST;
texture_data->strNx3Name = (*itTextureGroup)->strNx3Name.c_str();
TEXTURE_GROUP_LIST::Seq_list* pSeq = new TEXTURE_GROUP_LIST::Seq_list;
pSeq->strSeqName = (*itSeqList)->strSeqName.c_str();
pSeq->vTextureIndex[nTexGroupIndex].resize( nTexUsingIndex + 1, "" );
pSeq->vTextureIndex[nTexGroupIndex][nTexUsingIndex] = (*itStr).c_str();
texture_data->vSeqList.push_back( pSeq );
m_vTextureGroupData.push_back( texture_data );
}
}
}
}
}
ChangeTexture( m_nTextureGroupIndex );
}
}
//툴만
#ifndef _RAC
if( m_pModel )
{ //성능 관련된 정보 얻기
_CID( GET_PERFORMANCEINFO );
KMsgGET_PERFORMANCEINFO msg;
m_pModel->Perform( id_GET_PERFORMANCEINFO, msg );
}
#endif
if( bSlowLoad ) Sleep( 1 );
RefreshAllTransform();
CreateStools();
SetVisibility( 1.f );
m_bIsRealLoad = true;
}
void CTerrainProp::LoadCOB( const char* szFileName, const K3DMatrix& rMatrix )
{
//COB 데이타 만 읽어 들인다.
//Cube 데이타 읽어 온다.
if( m_strFileName.length() <= 0 )
{ //프랍 이름 없는 것들
m_pBoundCube = CreateDummyBoundCube();
m_bIsRealLoad = true;
return;
}
std::vector<COBSET *>* coblist = COBManager::GetManager()->Load( szFileName );
if( coblist == NULL )
{
m_pBoundCube = CreateDummyBoundCube();
return;
}
std::vector<COBSET *>::iterator it = coblist->begin();
if( it != coblist->end() )
{
COBSET * pPropSet = (*it);
//Prop 이 아니면 로딩 안 됨
if( pPropSet->nClan != GCLAN_PROP_NX3 &&
pPropSet->nClan != GCLAN_PROP_SPEED &&
pPropSet->nClan != GCLAN_PROP_COB )
{
m_pBoundCube = CreateDummyBoundCube();
return;
}
K3DBoundRotCube* pCube = new K3DBoundRotCube(
pPropSet->fVisibleCube[0], pPropSet->fVisibleCube[3],
pPropSet->fVisibleCube[1], pPropSet->fVisibleCube[4],
pPropSet->fVisibleCube[2], pPropSet->fVisibleCube[5] );
pCube->SetWireColor( KColor( 255, 255, 0, 255 ) );
m_pBoundCube = pCube;
m_nPropType = pPropSet->nClan;
m_dwPropRenderType = pPropSet->nRenderType;
m_dwPropCategory = pPropSet->nPropCategory;
m_dwPropShadowType = pPropSet->nShadowType;
}
}
KSeqForm* CTerrainProp::CreateNX3Model( const char* szNX3FileName, const char* szNAFFileName )
{
// _oprint( "CreateNX3Model : %s %s\n", szNX3FileName, szNAFFileName );
KSeqAvatar* pSeqNAF = new KSeqAvatar;
pSeqNAF->Initialize();
if( pSeqNAF->AddMesh( MPART_HAIR, szNX3FileName ) )
{
if( pSeqNAF->AddAnimation( szNAFFileName, TRUE ) )
{
pSeqNAF->PlayAnimation( GetSafeTickCount(), c_szDefault, KSeqModel::SEQTYPE_LOOP );
return pSeqNAF;
}
}
delete pSeqNAF;
return NULL;
}
KSeqForm* CTerrainProp::CreateNAFModel( const char* szFileName )
{
// _oprint( "CreateNAFModel : %s\n", szFileName );
KSeqModel* pSeqNX3 = new KSeqModel;
pSeqNX3->Initialize();
NX3LoadPack loadpack;
loadpack.Init();
if( pSeqNX3->AddAnimation( c_szDefault, szFileName, KNX3Manager::SEQTYPE_ALL, &loadpack ) )
{
pSeqNX3->PlayAnimation( GetSafeTickCount(), c_szDefault, KSeqModel::SEQTYPE_LOOP );
return pSeqNX3;
}
delete pSeqNX3;
return NULL;
}
KSeqForm* CTerrainProp::CreateSpeedTreeModel( const char* szFileName, const K3DMatrix& rMatrix )
{
//_oprint( "CreateSpeedTreeModel : %s\n", szFileName );
return SpeedTreeManager::GetManager()->Load( szFileName, rMatrix, rMatrix._11 );
}
KSeqForm* CTerrainProp::CreateNPCModel( const char* szFileName )
{
// _oprint( "CreateNPCModel : %s\n", szFileName );
std::vector<COBSET*>* pCobList = COBManager::GetManager()->Load( szFileName );
if( pCobList )
{
KSeqAvatarEx * pSeqAvatar = new KSeqAvatarEx;
pSeqAvatar->Initialize();
for( std::vector<COBSET*>::iterator it = pCobList->begin(); pCobList->end() != it; it++ )
{
COBSET* pSet = (*it);
if( NULL != pSet )
{
std::string strAniName;
for( unsigned int j(0); pSet->m_AniList.size() > j; j++ ) { pSeqAvatar->AddAnimation( pSet->nAniPart, pSet->m_AniList[j].c_str() ); CStringUtil::GetStrKey( pSet->m_AniList[j].c_str(), '_', strAniName ); }
for( unsigned int j(0); pSet->m_HelmList.size() > j; j++ ) pSeqAvatar->AddMesh( pSet->nAniPart, MPART_HELM, pSet->m_HelmList[j].c_str() );
for( unsigned int j(0); pSet->m_HairList.size() > j; j++ ) pSeqAvatar->AddMesh( pSet->nAniPart, MPART_HAIR, pSet->m_HairList[j].c_str() );
for( unsigned int j(0); pSet->m_FaceList.size() > j; j++ ) pSeqAvatar->AddMesh( pSet->nAniPart, MPART_FACE, pSet->m_FaceList[j].c_str() );
for( unsigned int j(0); pSet->m_BodyList.size() > j; j++ ) pSeqAvatar->AddMesh( pSet->nAniPart, MPART_BODY, pSet->m_BodyList[j].c_str() );
for( unsigned int j(0); pSet->m_HandList.size() > j; j++ ) pSeqAvatar->AddMesh( pSet->nAniPart, MPART_HAND, pSet->m_HandList[j].c_str() );
for( unsigned int j(0); pSet->m_FootList.size() > j; j++ ) pSeqAvatar->AddMesh( pSet->nAniPart, MPART_FOOT, pSet->m_FootList[j].c_str() );
if( pSet->nAniPart == ANIPART_BIPED )
pSeqAvatar->PlayAnimation( ANIPART_BIPED, GetSafeTickCount(), strAniName.c_str(), KSeqModel::SEQTYPE_LOOP );
}
}
return pSeqAvatar;
}
return NULL;
}
K3DBoundRotCube* CTerrainProp::CreateDummyBoundCube()
{
K3DBoundRotCube* pCube = new K3DBoundRotCube(
-c_fDummyCubeHalfLength,
c_fDummyCubeHalfLength,
-c_fDummyCubeHalfLength,
c_fDummyCubeHalfLength,
0.f,
(c_fDummyCubeHalfLength * 2.f) );
pCube->SetWireColor( KColor( 255, 0, 0, 255 ) );
pCube->SetWireDrawMode( true );
return pCube;
}
void CTerrainProp::UpdateTransform()
{
K3DMatrixIdentity( m_matTransform );
// K3DMatrixIdentity( m_matCorrectedTransform );
K3DMatrix matScale, matRotate, matWorld;
K3DMatrixIdentity( matScale );
K3DMatrixIdentity( matRotate );
K3DMatrixScaling( matScale, m_Scale.x, m_Scale.y, m_Scale.z );
K3DMatrixRotationYawPitchRoll( matRotate, m_Rotate.x, m_Rotate.y, m_Rotate.z );
m_matTransform = matScale * matRotate;
m_matTransform.SetPosVector( K3DVector( m_Pos.x, m_Pos.y, m_Pos.z + m_fZOffset ) );
}
void CTerrainProp::UpdateCorrectedTransform()
{
//m_matCorrectedTransform = m_matTransform;
//m_matCorrectedTransform._41 -= m_ptCurrentOriginCorrection.x;
//m_matCorrectedTransform._42 -= m_ptCurrentOriginCorrection.y;
}
void CTerrainProp::RefreshAllTransform()
{
UpdateTransform();
// UpdateCorrectedTransform()
if( NULL != m_pModel )
{
m_pModel->SetParentTransform( &m_matTransform );
}
if( NULL != m_pModelHeight )
{
m_pModelHeight->SetParentTransform( &m_matTransform );
#ifndef _RAC
m_WirePrimitive.Clear();
m_listTrianglesHeight.clear();
_CID( GETMESH_TRI );
KMsgGET_GETMESH_TRI msg;
msg.mat = m_matTransform;
msg.pListTriangles = &m_listTrianglesHeight;
m_pModelHeight->Perform( id_GETMESH_TRI, msg );
for(int i = 0; i < (int)m_listTrianglesHeight.size(); i += 3)
{
K3DVector &v1 = m_listTrianglesHeight[i+0];
K3DVector &v2 = m_listTrianglesHeight[i+1];
K3DVector &v3 = m_listTrianglesHeight[i+2];
m_WirePrimitive.AddLine( v1, v2, KColor(255,255,0,255) );
m_WirePrimitive.AddLine( v2, v3, KColor(0,255,255,255) );
m_WirePrimitive.AddLine( v3, v1, KColor(255,0,255,255) );
}
#endif
}
if( m_pBoundCube ) m_pBoundCube->SetTransform( m_matTransform );
if( m_pCameraCollision ) m_pCameraCollision->SetTransform( m_matTransform );
}
float CTerrainProp::GetPropHeightByTriangleIndex( float x, float y) const
{
float fHeight = -999999999.f;
if( !m_bIsRealLoad )
return fHeight;
std::vector<PropTri*> triList;
m_pIndexTri->GetCollisionTriList(x,y,&triList);
for(size_t i = 0; i < triList.size(); ++i)
{
const K3DPlane& plane = triList.at(i)->plane;
// z = (-ax - by - d) / c;
float fRet = ( -plane.a * x -plane.b * y - plane.d ) / plane.c;
if(fRet > fHeight)
{
fHeight = fRet;
}
}
return fHeight;
}
void CTerrainProp::GetPropTriangle( float x, float y, K3DVector& v1, K3DVector& v2, K3DVector& v3 ) const
{
float fHeight = -999999999.f;
if( !m_bIsRealLoad ) return;
std::vector<PropTri*> triList;
m_pIndexTri->GetCollisionTriList(x,y,&triList);
PropTri* pTriList = NULL;
for(size_t i = 0; i < triList.size(); ++i)
{
const K3DPlane& plane = triList.at(i)->plane;
// z = (-ax - by - d) / c;
float fRet = ( -plane.a * x -plane.b * y - plane.d ) / plane.c;
if(fRet > fHeight)
{
fHeight = fRet;
pTriList = triList[i];
}
}
if( pTriList )
{
v1 = K3DVector( pTriList->v[0].x, pTriList->v[0].y, pTriList->z[0] );
v2 = K3DVector( pTriList->v[1].x, pTriList->v[1].y, pTriList->z[1] );
v3 = K3DVector( pTriList->v[2].x, pTriList->v[2].y, pTriList->z[2] );
}
}
float CTerrainProp::GetPropHeight( const K3DVector& rNear, const K3DVector& rFar, K3DVector& rPickedPoint ) const
{
if( !m_bIsRealLoad )
return false;
float fStoolDistance = 1.f;
for(int i = 0; i < (int)m_listTrianglesHeight.size(); i += 3)
{
const K3DVector &v1 = m_listTrianglesHeight[i+0];
const K3DVector &v2 = m_listTrianglesHeight[i+1];
const K3DVector &v3 = m_listTrianglesHeight[i+2];
K3DVector inter;
float fret = KPCCP::triangle_collide_edge_twosides( v1, v2, v3, rNear, rFar, inter );
if( fret != 1.f )
{
//#ifndef NDEBUG
// m_WirePrimitive.AddLine( K3DVector(v1.x, v1.y, v1.z+10.f), K3DVector(v2.x, v2.y, v2.z+10.f), KColor(0,0,0,255) );
// m_WirePrimitive.AddLine( K3DVector(v2.x, v2.y, v2.z+10.f), K3DVector(v3.x, v3.y, v3.z+10.f), KColor(0,0,0,255) );
// m_WirePrimitive.AddLine( K3DVector(v3.x, v3.y, v3.z+10.f), K3DVector(v1.x, v1.y, v1.z+10.f), KColor(0,0,0,255) );
//
// _oprint( "Prop Height 01 [%s]: %f %f %f\n", m_strFileName.c_str(), inter.x, inter.y, inter.z );
//#endif
if( fStoolDistance > fret )
{
fStoolDistance = fret;
rPickedPoint = inter;
}
}
}
return fStoolDistance;
}
void CTerrainProp::CreateStools()
{
//if( NULL != m_pModel )
//{
// // 3d 충돌 큐브를 구한다.
// _CID( REQ_EVBOX );
// KMsgREQ_EVBOX msg;
// if( NULL != m_pModel->Perform( id_REQ_EVBOX, msg ) )
// {
// const K3DMatrix& rPropMatrix = m_matTransform;
// int nBoxCount = msg.GetBoxCount();
// for( int n( 0 ); n < nBoxCount; ++n )
// {
// KEventBoxSeq* pEvBoxSeq = msg.GetBox( n );
// if( 0 == ::_stricmp( pEvBoxSeq->GetName(), c_szCollisionCube ) )
// {
// K3DBoundRotCube cube = pEvBoxSeq->GetCube();
// cube.AddTransform( rPropMatrix );
// // stool 추가
// m_StoolVector.push_back( CTerrainStool( cube ) );
// }
// }
// }
// if( 0 < m_StoolVector.size() )
// {
// switch( m_nRenderType )
// {
// default:
// case KRenderObject::RENDEREFX_PROP: m_nRenderType = KRenderObject::RENDEREFX_PROP_HAS_STOOL; break;
// case KRenderObject::RENDEREFX_BUILDING: m_nRenderType = KRenderObject::RENDEREFX_BUILDING_HAS_STOOL; break;
// }
// }
//}
}
bool CTerrainProp::CreateCameraCollisionSource( )
{
if( !m_pCameraCollision ) return false;
m_CameraCollisionResource.clear( );
_CID( GETMESH_VERTEXBUFFERS );
_CID( GETMESH_INDEXBUFFERS );
KMsgGET_MESHVERTEXBUFFERS msgGMVB;
m_pCameraCollision->Perform( id_GETMESH_VERTEXBUFFERS, msgGMVB );
KMsgGET_MESHINDEXBUFFERS msgGMIB;
m_pCameraCollision->Perform( id_GETMESH_INDEXBUFFERS, msgGMIB );
if( msgGMVB.vVbStruct.size() != msgGMIB.vIbStruct.size() )
{
assert( 0 );
}
int nSize = msgGMVB.vVbStruct.size();
// for each vertex buffer structs & index buffer structs
for( int k = 0; k < nSize; ++k )
{
if( msgGMVB.vVbStruct[ k ]->nVBCount != msgGMIB.vIbStruct[ k ]->nIBCount ) continue;
// for each vertex buffers & index buffers in this struct
for( int j = 0; j < msgGMVB.vVbStruct[ k ]->nVBCount; ++j )
{
K3DVertexBuffer* pVB = (K3DVertexBufferDX*)msgGMVB.vVbStruct[ k ]->pVBs[ j ];
K3DIndexBuffer* pIB = (K3DIndexBufferDX*)msgGMIB.vIbStruct[ k ]->pIBs[ j ];
byte *pVtxData = NULL, *pIdxData = NULL;
int nVtxCount = pVB->GetVertexCount();
int nVtxStride = pVB->GetVertexStride();
int nIdxCount = pIB->GetIndexCount();
int nIdxFormat = pIB->GetFormat();
K3DVector v1, v2, v3;
K3DPlane plane;
unsigned short* pIdx16 = 0;
unsigned int* pIdx32 = 0;
// lock buffers
int crap;
pVB->Lock((void**) &pVtxData, crap, D3DLOCK_NOSYSLOCK);
if( pVtxData == 0 )
continue;
assert(pVtxData && "pVb->Lock((void**) &pVtxData, crap, D3DLOCK_NOOVERWRITE);");
pIB->Lock((void**) &pIdxData, crap, D3DLOCK_NOSYSLOCK);
if( pIdxData == 0 )
continue;
assert(pIdxData && "pIb->Lock((void**) &pIdxData, crap, D3DLOCK_NOOVERWRITE);");
for( int i = 0; i < nIdxCount; i += 3 )
{
if(nIdxFormat == D3DFMT_INDEX16)
{
pIdx16 = &( (unsigned short*)pIdxData )[ i ];
v1 = *( (K3DVertex*)( pVtxData + ( (*pIdx16) * nVtxStride ) ) );
++pIdx16;
v2 = *( (K3DVertex*)( pVtxData + ( (*pIdx16) * nVtxStride ) ) );
++pIdx16;
v3 = *( (K3DVertex*)( pVtxData + ( (*pIdx16) * nVtxStride ) ) );
++pIdx16;
}
else if(nIdxFormat == D3DFMT_INDEX32)
{
pIdx32 = &( (unsigned int*)pIdxData )[ i ];
v1 = *( (K3DVertex*)( pVtxData + ( (*pIdx32) * nVtxStride ) ) );
++pIdx32;
v2 = *( (K3DVertex*)( pVtxData + ( (*pIdx32) * nVtxStride ) ) );
++pIdx32;
v3 = *( (K3DVertex*)( pVtxData + ( (*pIdx32) * nVtxStride ) ) );
++pIdx32;
}
else
{
assert(0);
}
K3DVectorTransform( v1, v1, msgGMVB.vVbStruct[ k ]->matLocal );
K3DVectorTransform( v2, v2, msgGMVB.vVbStruct[ k ]->matLocal );
K3DVectorTransform( v3, v3, msgGMVB.vVbStruct[ k ]->matLocal );
m_CameraCollisionResource.push_back( v1 );
m_CameraCollisionResource.push_back( v2 );
m_CameraCollisionResource.push_back( v3 );
}
// unlock buffers
pVB->Unlock();
pIB->Unlock();
}
}
return true;
}
void CTerrainProp::CreateTriangleIndex()
{
if( m_pIndexTri )
{
assert(0);
return;
}
if(m_listTrianglesHeight.empty())
return;
// Min,Max 구하셈 -_-
float left,top,right,bottom;
left = top = m_listTrianglesHeight.front().x;
right = bottom = m_listTrianglesHeight.front().y;
for(size_t i = 1; i < m_listTrianglesHeight.size(); ++i)
{
const K3DVector &vtx = m_listTrianglesHeight.at(i);
left = std::min(left, vtx.x);
top = std::min(top, vtx.y);
right = std::max(right, vtx.x);
bottom = std::max(bottom, vtx.y);
}
m_PropArea = X2D::Rect<float>(left,top, right - left, bottom - top);
m_pIndexTri = new STriangleIndex(left,top,right - left, bottom - top, m_listTrianglesHeight.size() / 3 );
for(size_t i = 0; i < m_listTrianglesHeight.size(); i += 3)
{
const K3DVector &v1 = m_listTrianglesHeight[i+0];
const K3DVector &v2 = m_listTrianglesHeight[i+1];
const K3DVector &v3 = m_listTrianglesHeight[i+2];
K3DVector vDiff1 = v2 - v1;
K3DVector vDiff2 = v3 - v1;
K3DVector vNormal = CrossProduct(vDiff1, vDiff2);
Normalize(vNormal);
PropTri tri;
tri.plane.a = vNormal.x;
tri.plane.b = vNormal.y;
tri.plane.c = vNormal.z;
// ax + by + cz + d = 0;
tri.plane.d = -( K3DPlaneDotNormal(tri.plane, v1) );
for(size_t k = 0; k < 3; ++k)
{
tri.v[k].x = m_listTrianglesHeight[i+k].x;
tri.v[k].y = m_listTrianglesHeight[i+k].y;
tri.z[k] = m_listTrianglesHeight[i+k].z;
}
m_pIndexTri->AddTri(tri);
}
}
void CTerrainProp::RefreshLightmap(bool bEnableLightmap)
{
THREAD_SYNCRONIZE(m_LightmapSetLock);
m_bEnableLightmap = bEnableLightmap;
_SetLightmap();
}
void CTerrainProp::_SetLightmap()
{
if(NULL != m_pModel && false == m_nx3FileName.empty() )
{
// Lightmap Set
_CID( SET_LIGHT_MAP );
KMsgSET_LIGHTMAP lightMapSet(m_bEnableLightmap ? m_nx3FileName.c_str() : "", m_segmentIdx, m_propIdx);
m_pModel->Perform(id_SET_LIGHT_MAP, lightMapSet);
}
}
CTerrainProp* CTerrainProp::GetTerrainProp()
{
return this;
}
void CTerrainProp::ChangeTexture( short nTextureGroup )
{
_CID( CHANGE_MESH_TEXTURE );
KMsgCHANGE_MESH_TEXTURE msg;
iterator_texture_group_list itTextureGroupResult = m_vTextureGroupData.begin();
if( nTextureGroup > -1 && nTextureGroup < TEXTURE_GROUP_INDEX_MAX &&
m_vTextureGroupData.empty() == false )
{
for( ; itTextureGroupResult != m_vTextureGroupData.end(); ++itTextureGroupResult )
{
std::vector< TEXTURE_GROUP_LIST::Seq_list* >::iterator itSeqList = (*itTextureGroupResult)->vSeqList.begin();
for( ; itSeqList != (*itTextureGroupResult)->vSeqList.end(); ++itSeqList )
{
msg.szMeshName = (*itSeqList)->strSeqName.c_str();
std::vector< std::string >::iterator iter = (*itSeqList)->vTextureIndex[nTextureGroup].begin();
for( ; iter != (*itSeqList)->vTextureIndex[nTextureGroup].end(); ++iter )
{
msg.vTextureList.push_back( (*iter).c_str() );
}
if( m_pModel ) m_pModel->Perform( id_CHANGE_MESH_TEXTURE, msg );
msg.vTextureList.clear();
}
}
}
else
{
if( m_nTextureGroupIndex > -1 && m_nTextureGroupIndex < TEXTURE_GROUP_INDEX_MAX &&
m_vTextureGroupData.empty() == false )
{
for( ; itTextureGroupResult != m_vTextureGroupData.end(); ++itTextureGroupResult )
{
std::vector< TEXTURE_GROUP_LIST::Seq_list* >::iterator itSeqList = (*itTextureGroupResult)->vSeqList.begin();
for( ; itSeqList != (*itTextureGroupResult)->vSeqList.end(); ++itSeqList )
{
msg.szMeshName = (*itSeqList)->strSeqName.c_str();
std::vector< std::string >::iterator iter = (*itSeqList)->vTextureIndex[m_nTextureGroupIndex].begin();
for( ; iter != (*itSeqList)->vTextureIndex[m_nTextureGroupIndex].end(); ++iter )
{
msg.vTextureList.push_back( "" );
}
if( m_pModel ) m_pModel->Perform( id_CHANGE_MESH_TEXTURE, msg );
msg.vTextureList.clear();
}
}
}
}
m_nTextureGroupIndex = nTextureGroup;
}