#pragma once #include "K3DPCCP.h" #include "KRenderDevice.h" #include #include "MapDefine.h" #include "k3dpccp.h" #include "K3dTypes.h" // 지형 데이터 관련 const K3DVector c_DefaultNormal = K3DVector( 0.f, 0.f, 1.f ); const int c_nAttrCountPerTile = 8; const int c_nEventAreaPerTile = 8; const K3DLight c_DefaultLight = K3DLight ( K3DColor( 1.f, 1.f, 1.f ) , K3DColor( 1.f, 1.f, 1.f ) , K3DColor( 0.38f, 0.38f, 0.38f ) , K3DVector( 0.333333f, 0.666666f, -0.666666f ) ); //enum TERRAIN_FILTERING //{ // FILTERING_NONE = 0, // FILTERING_3TEXTURE = 1, // FILTERING_3TEXSHADOW = 2, //}; enum TERRAIN_RENDERMODE { TERRAIN_RENDERMODE_DEFAULT = 0, TERRAIN_RENDERMODE_MULTIPASS, }; enum TERRAIN_LOD_LEVEL { TERRAIN_LOD_LEVEL_1 = 0, TERRAIN_LOD_LEVEL_2, TERRAIN_LOD_LEVEL_MAX, }; enum TERRAIN_LOD_CRACK { TERRAIN_LOD_CRACK_LEFT = 0, TERRAIN_LOD_CRACK_TOP, TERRAIN_LOD_CRACK_RIGHT, TERRAIN_LOD_CRACK_BOTTOM, TERRAIN_LOD_CRACK_MAX, }; enum TERRAIN_LOD_CRACK_EX { TERRAIN_LOD_CRACK_TOP_LEFT = 0, TERRAIN_LOD_CRACK_BOTTOM_RIGHT, TERRAIN_LOD_CRACK_EX_MAX, }; enum TERRAIN_COMMON_INDEXBUFFER { TERRAIN_COMMON_IB = 0, TERRAIN_COMMON_IB_LOD, TERRAIN_COMMON_IB_CRACK, TERRAIN_COMMON_IB_MAX, }; const int c_nSegmentLodTileCount = 2; const int c_nCrackBySegmentIndex[TERRAIN_LOD_CRACK_MAX][2] = { { 0,-1}, ///< left { -1, 0}, ///< top { 0, 1}, ///< right { 1, 0}, ///< bottom }; class CTerrainInfo { public: virtual WORD GetTile( int nX, int nY ) const = 0; virtual WORD GetFillBit( int nStage, int nX, int nY ) const = 0; virtual float GetHeight( int nX, int nY ) const = 0; virtual unsigned __int64 GetAttrData( int nX, int nY ) const = 0; virtual KTripleColor GetColor( int nX, int nY ) const = 0; virtual K3DVertex GetVertex( int nX, int nY ) const = 0; virtual K3DVector GetVertexNormalVector( int nX, int nY ) const = 0; virtual BYTE GetVertexCoverageFactor( int nStage, int nX, int nY ) const = 0; virtual bool GetAttribute( int nAttrX, int nAttrY ) const = 0; virtual float GetZ( float x, float y ) const = 0; public: static K3DVector BuildNormalVector( K3DVertex v1, K3DVertex v2, K3DVertex v3 ) { float x = float((v2.z - v1.z) * (v3.y - v1.y) - (v2.y - v1.y) * (v3.z - v1.z)); float y = float((v2.x - v1.x) * (v3.z - v1.z) - (v2.z - v1.z) * (v3.x - v1.x)); float z = float((v2.y - v1.y) * (v3.x - v1.x) - (v2.x - v1.x) * (v3.y - v1.y)); float fLength = float(sqrt( (x * x) + (y * y) + (z * z) )); return (fLength != 0.f) ? K3DVector( x / fLength, y / fLength, z / fLength ) : c_DefaultNormal; } }; class CEditableTerrainInfo : public CTerrainInfo { public: virtual void SetTile( int nStage, int nX, int nY, WORD wTileIndex ) = 0; virtual void SetFillBit( int nStage, int nX, int nY, DWORD wFillBits ) = 0; virtual void AddHeightData( int nX, int nY, float fAdd ) = 0; virtual void SetHeightData( int nX, int nY, float fHeight ) = 0; virtual void SetAttrData( int nX, int nY, unsigned __int64 wAttribute ) = 0; virtual void SetColor( int nX, int nY, const KTripleColor& rColor ) = 0; virtual void SetAttribute( int nAttrX, int nAttrY, bool bBlock ) = 0; virtual void SetEventArea( int nX, int nY, bool bBlock ) = 0; }; class CTerrainUtil { public: /* 공간에 놓인 사각형과 선분의 교점을 구한다. 동일평면 상에 놓인 사각형을 이루는 4개의 버텍스. 순서는 다음과 같다. ^ | +-------+ | |2 |3 | | | | | | | +-------+ | 0 1 +---------------> 0->1->2의 삼각형과 1->3->2의 삼각형 2개를 각각 체크한다. */ static float GetLineCrossedPointTwoSides( const K3DVertex* pFourVertices, const K3DVector& rNear, const K3DVector& rFar, K3DVector& rIntersect ) { float fT = 1.0f, fSmallestT = 1.0f; K3DVector rTempIntersect, rCandidateIntersect; fT = KPCCP::triangle_collide_edge_twosides(pFourVertices[0], pFourVertices[1], pFourVertices[2], rNear, rFar, rTempIntersect); if(fSmallestT > fT) { fSmallestT = fT; rCandidateIntersect = rTempIntersect; } fT = KPCCP::triangle_collide_edge_twosides(pFourVertices[1], pFourVertices[3], pFourVertices[2], rNear, rFar, rTempIntersect); if(fSmallestT > fT) { fSmallestT = fT; rCandidateIntersect = rTempIntersect; } if(fSmallestT != 1.0f) { rIntersect = rCandidateIntersect; } return fSmallestT; } static bool GetLineCrossedPoint( const K3DVertex* pFourVertices, const K3DVector& rNear, const K3DVector& rFar, K3DVector& rIntersect ) { K3DPlane plane; if( KPCCP::triangle_collide_edge( pFourVertices[0], pFourVertices[1], pFourVertices[2], rNear, rFar ) ) { if( K3DPlaneFromPoints( plane, pFourVertices[0], pFourVertices[1], pFourVertices[2] ) ) if( K3DPlaneIntersectLine( rIntersect, plane, rNear, rFar ) ) return true; } if( KPCCP::triangle_collide_edge( pFourVertices[1], pFourVertices[3], pFourVertices[2], rNear, rFar ) ) { if( K3DPlaneFromPoints( plane, pFourVertices[1], pFourVertices[3], pFourVertices[2] ) ) if( K3DPlaneIntersectLine( rIntersect, plane, rNear, rFar ) ) return true; } return false; } /// 0->1->2의 삼각형과 1->3->2의 삼각형 2개를 각각 양면 모두 체크한다. static bool GetLineCrossedPointBothFaces( const K3DVertex* pFourVertices, const K3DVector& rNear, const K3DVector& rFar, K3DVector& rIntersect ) { K3DPlane plane; if( KPCCP::triangle_collide_edge( pFourVertices[0], pFourVertices[1], pFourVertices[2], rNear, rFar ) ) { if( K3DPlaneFromPoints( plane, pFourVertices[0], pFourVertices[1], pFourVertices[2] ) ) if( K3DPlaneIntersectLine( rIntersect, plane, rNear, rFar ) ) return true; } if( KPCCP::triangle_collide_edge( pFourVertices[1], pFourVertices[3], pFourVertices[2], rNear, rFar ) ) { if( K3DPlaneFromPoints( plane, pFourVertices[1], pFourVertices[3], pFourVertices[2] ) ) if( K3DPlaneIntersectLine( rIntersect, plane, rNear, rFar ) ) return true; } if( KPCCP::triangle_collide_edge( pFourVertices[2], pFourVertices[1], pFourVertices[0], rNear, rFar ) ) { if( K3DPlaneFromPoints( plane, pFourVertices[2], pFourVertices[1], pFourVertices[0] ) ) if( K3DPlaneIntersectLine( rIntersect, plane, rNear, rFar ) ) return true; } if( KPCCP::triangle_collide_edge( pFourVertices[2], pFourVertices[3], pFourVertices[1], rNear, rFar ) ) { if( K3DPlaneFromPoints( plane, pFourVertices[2], pFourVertices[3], pFourVertices[1] ) ) if( K3DPlaneIntersectLine( rIntersect, plane, rNear, rFar ) ) return true; } return false; } /// { [sonador][7.1.7]충돌 처리 개선(Swept Shpere Collision Detection) static bool GetEllipsoidCrossedPoint( const K3DVector* pFourVertices, const K3DVector& rBase, const K3DVector& rVelocity, float& fNearestT, K3DVector& rIntersect #ifdef _DEBUG , K3DVector* pCollidedPolygon #endif ) { // all vectors passed by argument must be in ellipsoid vector space, so ellipsoid must be unit sphere bool bFound = false; float fT = 1.0f; K3DVector vIntersectionCandidate; if( KPCCP::triangle_collide_swept_unit_sphere( pFourVertices[ 0 ], pFourVertices[ 1 ], pFourVertices[ 2 ], rBase, rVelocity, vIntersectionCandidate, fT ) && ( fNearestT > fT ) ) { bFound = true; fNearestT = fT; rIntersect = vIntersectionCandidate; #ifdef _DEBUG pCollidedPolygon[ 0 ] = pFourVertices[ 0 ]; pCollidedPolygon[ 1 ] = pFourVertices[ 1 ]; pCollidedPolygon[ 2 ] = pFourVertices[ 2 ]; #endif } if( KPCCP::triangle_collide_swept_unit_sphere( pFourVertices[ 1 ], pFourVertices[ 3 ], pFourVertices[ 2 ], rBase, rVelocity, vIntersectionCandidate, fT ) && ( fNearestT > fT ) ) { bFound = true; fNearestT = fT; rIntersect = vIntersectionCandidate; #ifdef _DEBUG pCollidedPolygon[ 0 ] = pFourVertices[ 1 ]; pCollidedPolygon[ 1 ] = pFourVertices[ 3 ]; pCollidedPolygon[ 2 ] = pFourVertices[ 2 ]; #endif } return bFound; } // } /// 주어진 점이 삼각형( z값을 무시한 xy평면에 투영된 삼각형 ) 안에 있는지 확인 static bool IsInside2DPolygon( const K3DVertex& rVtx1, const K3DVertex& rVtx2, const K3DVertex& rVtx3, float x, float y ) { float r1 = (rVtx2.y - rVtx1.y) * (x - rVtx1.x) - (rVtx2.x - rVtx1.x) * (y - rVtx1.y); float r2 = (rVtx3.y - rVtx2.y) * (x - rVtx2.x) - (rVtx3.x - rVtx2.x) * (y - rVtx2.y); float r3 = (rVtx1.y - rVtx3.y) * (x - rVtx3.x) - (rVtx1.x - rVtx3.x) * (y - rVtx3.y); return (r1 >= 0) ? ((r2 >= 0) && (r3 >= 0)) : ((r2 <= 0) && (r3 <= 0)); } /// 주어진 삼각형 내의 특정 (x, y)점의 z값을 구한다. static float GetHeightForPolygon( const K3DVertex& rVtx1, const K3DVertex& rVtx2, const K3DVertex& rVtx3, float x, float y ) { float a = (x - rVtx1.x); float b = (rVtx3.y - rVtx1.y); float c = (rVtx3.x - rVtx1.x); float d = (y - rVtx1.y); float e = (rVtx2.z - rVtx1.z); float f = (rVtx2.x - rVtx1.x); float g = (rVtx2.y - rVtx1.y); float h = (rVtx3.z - rVtx1.z); float i = (f * b) - (c * g); if (i == 0.f) { if( f != 0.f ) return (rVtx1.z + a * e / f); if( b != 0.f ) return (rVtx1.z + d * e / b); if( c != 0.f ) return (rVtx1.z + a * h / c); if( g != 0.f ) return (rVtx1.z + d * h / g); } return (rVtx1.z + ( ((a * b) - (c * d)) * e + ((f * d) - (a * g)) * h ) / i); } }; struct TERRAINMAP_PROPERTIES { struct COLORING { K3DLight litPrimary; ///< 지형 라이트 K3DLight litSecondary; ///< 캐랙터, prop용 라이트 KColor colorSky; ///< 하늘 색상 KColor colorFog; ///< 포그 색상 float fFogNear, fFogFar; ///< 포그 거리 설정 DWORD dwSkyType; ///< 하늘(구름) 타입 COLORING() : litPrimary( c_DefaultLight ) , litSecondary( c_DefaultLight ) , colorSky( KColor( 204, 222, 248, 255 ) ) , colorFog( KColor( 204, 222, 248, 255 ) ) , fFogNear( 1024.f ) , fFogFar( 4096.f ) , dwSkyType( 0 ) { } void LoadStream( KStream* pStream ) { KTripleColor color; LoadColor( pStream, color ); litPrimary.diffuse = K3DColor( color ); LoadColor( pStream, color ); litPrimary.ambient = K3DColor( color ); LoadVector( pStream, litPrimary.direction ); LoadColor( pStream, color ); litSecondary.diffuse = K3DColor( color ); LoadColor( pStream, color ); litSecondary.ambient = K3DColor( color ); LoadVector( pStream, litSecondary.direction ); LoadColor( pStream, color ); colorSky = color; LoadColor( pStream, color ); colorFog = color; pStream->Read( &fFogNear, sizeof(fFogNear) ); pStream->Read( &fFogFar, sizeof(fFogFar) ); pStream->Read( &dwSkyType, sizeof(dwSkyType) ); } void SaveStream( KStream* pStream ) const { KTripleColor color; color = (KTripleColor)litPrimary.diffuse; SaveColor( pStream, color ); color = (KTripleColor)litPrimary.ambient; SaveColor( pStream, color ); SaveVector( pStream, litPrimary.direction ); color = (KTripleColor)litSecondary.diffuse; SaveColor( pStream, color ); color = (KTripleColor)litSecondary.ambient; SaveColor( pStream, color ); SaveVector( pStream, litSecondary.direction ); SaveColor( pStream, KTripleColor( colorSky ) ); SaveColor( pStream, KTripleColor( colorFog ) ); pStream->Write( &fFogNear, sizeof(fFogNear) ); pStream->Write( &fFogFar, sizeof(fFogFar) ); pStream->Write( &dwSkyType, sizeof(dwSkyType) ); } bool operator!=( const COLORING& r ) const { return ( litPrimary.diffuse != r.litPrimary.diffuse || litPrimary.ambient != r.litPrimary.ambient || litPrimary.direction != r.litPrimary.direction || litSecondary.diffuse != r.litSecondary.diffuse || litSecondary.ambient != r.litSecondary.ambient || litSecondary.direction != r.litSecondary.direction || colorSky.color != r.colorSky.color || colorFog.color != r.colorFog.color || fFogNear != r.fFogNear || fFogFar != r.fFogFar || dwSkyType != r.dwSkyType ); } private: static void LoadColor( KStream* pStream, KTripleColor& rColor ) { pStream->Read( &(rColor.r), sizeof(rColor.r) ); pStream->Read( &(rColor.g), sizeof(rColor.g) ); pStream->Read( &(rColor.b), sizeof(rColor.b) ); } static void SaveColor( KStream* pStream, const KTripleColor& rColor ) { pStream->Write( &(rColor.r), sizeof(rColor.r) ); pStream->Write( &(rColor.g), sizeof(rColor.g) ); pStream->Write( &(rColor.b), sizeof(rColor.b) ); } static void LoadVector( KStream* pStream, K3DVector& rVector ) { pStream->Read( &(rVector.x), sizeof(rVector.x) ); pStream->Read( &(rVector.y), sizeof(rVector.y) ); pStream->Read( &(rVector.z), sizeof(rVector.z) ); } static void SaveVector( KStream* pStream, const K3DVector& rVector ) { pStream->Write( &(rVector.x), sizeof(rVector.x) ); pStream->Write( &(rVector.y), sizeof(rVector.y) ); pStream->Write( &(rVector.z), sizeof(rVector.z) ); } }; COLORING Coloring; bool bShowTerrainInGame; ///< 게임에서 지형 표시 여부 TERRAINMAP_PROPERTIES() : bShowTerrainInGame( true ) { } void LoadProperties( KStream* pStream ) { Coloring.LoadStream( pStream ); pStream->Read( &bShowTerrainInGame, sizeof(bShowTerrainInGame) ); } void SaveProperties( KStream* pStream ) const { Coloring.SaveStream( pStream ); pStream->Write( &bShowTerrainInGame, sizeof(bShowTerrainInGame) ); } };