#pragma once #include "stdafx.h" #include "TerrainSegment.h" #include "KViewport.h" #include "TerrainInfoForSegment.h" #include "TerrainPropInfo.h" #include "TerrainPrimitiveFor1Stage.h" #include "TerrainPrimitiveFor3Stage.h" #include "TerrainPrimitiveFor4Stage.h" //#include "K3DFrustum.h" #include "gamedefine.h" #include "SRenderFlag.h" #include "KSeqSpeedTree.h" #include "KResourceManager.h" #include "k3dpccp.h" #include "PVSObject.h" #include //#include "SDebug_Util.h" class CTerrainPrimitiveInvisible : public CTerrainPrimitive { public: CTerrainPrimitiveInvisible( int nVertexCount, const CTerrainInfo* pTerrainInfo, bool& rResult ) : CTerrainPrimitive( nVertexCount, NULL, pTerrainInfo ) { rResult = true; } virtual void Render( KViewportObject *viewport, class K3DRenderDevice *dev, bool bUseAccum = true ) { } public: // for Editor bool RefreshHeight( const CTerrainInfo* pTerrainInfo, K3DRenderDevice* pDev ) { return true; } bool RefreshTile( const CTerrainInfo* pTerrainInfo, K3DRenderDevice* pDev ) { return true; } bool RefreshColor( const CTerrainInfo* pTerrainInfo, K3DRenderDevice* pDev ) { return true; } }; namespace { K3DTexture* getLightmapTex(int segmentX, int segmentY) { int newSegmentIndex = 8 * (segmentY / 8) * 896 + 8 * (segmentX / 8 ); char lightMapName[_MAX_PATH]; _snprintf_s(lightMapName, _MAX_PATH, "_light_%d.tga", newSegmentIndex); NX3LoadPack nx3Pack; return KTextureManager::GetManager()->GetTexture(lightMapName, &nx3Pack); } // sonador #2.1.7.1 스피드 트리 퍼포먼스 증가 // 카메라와의 거리가 PropProcessSkipDist 이상이 되면 프랍의 process 가 호출되지 않도록 한다. const float PropProcessSkipDist = 1800.f; // prop의 가시거리에서 어느정도 이상 떨어졌을때 반투명하게 처리할지를 지정하는 값. // ( 예> 0.7f일 경우 보이는 거리의 70%이상 멀어지면 투명해지기 시작한다. ) const float PropOpaqueDistanceRatio = 0.9f; } #ifdef _DEBUG bool CTerrainSegment::s_bCubeRender = false; #endif bool CTerrainSegment::s_bGlassRender = true; CTerrainSegment::CTerrainSegment ( CTerrainInfoForSegment* pTerrainInfo // , TERRAIN_FILTERING FilteringType , TERRAIN_RENDERMODE RenderMode , float fTileLength , int nTileCount , K3DIndexBuffer** ppCommonIndexBuffer , CTerrainTextureInfo* pTextureInfo , const CTerrainPropInfo* pPropInfo , K3DRenderDevice* pDevice , int nSegmentIndex , bool& rResult , DWORD dwRenderTime , const K3DVertex* pOriginCorrection , int segmentIndex , int segmentX , int segmentY , bool bEnableLightmap) //: m_nFilteringType( FilteringType ) //: m_nFilteringType( FilteringType ) : m_nRenderMode(RenderMode) , m_bVisible( false ) , m_nTileCount( nTileCount ) , m_dwRenderTime( dwRenderTime ) , m_unLastRenderedTick( 0 ) , m_pTerrainInfo( pTerrainInfo ) , m_pTerrainPrimitive( NULL ) , m_pTerrainShadowPrimitive( NULL ) , m_pPropInfo( pPropInfo ) , m_pPropVisibleFlag( NULL ) , m_nPropVisibleFlagCount( 0 ) { int nVertexCount = (m_nTileCount + 1); m_nSegmentX = segmentX; m_nSegmentY = segmentY; int lightmap_offset_x = m_nSegmentX % 8; int lightmap_offset_y = m_nSegmentY % 8; m_nSegmentIndex = segmentIndex; m_bEnableLightmap = bEnableLightmap; K3DTexture* pLightmapTex = NULL; if(m_bEnableLightmap) pLightmapTex = getLightmapTex(m_nSegmentX, m_nSegmentY); // 지형 primitive 생성 if( m_pTerrainInfo->NeedPrimitive() ) { std::list UsingTileList; m_pTerrainInfo->GetUsingTileList( UsingTileList ); //switch( FilteringType ) //{ //case FILTERING_NONE: // m_pTerrainPrimitive = new CTerrainPrimitiveFor1Stage( // fTileLength, // nVertexCount, // pCommonIndexBuffer, // UsingTileList, // pTextureInfo, // m_pTerrainInfo, // pDevice, // rResult ); // break; //case FILTERING_3TEXTURE: // m_pTerrainPrimitive = new CTerrainPrimitiveFor3Stage( // fTileLength, // nVertexCount, // pCommonIndexBuffer, // UsingTileList, // pTextureInfo, // m_pTerrainInfo, // pDevice, // rResult ); // break; //case FILTERING_3TEXSHADOW: // m_pTerrainPrimitive = new CTerrainPrimitiveFor4Stage( // fTileLength, // nVertexCount, // pCommonIndexBuffer, // UsingTileList, // pTextureInfo, // m_pTerrainInfo, // pDevice, // rResult ); // break; //default: // rResult = false; // break; //} switch( RenderMode ) { case TERRAIN_RENDERMODE_DEFAULT: case TERRAIN_RENDERMODE_MULTIPASS: m_pTerrainPrimitive = new CTerrainPrimitiveFor4Stage( fTileLength, nVertexCount, ppCommonIndexBuffer, UsingTileList, pTextureInfo, m_pTerrainInfo, pDevice, RenderMode, rResult, pLightmapTex, lightmap_offset_x, lightmap_offset_y); break; default: rResult = false; break; } if( NULL != m_pTerrainPrimitive ) { m_pTerrainPrimitive->SetOriginCorrection( pOriginCorrection ); m_pTerrainShadowPrimitive = m_pTerrainPrimitive->CreateCustomTexturePrimitive(); } } else { m_pTerrainPrimitive = new CTerrainPrimitiveInvisible( nVertexCount, m_pTerrainInfo, rResult ); } #ifdef _DEBUG float minx,miny,minz,maxx,maxy,maxz; m_pTerrainPrimitive->GetSegmentMinMaxValue( minx,miny,minz,maxx,maxy,maxz ); m_segment_cube = K3DBoundRotCube( minx,maxx, miny,maxy, minz,maxz ); //only segment m_segment_cube.SetWireColor( KColor(0,0,0,255) ); m_segment_cube.SetColorGradation( true ); #endif } CTerrainSegment::~CTerrainSegment() { SAFE_DELETE( m_pTerrainShadowPrimitive ); SAFE_DELETE( m_pTerrainPrimitive ); if( m_pPropVisibleFlag ) delete [] m_pPropVisibleFlag; delete m_pTerrainInfo; TERRAINSPEEDGRASS_VECTOR::iterator iter = m_vSpeedGrass.begin(); for( ; iter != m_vSpeedGrass.end(); ) { SAFE_DELETE( (*iter) ); iter = m_vSpeedGrass.erase( iter ); } m_vSpeedGrass.clear(); } const TERRAINMAP_PROPERTIES::COLORING& CTerrainSegment::GetMapColoring() const { return m_pTerrainInfo->GetMapColoring(); } void CTerrainSegment::SetTerrainLight( const K3DLight& rLight, K3DRenderDevice* pDevice ) { m_pTerrainInfo->SetTerrainLight( rLight ); m_pTerrainPrimitive->RefreshColor( m_pTerrainInfo, pDevice ); } void CTerrainSegment::SetCustomValid( bool bIsValid ) { if( NULL != m_pTerrainShadowPrimitive ) { m_pTerrainShadowPrimitive->SetValid( bIsValid ); } } WORD CTerrainSegment::GetTile( float x, float y ) const { return m_pTerrainInfo->GetGameTile( x, y ); } float CTerrainSegment::GetSegmentHeight( float x, float y ) const { return m_pTerrainInfo->GetZ( x, y ); } bool CTerrainSegment::GetSegmentColor( float x, float y, KTripleColor &out ) const { if( !m_pTerrainInfo->NeedPrimitive() ) return false; // Read color from terrain info <- NOT WORKING!! // return m_pTerrainInfo->GetColorByWorldCoordinate( nX, nY ); // // Read color from vertex buffer // float baseX, baseY; K3DTERRAINVERTEX *p, *q; K3DMatrix *transform; // Get reference point transform=m_pTerrainPrimitive->GetRootMat(); baseX=transform->m30; baseY=transform->m31; x-=baseX; y-=baseY; // Get vertex buffer K3DVertexBufferSPtr *vb=m_pTerrainPrimitive->GetVertexBuffer(); if( !vb ) return false; int vcount=m_pTerrainPrimitive->GetVertexCount(); int count; (*vb)->Lock( (void**)&p, count ); try { if (p==NULL) throw 0; if (x < p->pos.x) throw 0; // nX < GRIDS if (y < p->pos.y) throw 0; // nY < GRIDS int i; // Y 거르기 q=p+vcount; // 한 줄 다음 for (i=0; ipos.y) break; p=q; q+=vcount; } if (i==vcount-1) throw 0; // nY >= GRIDS // X거르기 q=p+1; // 한 칸 다음 for (i=0; ipos.x) break; p=q; q++; } if (i==vcount-1) throw 0; // nX >= GRIDS // 색 blend용 좌표 float dx, dy, dxi, dyi; dx=(x - p->pos.x) / ((p+1)->pos.x - p->pos.x); if (dx<0.) dx=0; else if (dx>1.) dx=1.; dy=(y - p->pos.y) / ((p+vcount)->pos.y - p->pos.y); if (dy<0.) dy=0; else if (dy>1.) dy=1.; dxi=1.f-dx; dyi=1.f-dy; // Get 4 grid corner colors const KColor& rColor00 = p->diffuse; const KColor& rColor10 = q->diffuse; p+=vcount; q+=vcount; const KColor& rColor01 = p->diffuse; const KColor& rColor11 = q->diffuse; // Blend color K3DVector cl, cr, c; cl.x=rColor00.r*dyi + rColor01.r*dy; cl.y=rColor00.g*dyi + rColor01.g*dy; cl.z=rColor00.b*dyi + rColor01.b*dy; cr.x=rColor10.r*dyi + rColor11.r*dy; cr.y=rColor10.g*dyi + rColor11.g*dy; cr.z=rColor10.b*dyi + rColor11.b*dy; c.x=cl.x*dxi + cr.x*dx; c.y=cl.y*dxi + cr.y*dx; c.z=cl.z*dxi + cr.z*dx; if (c.x<0.) c.x=0.; else if (c.x>255.) c.x=255.; if (c.y<0.) c.y=0.; else if (c.y>255.) c.y=255.; if (c.z<0.) c.z=0.; else if (c.z>255.) c.z=255.; // Map float to byte out.r=(unsigned char)c.x; out.g=(unsigned char)c.y; out.b=(unsigned char)c.z; } catch (int) { out=KTripleColor(0, 0, 0); } if (p!=NULL) (*vb)->Unlock(); return true; } void CTerrainSegment::GetSegmentTriangle(float x, float y, K3DVector& v1, K3DVector& v2, K3DVector& v3) const { m_pTerrainInfo->GetTriangle(x, y, v1, v2, v3); } bool CTerrainSegment::GetAttribute( int nAttrX, int nAttrY ) const { return m_pTerrainInfo->GetAttribute( nAttrX, nAttrY ); } K3DVertex CTerrainSegment::GetVertex( int nX, int nY ) const { return m_pTerrainInfo->GetVertex( nX, nY ); } //void CTerrainSegment::ResetStoolColor() const //{ // for( TERRAINPROP_VECTOR::const_iterator itProp = m_PropVector.begin(); itProp != m_PropVector.end(); itProp++ ) // { // const TERRAINSTOOL_VECTOR& rStoolVector = (*itProp)->GetStoolVector(); // for( TERRAINSTOOL_VECTOR::const_iterator itStool = rStoolVector.begin(); itStool != rStoolVector.end(); itStool++ ) // (*itStool).BuildWire( KColor( 255, 255, 0, 255 ) ); // } //} float CTerrainSegment::GetLineCrossedPointTwoSides( const K3DVector& rNear, const K3DVector& rFar, K3DVector& rPickedPoint ) const { K3DVertex vertices[4]; float fT = 1.0f, fSmallestT = 1.0f; K3DVector rCurrentPickedPoint; for( int nY( 0 ); nY < m_nTileCount; ++nY ) { for( int nX( 0 ); nX < m_nTileCount; ++nX ) { vertices[0] = m_pTerrainInfo->GetVertex( nX , nY ); vertices[1] = m_pTerrainInfo->GetVertex( nX + 1, nY ); vertices[2] = m_pTerrainInfo->GetVertex( nX , nY + 1 ); vertices[3] = m_pTerrainInfo->GetVertex( nX + 1, nY + 1 ); fT = CTerrainUtil::GetLineCrossedPointTwoSides( vertices, rNear, rFar, rCurrentPickedPoint ); if( fSmallestT > fT ) { fSmallestT = fT; rPickedPoint = rCurrentPickedPoint; return fSmallestT; // 임시 코드 by blackfish } } } return fSmallestT; } static inline float point_dist_point( float px, float py, float qx, float qy ) { qx -= px, qy -= py; return sqrt( qx*qx + qy*qy ); } static inline float point_dist_linesegment( float px, float py, float sx, float sy, float tx, float ty ) { tx -= sx, ty -= sy; if ( tx == 0 && ty == 0 ) return point_dist_point( px, py, sx, sy ); float len_st = sqrt( tx*tx + ty*ty ); return abs( (px-sx) * ty - (py-sy) * tx ) / len_st; } bool CTerrainSegment::GetLineCrossedPoint( const K3DVector& rNear, const K3DVector& rFar, K3DVector& rPickedPoint ) const { float d = point_dist_linesegment( m_pTerrainInfo->GetCenterX(), m_pTerrainInfo->GetCenterY(), rNear.x, rNear.y, rFar.x, rFar.y ); if ( d > m_pTerrainInfo->GetSegmentLength() * 1.414213f ) return false; const K3DVertex* pCube = m_pTerrainPrimitive->GetTerrainCube(); K3DVertex pLine[ 2 ]; pLine[ 0 ] = rNear; pLine[ 1 ] = rFar; if( !KPCCP::edge_collide_rotcube( pLine, pCube ) ) return false; K3DVertex vertices[4]; for( int nY( 0 ); nY < m_nTileCount; ++nY ) { for( int nX( 0 ); nX < m_nTileCount; ++nX ) { vertices[0] = m_pTerrainInfo->GetVertex( nX , nY ); vertices[1] = m_pTerrainInfo->GetVertex( nX + 1, nY ); vertices[2] = m_pTerrainInfo->GetVertex( nX , nY + 1 ); vertices[3] = m_pTerrainInfo->GetVertex( nX + 1, nY + 1 ); if( CTerrainUtil::GetLineCrossedPoint( vertices, rNear, rFar, rPickedPoint ) ) { return true; } } } return false; } // { [sonador][7.1.7]충돌 처리 개선(Swept Shpere Collision Detection) bool CTerrainSegment::GetEllipsoidCrossedPoint ( const K3DVector& rNear , const K3DVector& rFar , const K3DVector& rRadius , const K3DVector& rBaseInESpace , const K3DVector& rVelocityInESpace , const K3DMatrix& rCBM , float& fNearestT , K3DVector& rPickedPoint #ifdef _DEBUG , K3DVector* pCollidedPolygon , std::vector< std::pair< K3DVector, KColor > >& vecDebugLine #endif ) const { float d = point_dist_linesegment( m_pTerrainInfo->GetCenterX( ), m_pTerrainInfo->GetCenterY( ), rNear.x, rNear.y, rFar.x, rFar.y ); if ( d > m_pTerrainInfo->GetSegmentLength( ) * 1.414213f ) return false; //const K3DVertex* pCube = m_pTerrainPrimitive->GetTerrainCube( ); //K3DVertex pLine[ 2 ]; //pLine[ 0 ] = rNear; //pLine[ 1 ] = rFar; //if( !KPCCP::edge_collide_rotcube( pLine, pCube ) ) return false; K3DVector min, max; m_pTerrainPrimitive->GetSegmentMinMaxValue( min.x, min.y, min.z, max.x, max.y, max.z ); min -= rRadius; max += rRadius; if( ( rNear.x < min.x && rFar.x < min.x ) || ( rNear.x > max.x && rFar.x > max.x ) || ( rNear.y < min.y && rFar.y < min.y ) || ( rNear.y > max.y && rFar.y > max.y ) || ( rNear.z < min.z && rFar.z < min.z ) || ( rNear.z > max.z && rFar.z > max.z ) ) return false; bool bFound = false; K3DVector vertices[ 4 ]; for( int nY( 0 ); nY < m_nTileCount; ++nY ) { for( int nX( 0 ); nX < m_nTileCount; ++nX ) { vertices[ 0 ] = m_pTerrainInfo->GetVertex( nX , nY ); vertices[ 1 ] = m_pTerrainInfo->GetVertex( nX + 1, nY ); vertices[ 2 ] = m_pTerrainInfo->GetVertex( nX , nY + 1 ); vertices[ 3 ] = m_pTerrainInfo->GetVertex( nX + 1, nY + 1 ); #ifdef _DEBUG vecDebugLine.push_back( std::make_pair( vertices[ 0 ], KColor( 0xff00ff00 ) ) ); vecDebugLine.push_back( std::make_pair( vertices[ 1 ], KColor( 0xff00ff00 ) ) ); vecDebugLine.push_back( std::make_pair( vertices[ 1 ], KColor( 0xff00ff00 ) ) ); vecDebugLine.push_back( std::make_pair( vertices[ 2 ], KColor( 0xff00ff00 ) ) ); vecDebugLine.push_back( std::make_pair( vertices[ 2 ], KColor( 0xff00ff00 ) ) ); vecDebugLine.push_back( std::make_pair( vertices[ 0 ], KColor( 0xff00ff00 ) ) ); vecDebugLine.push_back( std::make_pair( vertices[ 1 ], KColor( 0xff00ff00 ) ) ); vecDebugLine.push_back( std::make_pair( vertices[ 3 ], KColor( 0xff00ff00 ) ) ); vecDebugLine.push_back( std::make_pair( vertices[ 3 ], KColor( 0xff00ff00 ) ) ); vecDebugLine.push_back( std::make_pair( vertices[ 2 ], KColor( 0xff00ff00 ) ) ); #endif // transform to ellipsoid vector space for( int n = 0; n < 4; ++n ) K3DVectorTransform( vertices[ n ], vertices[ n ], rCBM ); if( CTerrainUtil::GetEllipsoidCrossedPoint( vertices, rBaseInESpace, rVelocityInESpace, fNearestT, rPickedPoint #ifdef _DEBUG , pCollidedPolygon #endif ) ) { bFound = true; } } } return bFound; } // } const int LOAD_PROP_MAX_SIZE = 1; void CTerrainSegment::ProcessLoadedProps() { THREAD_SYNCRONIZE( m_PropLock ); int nLoadedCnt = 0; int nLoadingCnt = 0; // 로딩 끝난 녀석을 m_NotLoadedPropVector 에 넣어준다. for( TERRAINPROP_VECTOR::iterator itProp = m_NotLoadedPropVector.begin(); itProp != m_NotLoadedPropVector.end(); ) { const CTerrainPropForGameSPtr& spProp = (*itProp); // 로딩 끝났으면... if( (*itProp)->IsRealLoad() ) { ++nLoadedCnt; m_Loaded_PropVector.push_back( spProp ); itProp = m_NotLoadedPropVector.erase( itProp ); continue; } // 이미 로딩 걸려 있으면 패스 if( (*itProp)->IsPendLoading() ) { ++nLoadingCnt; ++itProp; continue; } ++itProp; } if( !nLoadingCnt || nLoadedCnt > 10 ) { if( nLoadedCnt ) { applyProps(); } } if( nLoadedCnt && m_nPropVisibleFlagCount < (int)m_Loaded_PropVector.size() ) { if( m_pPropVisibleFlag ) delete [] m_pPropVisibleFlag; m_nPropVisibleFlagCount = (int)m_Loaded_PropVector.size(); m_pPropVisibleFlag = new char[ m_nPropVisibleFlagCount/8 + 1 ]; } } void CTerrainSegment::LoadAllProps( const K3DVector* pFrustum /*= NULL*/ ) { THREAD_SYNCRONIZE( m_PropLock ); for( TERRAINPROP_VECTOR::iterator itProp = m_PropVector.begin(); itProp != m_PropVector.end(); itProp++ ) { CTerrainPropForGameSPtr pProp = (*itProp); if( pProp->GetParentSegment() != this ) continue; if( pFrustum ) { pProp->ClipTest( pFrustum ); if( pProp->GetIsClip() ) continue; } pProp->Load_Real(); m_Loaded_PropVector.push_back( pProp ); } applyProps(); } void CTerrainSegment::SetWindStrength( float fStrength ) { for(TERRAINPROP_VECTOR::iterator itProp = m_Loaded_PropVector.begin(); itProp != m_Loaded_PropVector.end(); itProp++) { if((*itProp)->GetPropType() == GCLAN_PROP_SPEED) { KSeqSpeedTree* pTree = (KSeqSpeedTree*) (*itProp)->GetModel(); pTree->SetWindStrength( fStrength ); } } } void CTerrainSegment::GetStoolLineCrossedPoint( const K3DVector& rNear, const K3DVector& rFar, K3DVector& rPickedPoint, TERRAIN_PICK_RESULT & nStoolPickResult, float & fStoolDistance, K3DVector & vtCurrentPoint, std::vector< CTerrainProp * > & check_list ) { THREAD_SYNCRONIZE( m_PropLock ); // 프랍들에 대해 체크 TERRAINPROP_VECTOR& rPropVector = m_Loaded_PropVector; float fHeight = 0.f; for( TERRAINPROP_VECTOR::iterator itProp = rPropVector.begin(); itProp != rPropVector.end(); itProp++ ) { bool IsCheck = false; for( unsigned int i(0); check_list.size()>i; i++ ) { //TODO : 최적화의 여지가 남아 있다. if( check_list[i] == (*itProp) ) { IsCheck = true; break; } } if( IsCheck ) continue; //이미 체크 되어 있음 if( (*itProp)->GetBoundCube()->CheckCollision( rNear, rFar ) ) { // _oprint( "Click Prop : %s \n", (*itProp)->m_strFileName.c_str() ); check_list.push_back( (*itProp) ); if( !(*itProp)->GetProcessFlagAtThisTick() ) continue; if( (*itProp)->IsHeight() ) { float fCurrentDistance = (*itProp)->GetPropHeight( rNear, rFar, vtCurrentPoint ); if( fStoolDistance > fCurrentDistance ) { fStoolDistance = fCurrentDistance; rPickedPoint = vtCurrentPoint; nStoolPickResult = TERRAIN_STOOL_PICK_SUCCECED; } } } } } // { [sonador][COLLIDABLE_CAMERA] bool CTerrainSegment::GetPropLineCrossedPointTwoSidesWithCollisionMesh ( const K3DVector& rayStart , const K3DVector& rayEnd , float& fNearestT , K3DVector& vCandidateCollidedPoint #ifdef _DEBUG , K3DVector* pCollidedPolygon #endif ) { THREAD_SYNCRONIZE( m_PropLock ); #ifdef _DEBUG K3DVector collidedPolygon[ 3 ]; #endif bool bFound = false; TERRAINPROP_VECTOR& propVector = m_Loaded_PropVector; TERRAINPROP_VECTOR::iterator itPropEnd = propVector.end(); for( TERRAINPROP_VECTOR::iterator itProp = propVector.begin(); itProp != itPropEnd; ++itProp ) { if( !(*itProp)->GetProcessFlagAtThisTick() ) continue; if( (*itProp)->GetBoundCube()->CheckCollision( rayStart, rayEnd ) ) { K3DVector vCollisionPoint; float fT = (*itProp)->CheckPolygonCollisionWithCollisionMesh( rayStart, rayEnd, fNearestT, vCollisionPoint #ifdef _DEBUG , collidedPolygon #endif ); if( fNearestT > fT ) { bFound = true; fNearestT = fT; vCandidateCollidedPoint = vCollisionPoint; #ifdef _DEBUG pCollidedPolygon[ 0 ] = collidedPolygon[ 0 ]; pCollidedPolygon[ 1 ] = collidedPolygon[ 1 ]; pCollidedPolygon[ 2 ] = collidedPolygon[ 2 ]; #endif } } } return bFound; } // 2010.07.22 - prodongi //extern std::vector collidedMesh; extern std::vector collidedMesh; // } // { [sonador][7.1.7]충돌 처리 개선(Swept Shpere Collision Detection) bool CTerrainSegment::GetPropEllipsoidCrossedPointTwoSidesWithCollisionMesh ( const K3DVector& rayStart , const K3DVector& rayEnd , const K3DVector& rayStartInESpace , const K3DVector& rayEndInESpace , const K3DMatrix& matCBM , float& fNearestT , K3DVector& vCandidateCollidedPoint #ifdef _DEBUG , K3DVector* pCollidedPolygon #endif ) { THREAD_SYNCRONIZE( m_PropLock ); bool bFound = false; TERRAINPROP_VECTOR& propVector = m_Loaded_PropVector; TERRAINPROP_VECTOR::iterator itPropEnd = propVector.end(); for( TERRAINPROP_VECTOR::iterator itProp = propVector.begin(); itProp != itPropEnd; ++itProp ) { if( !(*itProp)->GetProcessFlagAtThisTick() ) continue; // 2010.07.22 m_strFileName은 고유 번호가 될 수 없다- prodongi /* if ( find(collidedMesh.begin(), collidedMesh.end(), (*itProp)->m_strFileName) == collidedMesh.end() ) collidedMesh.push_back((*itProp)->m_strFileName); else continue; */ if ( find(collidedMesh.begin(), collidedMesh.end(), (*itProp)->GetID()) == collidedMesh.end() ) collidedMesh.push_back((*itProp)->GetID()); else continue; if( (*itProp)->GetBoundCube()->CheckCollision( rayStart, rayEnd ) ) { if( (*itProp)->CheckPolygonEllipsoidCollisionWithCollisionMesh( rayStartInESpace, rayEndInESpace, matCBM, fNearestT, vCandidateCollidedPoint #ifdef _DEBUG , pCollidedPolygon #endif ) ) { bFound = true; } } } return bFound; } // } void CTerrainSegment::GetPropLineCrossedPointTwoSides( const K3DVector& rNear, const K3DVector& rFar, float & fSmallestT, K3DVector& rCandidatePickedPoint ) { THREAD_SYNCRONIZE( m_PropLock ); TERRAINPROP_VECTOR& rPropVector = m_Loaded_PropVector; float fHeight = 0.f; for( TERRAINPROP_VECTOR::iterator itProp = rPropVector.begin(); itProp != rPropVector.end(); itProp++ ) { if( !(*itProp)->GetProcessFlagAtThisTick() ) continue; if( (*itProp)->GetBoundCube()->CheckCollision( rNear, rFar ) ) { K3DVector rTempPickedPoint; float fT = (*itProp)->CheckPolygonCollision( rNear, rFar, rTempPickedPoint ); if( fSmallestT > fT ) { fSmallestT = fT; rCandidatePickedPoint = rTempPickedPoint; } } } return; } bool CTerrainSegment::GetStoolTriangle( float x, float y, K3DVector& v1, K3DVector& v2, K3DVector& v3, float fTerrainHeight ) const { const CTerrainPropForGame* pSelectProp = NULL; K3DVector pos1 = K3DVector( x, y, 50000.f); K3DVector pos2 = K3DVector( x, y, -50000.f); K3DVector vResult; float fResult = 1.f; for( TERRAINPROP_VECTOR::const_iterator itProp = m_PropVector.begin(); itProp != m_PropVector.end(); itProp++ ) { if( (*itProp)->IsHeight() && (*itProp)->IsInRectArea(x,y) ) { float resultCur = (*itProp)->GetPropHeightByTriangleIndex(x,y); if( fTerrainHeight < resultCur ) { fTerrainHeight = resultCur; pSelectProp = (*itProp); } } } if( pSelectProp ) { pSelectProp->GetPropTriangle( x, y, v1, v2, v3 ); return true; } return false; } bool CTerrainSegment::GetStoolHeight( float x, float y, float& rGetHeight ) { THREAD_SYNCRONIZE( m_PropLock ); #ifndef NDEBUG DWORD dwStartTime = GetSafeTickCount(); #endif bool bGetStoolHeight = false; TERRAIN_PICK_RESULT nStoolPickResult = TERRAIN_STOOL_PICK_FAILED; K3DVector pos1 = K3DVector( x, y, 50000.f); K3DVector pos2 = K3DVector( x, y, -50000.f); K3DVector vResult; for( TERRAINPROP_VECTOR::const_iterator itProp = m_PropVector.begin(); itProp != m_PropVector.end(); itProp++ ) { if( (*itProp)->IsHeight() && (*itProp)->IsInRectArea(x,y) ) { float resultCur = (*itProp)->GetPropHeightByTriangleIndex(x,y); if( rGetHeight < resultCur ) { rGetHeight = resultCur; bGetStoolHeight = true; } } } #ifndef NDEBUG // _oprint( "[시간 검사 GetStoolHeight : %d]\n", GetSafeTickCount()-dwStartTime ); #endif return bGetStoolHeight; } CTerrainProp* CTerrainSegment::GetTerrainProp( float x, float y, float& rGetHeight ) { THREAD_SYNCRONIZE( m_PropLock ); TERRAIN_PICK_RESULT nStoolPickResult = TERRAIN_STOOL_PICK_FAILED; K3DVector pos1 = K3DVector( x, y, 50000.f); K3DVector pos2 = K3DVector( x, y, -50000.f); K3DVector vResult; CTerrainProp* pTerrainProp = NULL; for( TERRAINPROP_VECTOR::iterator itProp = m_PropVector.begin(); itProp != m_PropVector.end(); itProp++ ) { if( (*itProp)->IsHeight() && (*itProp)->IsInRectArea(x,y) ) { float resultCur = (*itProp)->GetPropHeightByTriangleIndex(x,y); if( rGetHeight < resultCur ) { rGetHeight = resultCur; pTerrainProp = (*itProp)->GetTerrainProp(); } } } return pTerrainProp; } void CTerrainSegment::applyProps() { if( m_nRenderMode == TERRAIN_RENDERMODE_DEFAULT) { m_pTerrainPrimitive->ReloadProp( m_PropVector ); } if( m_nPropVisibleFlagCount < (int)m_Loaded_PropVector.size() ) { if( m_pPropVisibleFlag ) delete [] m_pPropVisibleFlag; m_nPropVisibleFlagCount = (int)m_Loaded_PropVector.size(); m_pPropVisibleFlag = new char[ m_nPropVisibleFlagCount/8 + 1 ]; } } bool CTerrainSegment::IsFrustumCollide( const K3DVector* pFrustum ) { return KPCCP::nonuniformcube_collide_nonuniformcube(pFrustum, m_pTerrainPrimitive->GetVisibleCube()); } bool CTerrainSegment::PVSDrawSegment( const unsigned long uRenderBitVector, KViewportObject** ppViewportList, int nViewportCount, const K3DVector* pFrustum, const K3DVector& rCameraPos, float fVisibleDistance, float fLodDistance, float fDistanceRatio, DWORD dwCurrentTime, unsigned unCurrentRenderTick, int & nRenderPropCnt, PVSObjectManager* pPVSObjManager ) { const int fixFps = 24; bool bPropProcess = true; float msFps = 1000.f / fixFps; if ( (dwCurrentTime - m_dwRenderTime) < msFps ) { bPropProcess = false; } else { m_dwRenderTime = dwCurrentTime; } m_bVisible = pPVSObjManager->CheckSegment( m_nSegmentX, m_nSegmentY ); m_unLastRenderedTick = unCurrentRenderTick; bool bAnyVisible = false, bVPVisible[8] = { false, }; if( m_bVisible ) { //카메라 Frustum Check for(int vit = 0; vit < nViewportCount; ++vit) { m_pTerrainPrimitive->TestRenderObject(); bVPVisible[vit] = KPCCP::nonuniformcube_collide_nonuniformcube(ppViewportList[vit]->GetFrustum(), m_pTerrainPrimitive->GetVisibleCube()); // bAnyVisible은 하나의 viewport에서라도 보이면 체크된다. - 01 if(bVPVisible[vit]) bAnyVisible = true; if(m_pTerrainInfo->NeedPrimitive() == false || bVPVisible[vit] == false) continue; if( uRenderBitVector & Game_RenderSegment ) { if( (ppViewportList[vit]->GetAttributes() & KViewportObject::VIEWPORT_GAME) != 0 || (ppViewportList[vit]->GetAttributes() & KViewportObject::VIEWPORT_WATER) != 0 ) { #ifdef _DEBUG if( s_bCubeRender ) { if( (ppViewportList[vit]->GetAttributes() & KViewportObject::VIEWPORT_GAME) != 0 ) { m_visible_cube.Render( ppViewportList[vit] ); m_segment_cube.Render( ppViewportList[vit] ); } } #endif m_pTerrainPrimitive->CalcLength( rCameraPos ); ppViewportList[vit]->Register( m_pTerrainPrimitive, KRenderObject::RENDEREFX_TERRAIN); if( uRenderBitVector & Game_RenderSegShadow01 ) { if( NULL != m_pTerrainShadowPrimitive && m_pTerrainShadowPrimitive->IsValid() ) { ppViewportList[vit]->Register( m_pTerrainShadowPrimitive, KRenderObject::RENDEREFX_SHADOW_TERRAIN); } } } } } } m_bVisible = bVPVisible[0]; //프랍은 세그먼트와 상관 없이 보일 수 있음. if( true ) { if( bAnyVisible ) { THREAD_SYNCRONIZE( m_PropLock ); bool bPropLoadCompleteFlag = false; for( TERRAINPROP_VECTOR::iterator itLoadingProp = m_NotLoadedPropVector.begin(); itLoadingProp != m_NotLoadedPropVector.end(); ) { CTerrainPropForGame* pProp = (*itLoadingProp); if( pProp->IsRealLoad() ) { bPropLoadCompleteFlag = true; ++itLoadingProp; continue; } if( pProp->IsPendLoading() ) { ++itLoadingProp; continue; } float fPropAlphaRatio = PropOpaqueDistanceRatio; // 카메라와의 거리 체크 float fGapX = rCameraPos.x - pProp->GetPos().x; float fGapY = rCameraPos.y - pProp->GetPos().y; float fCameraDist = sqrtf((fGapX * fGapX) + (fGapY * fGapY)); // 프랍의 크기도 고려 float fPropWidth = pProp->GetBoundCube()->GetWidth(); float fPropLength = pProp->GetBoundCube()->GetLength(); float fRadius = sqrtf((fPropWidth * fPropWidth) + (fPropLength * fPropLength)) / 2.0f; // 시야에 보일만한 거리에 있는 놈들만 로딩건다. if( fVisibleDistance + fRadius*2 > fCameraDist ) { pProp->PendLoading(); } ++itLoadingProp; } if( bPropLoadCompleteFlag ) { ProcessLoadedProps(); } }//if( bAnyVisible ) if( !m_Loaded_PropVector.empty() ) { int prop_visible_count = 0; memset( m_pPropVisibleFlag, 0, m_nPropVisibleFlagCount/8 + 1 ); if( uRenderBitVector & Game_RenderPropProc ) { THREAD_SYNCRONIZE( m_PropLock ); for( TERRAINPROP_VECTOR::iterator itProp = m_Loaded_PropVector.begin(); itProp != m_Loaded_PropVector.end(); itProp++, prop_visible_count++ ) { CTerrainPropForGame* pProp = (*itProp); if( !pPVSObjManager->CheckProp( pProp->GetSegmentIdx(), pProp->GetPropIdx() ) ) continue; if( pProp->GetProcessFlagAtThisTick() ) continue; pProp->SetProcessFlagAtThisTick(); float fBoundary, fPropAlphaRatio = PropOpaqueDistanceRatio; // 카메라와의 거리 체크 float fGapX = rCameraPos.x - pProp->GetPos().x; float fGapY = rCameraPos.y - pProp->GetPos().y; float fCameraDist = sqrtf((fGapX * fGapX) + (fGapY * fGapY)); // 프랍의 크기도 고려 float fPropWidth = pProp->GetBoundCube()->GetWidth(); float fPropLength = pProp->GetBoundCube()->GetLength(); float fRadius = sqrtf((fPropWidth * fPropWidth) + (fPropLength * fPropLength)) / 2.0f; float fDist = fCameraDist - fRadius*2; if(fDist < 0.0f) fDist = 0.0f; ////프랍이 일정거리 이상이면, Process Skip //if( fDist >= PropProcessSkipDist ) // bPropProcess = false; float fPropVisibleRatio = m_pPropInfo->GetPropVisibleRatio( pProp->GetPropNum() ); // 알파가 fBoundary 이하인것은 그리지 않는다. // fBoundary & fPropAlphaRatio 조절 if( fPropVisibleRatio < 2.0f ) { fBoundary = 0.0f; fPropAlphaRatio = 0.6f; } else if( fPropVisibleRatio < 3.0f ) { fBoundary = 0.1f; fPropAlphaRatio = 0.7f; } else if( fPropVisibleRatio < 4.0f ) { fBoundary = 0.2f; fPropAlphaRatio = 0.8f; } else { fBoundary = 0.3f; } float fPropVisibleDistance = fVisibleDistance * fPropVisibleRatio; float fPropAlphaDistance = (fPropVisibleDistance * fPropAlphaRatio); float fPropVisibility = GetPropVisibility( fDist, fPropVisibleDistance * pProp->GetVisRatio(), fPropAlphaDistance * pProp->GetVisRatio() ); // 알파 테스트 if( fBoundary > fPropVisibility ) continue; pProp->SetLodLevel( (fDist < fLodDistance) ? 0 : 1 ); m_pPropVisibleFlag[ prop_visible_count / 8 ] |= ( 1 << ( prop_visible_count % 8 ) ); if( true /*bPropProcess*/ ) { pProp->SetVisibility( fPropVisibility ); //pProp->SetVisible(fCameraDist, fPropVisibleDistance); } pProp->SetFloatLod(fCameraDist, fPropVisibleDistance); } } if( uRenderBitVector & Game_RenderProp ) { THREAD_SYNCRONIZE( m_PropLock ); for(int vit = 0; vit < nViewportCount; ++vit) { if(vit != 0 && bVPVisible[vit] == false) continue; K3DVector *npFrustum = ppViewportList[vit]->GetFrustum(); prop_visible_count = 0; for( TERRAINPROP_VECTOR::iterator itProp = m_Loaded_PropVector.begin(); itProp != m_Loaded_PropVector.end(); itProp++, prop_visible_count++ ) { CTerrainPropForGame* pProp = (*itProp); if( ( 1 << (prop_visible_count % 8) ) & m_pPropVisibleFlag[ ( prop_visible_count / 8 ) ] ) { pProp->ClipTest( npFrustum ); if( !pProp->GetIsClip() ) { pProp->Process( dwCurrentTime ); //현재 랜더링 되는 객체 수, 기본 뷰포트에서 그리는 것만 Count if( (ppViewportList[vit]->GetAttributes() & KViewportObject::VIEWPORT_GAME) ) nRenderPropCnt++; pProp->Render( ppViewportList[vit] ); } } } } } } if( s_bGlassRender && !m_vSpeedGrass.empty() ) {//========================== for(int vit = 0; vit < nViewportCount; ++vit) { if( (ppViewportList[vit]->GetAttributes() & KViewportObject::VIEWPORT_GAME) ) { TERRAINSPEEDGRASS_VECTOR::iterator iter = m_vSpeedGrass.begin(); for( ; iter != m_vSpeedGrass.end(); ++iter ) { (*iter)->Process( dwCurrentTime ); (*iter)->Render( ppViewportList[vit] ); } } } }//========================== } if( m_pTerrainInfo->NeedPrimitive() ) return m_bVisible; else return false; return m_bVisible; } bool CTerrainSegment::DrawSegment( const unsigned long uRenderBitVector, KViewportObject** ppViewportList, int nViewportCount, const K3DVector* pFrustum, const K3DVector& rCameraPos, float fVisibleDistance, float fLodDistance, float fDistanceRatio, DWORD dwCurrentTime, unsigned unCurrentRenderTick, int & nRenderPropCnt, int nLimitDistance/*=0*/ ) { const int fixFps = 24; bool bPropProcess = true; float msFps = 1000.f / fixFps; if ( (dwCurrentTime - m_dwRenderTime) < msFps ) { bPropProcess = false; } else { m_dwRenderTime = dwCurrentTime; } m_unLastRenderedTick = unCurrentRenderTick; bool bAnyVisible = false, bVPVisible[8] = { false, }; //하늘이 아닌 경우만, 랜더 한다. { for(int vit = 0; vit < nViewportCount; ++vit) { m_pTerrainPrimitive->TestRenderObject(); bVPVisible[vit] = KPCCP::nonuniformcube_collide_nonuniformcube(ppViewportList[vit]->GetFrustum(), m_pTerrainPrimitive->GetVisibleCube()); // bAnyVisible은 하나의 viewport에서라도 보이면 체크된다. - 01 if(bVPVisible[vit]) bAnyVisible = true; if(m_pTerrainInfo->NeedPrimitive() == false || bVPVisible[vit] == false) continue; //강제로 마을 같은 경우는 거리 제한이 생긴다. if( nLimitDistance > 0 ) { if( (ppViewportList[vit]->GetAttributes() & KViewportObject::VIEWPORT_GAME) != 0 ) { #ifdef _DEBUG K3DVertex tpos = ppViewportList[vit]->GetCameraTargetPos(); K3DVertex spos = m_pTerrainPrimitive->GetWorldTransform(); #endif float fD1 = K3DVectorLength( ppViewportList[vit]->GetCameraTargetPos() - m_pTerrainPrimitive->GetWorldTransform() ); int nLimit = 3000; if ((m_nMapX == 12) && (m_nMapY == 7)) nLimit = 3500; // 엘카시아 던전에서만 약간 늘림 if( fD1 > nLimit ) continue; } } if( uRenderBitVector & Game_RenderSegment ) { if( (ppViewportList[vit]->GetAttributes() & KViewportObject::VIEWPORT_GAME) != 0 || (ppViewportList[vit]->GetAttributes() & KViewportObject::VIEWPORT_WATER) != 0 ) { #ifdef _DEBUG if( s_bCubeRender ) { if( (ppViewportList[vit]->GetAttributes() & KViewportObject::VIEWPORT_GAME) != 0 ) { m_visible_cube.Render( ppViewportList[vit] ); m_segment_cube.Render( ppViewportList[vit] ); } } #endif m_pTerrainPrimitive->CalcLength( rCameraPos ); ppViewportList[vit]->Register( m_pTerrainPrimitive, KRenderObject::RENDEREFX_TERRAIN); if( uRenderBitVector & Game_RenderSegShadow01 ) { if( NULL != m_pTerrainShadowPrimitive && m_pTerrainShadowPrimitive->IsValid() ) { ppViewportList[vit]->Register( m_pTerrainShadowPrimitive, KRenderObject::RENDEREFX_SHADOW_TERRAIN); } } } } } } // m_bVisibe은 GameViewport에서 보일때만 체크된다. - 01 m_bVisible = bVPVisible[0]; if( bAnyVisible ) { THREAD_SYNCRONIZE( m_PropLock ); bool bPropLoadCompleteFlag = false; for( TERRAINPROP_VECTOR::iterator itLoadingProp = m_NotLoadedPropVector.begin(); itLoadingProp != m_NotLoadedPropVector.end(); ) { CTerrainPropForGame* pProp = (*itLoadingProp); if( pProp->IsRealLoad() ) { bPropLoadCompleteFlag = true; ++itLoadingProp; continue; } if( pProp->IsPendLoading() ) { ++itLoadingProp; continue; } //float fPropAlphaRatio = PropOpaqueDistanceRatio; // 카메라와의 거리 체크 float fGapX = rCameraPos.x - pProp->GetPos().x; float fGapY = rCameraPos.y - pProp->GetPos().y; float fCameraDist = sqrtf((fGapX * fGapX) + (fGapY * fGapY)); // 프랍의 크기도 고려 float fPropWidth = pProp->GetBoundCube()->GetWidth(); float fPropLength = pProp->GetBoundCube()->GetLength(); float fRadius = sqrtf((fPropWidth * fPropWidth) + (fPropLength * fPropLength)) / 2.0f; // 시야에 보일만한 거리에 있는 놈들만 로딩건다. if( fVisibleDistance + fRadius*2 > fCameraDist ) { pProp->PendLoading(); } ++itLoadingProp; } if( bPropLoadCompleteFlag ) { ProcessLoadedProps(); } if( !m_Loaded_PropVector.empty() ) { int prop_visible_count = 0; memset( m_pPropVisibleFlag, 0, m_nPropVisibleFlagCount/8 + 1 ); if( uRenderBitVector & Game_RenderPropProc ) { THREAD_SYNCRONIZE( m_PropLock ); for( TERRAINPROP_VECTOR::iterator itProp = m_Loaded_PropVector.begin(); itProp != m_Loaded_PropVector.end(); itProp++, prop_visible_count++ ) { CTerrainPropForGame* pProp = (*itProp); if( pProp->GetProcessFlagAtThisTick() ) continue; pProp->SetProcessFlagAtThisTick(); float fPropAlphaRatio = PropOpaqueDistanceRatio; // 카메라와의 거리 체크 float fGapX = rCameraPos.x - pProp->GetPos().x; float fGapY = rCameraPos.y - pProp->GetPos().y; float fCameraDist = sqrtf((fGapX * fGapX) + (fGapY * fGapY)); // 프랍의 크기도 고려 float fPropWidth = pProp->GetBoundCube()->GetWidth(); float fPropLength = pProp->GetBoundCube()->GetLength(); float fRadius = sqrtf((fPropWidth * fPropWidth) + (fPropLength * fPropLength)) / 2.0f; float fDist = fCameraDist - fRadius; if(fDist < 0.0f) fDist = 0.0f; ////프랍이 일정거리 이상이면, Process Skip //if( fDist >= PropProcessSkipDist ) // bPropProcess = false; float fPropVisibleRatio = m_pPropInfo->GetPropVisibleRatio( pProp->GetPropNum() ); //// 알파가 fBoundary 이하인것은 그리지 않는다. //// fBoundary & fPropAlphaRatio 조절 //if( fPropVisibleRatio < 0.2f ) { fBoundary = 0.0f; fPropAlphaRatio = 0.6f; } //else if( fPropVisibleRatio < 0.3f ) { fBoundary = 0.1f; fPropAlphaRatio = 0.7f; } //else if( fPropVisibleRatio < 0.4f ) { fBoundary = 0.2f; fPropAlphaRatio = 0.8f; } //else { fBoundary = 0.3f; } float fPropVisibleDistance = fVisibleDistance * fPropVisibleRatio; float fPropAlphaDistance = (fPropVisibleDistance * fPropAlphaRatio); float fPropLodDistance = fLodDistance * fPropVisibleRatio * pProp->GetVisRatio(); float fPropVisibility = GetPropVisibility( fDist, fPropVisibleDistance * pProp->GetVisRatio(), fPropAlphaDistance * pProp->GetVisRatio() ); // 알파 테스트 // if( fBoundary > fPropVisibility ) continue; // if( fPropVisibility <= 0.1f ) continue; pProp->SetLodLevel( ( fDist < fPropLodDistance ) ? 0 : 1 ); m_pPropVisibleFlag[ prop_visible_count / 8 ] |= ( 1 << ( prop_visible_count % 8 ) ); if( bPropProcess ) { pProp->SetVisibility( fPropVisibility ); //pProp->SetVisible(fCameraDist, fPropVisibleDistance); } pProp->SetFloatLod( fCameraDist, fPropLodDistance ); } } if( uRenderBitVector & Game_RenderProp ) { THREAD_SYNCRONIZE( m_PropLock ); for(int vit = 0; vit < nViewportCount; ++vit) { if(bVPVisible[vit] == false) continue; K3DVector *npFrustum = ppViewportList[vit]->GetFrustum(); prop_visible_count = 0; for( TERRAINPROP_VECTOR::iterator itProp = m_Loaded_PropVector.begin(); itProp != m_Loaded_PropVector.end(); itProp++, prop_visible_count++ ) { CTerrainPropForGame* pProp = (*itProp); if( ( 1 << (prop_visible_count % 8) ) & m_pPropVisibleFlag[ ( prop_visible_count / 8 ) ] ) { pProp->ClipTest( npFrustum ); if( !pProp->GetIsClip() ) { pProp->Process( dwCurrentTime ); //강제로 마을 같은 경우는 거리 제한이 생긴다. if( nLimitDistance > 0 ) { #ifdef _DEBUG K3DVertex tpos = ppViewportList[vit]->GetCameraTargetPos(); K3DVertex spos = m_pTerrainPrimitive->GetWorldTransform(); #endif float fD1 = K3DVectorLength( ppViewportList[vit]->GetCameraTargetPos() - pProp->GetTransform().GetPosVector() ); if( fD1 > nLimitDistance ) { //크기가 작은 것들을 우선으로 걸른다. if( pProp->IsSizeCull() ) continue; } } //현재 랜더링 되는 객체 수, 기본 뷰포트에서 그리는 것만 Count if( (ppViewportList[vit]->GetAttributes() & KViewportObject::VIEWPORT_GAME) ) nRenderPropCnt++; pProp->Render( ppViewportList[vit] ); } } } } } } if( s_bGlassRender && !m_vSpeedGrass.empty() ) {//========================== for(int vit = 0; vit < nViewportCount; ++vit) { if( (ppViewportList[vit]->GetAttributes() & KViewportObject::VIEWPORT_GAME) ) { TERRAINSPEEDGRASS_VECTOR::iterator iter = m_vSpeedGrass.begin(); for( ; iter != m_vSpeedGrass.end(); ++iter ) { (*iter)->Process( dwCurrentTime ); (*iter)->Render( ppViewportList[vit] ); } } } }//========================== } if( m_pTerrainInfo->NeedPrimitive() ) return m_bVisible; else return false; return m_bVisible; } TERRAIN_LOD_LEVEL CTerrainSegment::CalcLength( const K3DVector& rCameraPos ) { if( m_pTerrainPrimitive == NULL ) return TERRAIN_LOD_LEVEL_MAX; else { if( m_pTerrainInfo->NeedPrimitive() == false ) return TERRAIN_LOD_LEVEL_MAX; } m_pTerrainPrimitive->CalcLength( rCameraPos ); return m_pTerrainPrimitive->GetTerrainLodLevel(); } void CTerrainSegment::SetNeighborsTerrainLoadLevel( TERRAIN_LOD_LEVEL nLevel, TERRAIN_LOD_CRACK nLodCrack ) { if( m_pTerrainPrimitive ) m_pTerrainPrimitive->SetNeighborsTerrainLoadLevel( nLevel, nLodCrack ); } namespace { inline bool Is2DCollision( float fSrcLeft, float fSrcTop, float fSrcRight, float fSrcBottom, float fDesLeft, float fDesTop, float fDesRight, float fDesBottom ) { return ( std::min( fSrcRight , fDesRight ) > std::max( fSrcLeft, fDesLeft ) && std::min( fSrcBottom, fDesBottom ) > std::max( fSrcTop , fDesTop ) ); } inline void GetPropMinMaxVertices( const CTerrainPropForGame* pProp, K3DVertex& rMin, K3DVertex& rMax ) { const K3DBoundRotCube* pCube = pProp->GetBoundCube(); if( pCube ) { rMin = pCube->GetMinVertex(); rMax = pCube->GetMaxVertex(); } else { assert( 0 ); rMin = K3DVertex( -1, -1, -1 ); rMax = K3DVertex( 1, 1, 1 ); } } } void CTerrainSegment::TakeNeighborsPropInfo( CTerrainSegment *pNeighbor, K3DPoint & ptMinSegment, K3DPoint & ptMaxSegment ) { THREAD_SYNCRONIZE( pNeighbor->m_PropLock ); TERRAINPROP_VECTOR & rPropVector = pNeighbor->m_PropVector; for( TERRAINPROP_VECTOR::iterator itProp = rPropVector.begin(); itProp != rPropVector.end(); itProp++ ) { K3DVertex vtMinProp, vtMaxProp; GetPropMinMaxVertices( (*itProp), vtMinProp, vtMaxProp ); // prop과 세그먼트 영역이 겹치는 경우 prop 정보를 추가시킨다. if( Is2DCollision( vtMinProp.x, vtMinProp.y, vtMaxProp.x, vtMaxProp.y, ptMinSegment.x, ptMinSegment.y, ptMaxSegment.x, ptMaxSegment.y ) ) { AddProp( *itProp ); } } #ifdef _DEBUG float minx,miny,minz,maxx,maxy,maxz; m_pTerrainPrimitive->GetVisibleMinMaxValue( minx,miny,minz,maxx,maxy,maxz ); m_visible_cube = K3DBoundRotCube( minx,maxx, miny,maxy, minz,maxz ); //include prop m_visible_cube.SetWireColor( KColor(0,0,255,255) ); m_visible_cube.SetColorGradation( true ); #endif } void CTerrainSegment::AddProp( CTerrainPropForGame* pProp ) { THREAD_SYNCRONIZE( m_PropLock ); if( std::find( m_PropVector.begin(), m_PropVector.end(), pProp ) == m_PropVector.end() ) { m_PropVector.push_back( CTerrainPropForGameSPtr(pProp) ); if( !pProp->IsRealLoad() ) { m_NotLoadedPropVector.push_back( CTerrainPropForGameSPtr(pProp) ); } //applyProps(); } m_pTerrainPrimitive->SetPropBound( pProp->GetBoundCube()->GetMinVertex(), pProp->GetBoundCube()->GetMaxVertex() ); } bool CTerrainSegment::IsPropLoadCompleted() { THREAD_SYNCRONIZE( &m_PropLock ); for( TERRAINPROP_VECTOR::const_iterator itProp = m_PropVector.begin(); itProp != m_PropVector.end(); itProp++ ) if( !(*itProp)->IsLoadCompleted() ) return false; return true; } float CTerrainSegment::GetPropVisibility( float fCameraDist, float fPropVisibleDist, float fPropAlphaDist ) const { if( fCameraDist > fPropVisibleDist ) return 0.f; if( fCameraDist > fPropAlphaDist ) return 1.f - ( (fCameraDist - fPropAlphaDist) / (fPropVisibleDist - fPropAlphaDist) ); return 1.f; } void CTerrainSegment::AddSpeedGrass( CTerrainSpeedGrassForGame* pSpeedGrass ) { m_vSpeedGrass.push_back( pSpeedGrass ); } void CTerrainSegment::RefreshTerrainLightmap(bool bEnableLightmap) { m_bEnableLightmap = bEnableLightmap; K3DTexture* pLightmapTex = NULL; if(m_bEnableLightmap) pLightmapTex = getLightmapTex(m_nSegmentX, m_nSegmentY); m_pTerrainPrimitive->SetLightMapTex(pLightmapTex); THREAD_SYNCRONIZE( &m_PropLock ); for( TERRAINPROP_VECTOR::iterator itProp = m_PropVector.begin(); itProp != m_PropVector.end(); itProp++ ) (*itProp)->RefreshLightmap(m_bEnableLightmap); }