#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 //#include "Util.h" #include "KSeqSpeedTree.h" #include "SSpeedTreeManager.h" #include "SCobManager.h" #include "KRenderObjectEtc.h" #include #include #include /// 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 v[3]; float z[3]; //높이 K3DPlane plane; //접선의 방정식 -_- }; template< typename T > inline bool COLLISION( const PropTri& lh, const X2D::Point& 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& lh, const PropTri& rh ) { // 하나라도 안에 있으면 for(size_t i = 0; i < 3; ++i) { if(lh.IsCollision(rh.v[i]) ) return true; X2D::Line line(rh.v[i%3], rh.v[(i+1)%3] ); if(lh.IsCollision(line)) return true; } X2D::Point 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( ::sqrtf(static_cast(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 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* pTriVector) { float offsetX = x - m_Area.GetLeft(); float offsetY = y - m_Area.GetTop(); int blockX = static_cast( offsetX / m_WidthUnit ); int blockY = static_cast( 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 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 m_Area; float m_WidthUnit; float m_HeightUnit; typedef std::vector 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& 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* coblist = COBManager::GetManager()->Load( m_strFileName.c_str() ); if( coblist == NULL ) { m_bIsRealLoad = true; return; } if( bSlowLoad ) Sleep( 10 ); std::vector::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* coblist = COBManager::GetManager()->Load( szFileName ); if( coblist == NULL ) { m_pBoundCube = CreateDummyBoundCube(); return; } std::vector::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* pCobList = COBManager::GetManager()->Load( szFileName ); if( pCobList ) { KSeqAvatarEx * pSeqAvatar = new KSeqAvatarEx; pSeqAvatar->Initialize(); for( std::vector::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 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 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(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; }