#pragma once #include #include "KPrimitive.h" #include "TerrainDefine.h" #include "TerrainCustomTexturePrimitive.h" #include "TerrainTextureInfo.h" #include "KViewport.h" #include "k3dpccp.h" #ifdef _RAC #include "TerrainPropForGame.h" #endif const float VIEW_DELTA = 500.f; class CTerrainPrimitive : public K3DPrimitive { public: CTerrainPrimitive( int nVertexCount, K3DIndexBuffer* pCommonIndexBuffer, const CTerrainInfo* pTerrainInfo ) : m_nVertexCount( nVertexCount ) , m_spCommonIndexBuffer(pCommonIndexBuffer) , m_pOriginCorrection( NULL ) , m_vtWorldTransform( K3DVertex( 0.f, 0.f, 0.f ) ) , m_nTerrainLoadLevel( TERRAIN_LOD_LEVEL_1 ) { m_type = KPRIMITIVE_TERRAIN; m_pVB = NULL; m_nIndexVB = -1; m_vertexMin = pTerrainInfo->GetVertex( 0, 0 ); m_vertexMax = pTerrainInfo->GetVertex( m_nVertexCount - 1, m_nVertexCount - 1 ); m_vtCenterWorldTransform = pTerrainInfo->GetVertex( (m_nVertexCount - 1)/2, (m_nVertexCount - 1)/2 ); for( int nY = 0; nY < m_nVertexCount; ++nY ) { for( int nX = 0; nX < m_nVertexCount; ++nX ) { float fZ = pTerrainInfo->GetHeight( nX, nY ); if( fZ < m_vertexMin.z ) m_vertexMin.z = fZ; if( fZ > m_vertexMax.z ) m_vertexMax.z = fZ; } } m_vMinProp = m_vertexMin; m_vMaxProp = m_vertexMax; CreateTerrainCube(); CreateVisibleCube(); m_bUpdateLength = false; m_nTerrainLoadLevel = TERRAIN_LOD_LEVEL_1; for( int i = 0; i < TERRAIN_LOD_CRACK_MAX; ++i ) m_nNeighborsTerrainLoadLevel[i] = TERRAIN_LOD_LEVEL_1; } virtual ~CTerrainPrimitive() { } void SetOriginCorrection( const K3DVertex* pOriginCorrection = NULL ) { m_pOriginCorrection = pOriginCorrection; } const K3DVertex* GetVisibleCube() const { return m_VisibleCube; } const K3DVertex* GetTerrainCube() const { return m_TerrainCube; } void SetPropBound( const K3DVector &vMinProp, const K3DVector &vMaxProp ) { bool bIsCheck = false; if( m_vMinProp.x > vMinProp.x ) { m_vMinProp.x = vMinProp.x; bIsCheck = true; } if( m_vMinProp.y > vMinProp.y ) { m_vMinProp.y = vMinProp.y; bIsCheck = true; } if( m_vMinProp.z > vMinProp.z ) { m_vMinProp.z = vMinProp.z; bIsCheck = true; } if( m_vMaxProp.x < vMaxProp.x ) { m_vMaxProp.x = vMaxProp.x; bIsCheck = true; } if( m_vMaxProp.y < vMaxProp.y ) { m_vMaxProp.y = vMaxProp.y; bIsCheck = true; } if( m_vMaxProp.z < vMaxProp.z ) { m_vMaxProp.z = vMaxProp.z; bIsCheck = true; } if( bIsCheck ) CreateVisibleCube(); } CTerrainCustomTexturePrimitive* CreateCustomTexturePrimitive() #ifdef _RAC { return new CTerrainCustomTexturePrimitive( m_pVB, m_spCommonIndexBuffer, m_vtWorldTransform ); } #else { return new CTerrainCustomTexturePrimitive( m_spVB, m_spCommonIndexBuffer, m_vtWorldTransform ); } #endif #ifdef _RAC virtual void ReloadProp(TERRAINPROP_VECTOR &listPropVector) {} #endif virtual void TestRenderObject() {} virtual void Render( KViewportObject *viewport, class K3DRenderDevice *dev, bool bUseAccum = true ) = 0; inline bool CheckFogFar( KViewportObject* viewport ) { float fNear, fFar, fTop, fBottom; float fLen = ( m_vtWorldTransform - K3DVector(viewport->GetCameraTargetPos().x, viewport->GetCameraTargetPos().y,0) ).Magnitude(); viewport->GetFogFactor( fNear, fFar, fTop, fBottom ); if( fLen >= (fFar-VIEW_DELTA) ) //포그 Far 보다 멀면, 텍스쳐 설정 NULL return true; return false; } const K3DVertex& GetWorldTransform() { return m_vtWorldTransform; } const K3DVertex& GetCenterWorldTransform() { return m_vtCenterWorldTransform; } /// terrain list를 rendering 하기 전에 불리움 virtual void PreRenderPrimitiveGroup(K3DRenderDevice* pDev, KViewportObject* pViewport) {} /// terrain list를 전부 rendering 하고 나서 불리움 ( viewport에서 call해줌) virtual void PostRenderPrimitiveGroup(K3DRenderDevice* pDev, KViewportObject* pViewport) {} virtual void SetLightMapTex(K3DTexture* pLightmapTex) {} void GetVisibleMinMaxValue( float& minX, float& minY, float& minZ, float& maxX, float& maxY, float& maxZ ) { minX = min(m_vertexMin.x, m_vMinProp.x); maxX = max(m_vertexMax.x, m_vMaxProp.x); minY = min(m_vertexMin.y, m_vMinProp.y); maxY = max(m_vertexMax.y, m_vMaxProp.y); minZ = min(m_vertexMin.z, m_vMinProp.z); maxZ = max(m_vertexMax.z, m_vMaxProp.z); } void GetSegmentMinMaxValue( float& minX, float& minY, float& minZ, float& maxX, float& maxY, float& maxZ ) { //지형만 큐브 minX = m_vertexMin.x; maxX = m_vertexMax.x; minY = m_vertexMin.y; maxY = m_vertexMax.y; minZ = m_vertexMin.z; maxZ = m_vertexMax.z; } static void SetCheckOcclusionCulling( bool bCheck ) { s_CheckOcclusionCulling = bCheck; } virtual void CalcLength( const K3DVector& rCameraPos ) {} void SetTerrainLodLevel( TERRAIN_LOD_LEVEL nLevel ) { m_nTerrainLoadLevel = nLevel; } void SetNeighborsTerrainLoadLevel( TERRAIN_LOD_LEVEL nLevel, TERRAIN_LOD_CRACK nLodCrack ) { m_nNeighborsTerrainLoadLevel[nLodCrack] = nLevel; } public: // for Editor virtual bool RefreshHeight( const CTerrainInfo* pTerrainInfo, K3DRenderDevice* pDev ) = 0; virtual bool RefreshTile( const CTerrainInfo* pTerrainInfo, K3DRenderDevice* pDev ) = 0; virtual bool RefreshColor( const CTerrainInfo* pTerrainInfo, K3DRenderDevice* pDev ) = 0; public: // For vertex manipulation (color reading) K3DVertexBufferSPtr *GetVertexBuffer() { return &m_spVB; } int GetVertexCount() { return m_nVertexCount; } ///< actually (m_nVertexCount*m_nVertexCount) vertexes in vertex-buffer TERRAIN_LOD_LEVEL GetTerrainLodLevel() { return m_nTerrainLoadLevel; } TERRAIN_LOD_LEVEL GetNeighborsTerrainLoadLevel( TERRAIN_LOD_CRACK nLodCrack ) { return m_nNeighborsTerrainLoadLevel[nLodCrack]; } protected: K3DVertexBufferSPtr m_spVB; K3DVertexBuffer* m_pVB; int m_nIndexVB; K3DIndexBufferSPtr m_spCommonIndexBuffer; const K3DVertex* m_pOriginCorrection; K3DVertex m_vtWorldTransform; K3DVertex m_vtCenterWorldTransform; int m_nVertexCount; K3DVertex m_VisibleCube[8]; K3DVertex m_TerrainCube[8]; K3DVertex m_vMinProp, m_vMaxProp; K3DVertex m_vertexMin, m_vertexMax; static bool s_CheckOcclusionCulling; TERRAIN_LOD_LEVEL m_nTerrainLoadLevel; TERRAIN_LOD_LEVEL m_nNeighborsTerrainLoadLevel[TERRAIN_LOD_CRACK_MAX]; bool m_bUpdateLength; void CreateVisibleCube() { float minx = min(m_vertexMin.x, m_vMinProp.x); float maxx = max(m_vertexMax.x, m_vMaxProp.x); float miny = min(m_vertexMin.y, m_vMinProp.y); float maxy = max(m_vertexMax.y, m_vMaxProp.y); float minz = min(m_vertexMin.z, m_vMinProp.z); float maxz = max(m_vertexMax.z, m_vMaxProp.z); //프랍과 합쳐진 큐브 m_VisibleCube[0] = KPCCP::get_cube_vertex(0, minx, maxx, miny, maxy, minz, maxz); m_VisibleCube[1] = KPCCP::get_cube_vertex(1, minx, maxx, miny, maxy, minz, maxz); m_VisibleCube[2] = KPCCP::get_cube_vertex(2, minx, maxx, miny, maxy, minz, maxz); m_VisibleCube[3] = KPCCP::get_cube_vertex(3, minx, maxx, miny, maxy, minz, maxz); m_VisibleCube[4] = KPCCP::get_cube_vertex(4, minx, maxx, miny, maxy, minz, maxz); m_VisibleCube[5] = KPCCP::get_cube_vertex(5, minx, maxx, miny, maxy, minz, maxz); m_VisibleCube[6] = KPCCP::get_cube_vertex(6, minx, maxx, miny, maxy, minz, maxz); m_VisibleCube[7] = KPCCP::get_cube_vertex(7, minx, maxx, miny, maxy, minz, maxz); } void CreateTerrainCube() { //지형만 큐브 float minx = m_vertexMin.x; float maxx = m_vertexMax.x; float miny = m_vertexMin.y; float maxy = m_vertexMax.y; float minz = m_vertexMin.z; float maxz = m_vertexMax.z; m_TerrainCube[0] = KPCCP::get_cube_vertex(0, minx, maxx, miny, maxy, minz, maxz); m_TerrainCube[1] = KPCCP::get_cube_vertex(1, minx, maxx, miny, maxy, minz, maxz); m_TerrainCube[2] = KPCCP::get_cube_vertex(2, minx, maxx, miny, maxy, minz, maxz); m_TerrainCube[3] = KPCCP::get_cube_vertex(3, minx, maxx, miny, maxy, minz, maxz); m_TerrainCube[4] = KPCCP::get_cube_vertex(4, minx, maxx, miny, maxy, minz, maxz); m_TerrainCube[5] = KPCCP::get_cube_vertex(5, minx, maxx, miny, maxy, minz, maxz); m_TerrainCube[6] = KPCCP::get_cube_vertex(6, minx, maxx, miny, maxy, minz, maxz); m_TerrainCube[7] = KPCCP::get_cube_vertex(7, minx, maxx, miny, maxy, minz, maxz); } public: static K3DIndexBuffer* CreateCommonIndexBuffer( int nTileCount, K3DRenderDevice* pDev ) { assert( pDev && "Device Lost???" ); if( pDev == NULL ) return NULL; int nVertexCount = (nTileCount + 1); K3DIndexBuffer* pCommonIndexBuffer = pDev->CreateIndexBuffer( (nTileCount * nTileCount) * 3 * 2 ); // 1타일 당 삼각형 2개 if( !pCommonIndexBuffer ) return NULL; int nSize; WORD* pIndices; // 인덱스 버퍼 Lock pCommonIndexBuffer->Lock( (void**)&pIndices, nSize ); if( !pIndices ) { pCommonIndexBuffer->Discard(); return NULL; } WORD* debug = pIndices; for( int nY = 0; nY < nTileCount; ++nY ) { for( int nX = 0; nX < nTileCount; ++nX ) { WORD wIndex = static_cast((nY * nVertexCount) + nX); *pIndices++ = wIndex; *pIndices++ = wIndex + (WORD)nVertexCount; *pIndices++ = wIndex + 1; *pIndices++ = wIndex + 1; *pIndices++ = wIndex + (WORD)nVertexCount; *pIndices++ = wIndex + (WORD)nVertexCount + 1; } } pCommonIndexBuffer->Unlock(); return pCommonIndexBuffer; } static K3DIndexBuffer* CreateCommonCrackIndexBuffer( K3DRenderDevice* pDev ) { assert( pDev && "Device Lost???" ); if( pDev == NULL ) return NULL; K3DIndexBuffer* pCommonIndexBuffer = pDev->CreateIndexBuffer( 8 ); if( !pCommonIndexBuffer ) return NULL; int nSize; WORD* pIndices; // 인덱스 버퍼 Lock pCommonIndexBuffer->Lock( (void**)&pIndices, nSize ); if( !pIndices ) { pCommonIndexBuffer->Discard(); return NULL; } *pIndices++ = 0; *pIndices++ = 7; *pIndices++ = 8; *pIndices++ = 9; *pIndices++ = 10; *pIndices++ = 11; *pIndices++ = 12; *pIndices++ = 13; pCommonIndexBuffer->Unlock(); return pCommonIndexBuffer; } };