#pragma once #ifdef _DEV #include #else #include #endif #include #include #include "TerrainDefine.h" #include "TerrainSegment.h" #include "TerrainInfoForSegment.h" #include "TerrainSegmentLoadThread.h" #include #include #include "K3DTypes.h" class K3DCamera; class CTerrainSeamlessWorldInfo; class CTerrainTextureInfo; class CTerrainPropInfo; class CTerrainLocationInfoForMap; class CTerrainEventAreaInfoForMap; class CTerrainLowQualityWaterInfo; class CGrassColonyInfoContainer; class CTerrainGrassColonyInfoForMap; class KSeqSpeedGrass; class CTerrainMapEngine { public: CTerrainMapEngine(); virtual ~CTerrainMapEngine(); bool Initialize ( K3DRenderDevice* pDevice , K3DCamera* pCamera //, TERRAIN_FILTERING FilteringType , TERRAIN_RENDERMODE RenderMode , DWORD dwSegmentRemovePeriod , DWORD dwSegmentExpireTime , int nThreadCount = 3 ); void Release(); int GetTileCount(); const CTerrainSeamlessWorldInfo* GetSeamlessWorldInfo() const { return m_pSeamlessWorldInfo; } const CTerrainPropInfo* GetPropInfo() const { return m_pPropInfo; } /// 타일의 한쪽면 길이 float GetTileLength() const { return m_fTileLength; } /// 속성 셀의 한쪽면 길이 float GetAttrCellLength() const { return m_fAttrCellLength; } //TERRAIN_FILTERING GetFilteringType() const { return m_FilteringType; } TERRAIN_RENDERMODE GetRenderMode() const { return m_RenderMode; } void SetRenderMode( TERRAIN_RENDERMODE Mode ); /// 0은 무제한이므로 viewport에 지정된 거리까지 모두 보인다. ( 권장하지 않음. ) float GetTerrainVisibleDistance() const { return m_fTerrainVisibleDistance; } float GetTerrainVisibleDistanceRatio() const { return m_fTerrainVisibleDistanceRatio; } void SetTerrainVisibleDistance( float fDistance ); void SetTerrainVisibleDistanceRatio( float fRatio ); /// 0은 시야 거리까지 float GetPickingDistance() const { return ::sqrt( m_fPickingSquareDistance ); } void SetPickingDistance( float fDistance = 0.f ) { m_fPickingSquareDistance = (fDistance * fDistance); } float GetPropLodDistance() const { return m_fPropLodDistance; } void SetPropLodDistance( float fDistance ) { m_fPropLodDistance = fDistance; } /// sonador #2.1.7.1 스피드 트리 퍼포먼스 증가 float GetPropLodDistanceRatio() const { return m_fPropLodDistanceRatio; } void SetPropLodDistanceRatio( float fRatio ); TERRAIN_PICK_RESULT GetLineCrossedPoint( const K3DCamera* pCamera, const K3DVector& rNear, const K3DVector& rFar, K3DVector& rPickedPoint ); float GetLineCrossedPointTwoSides( const K3DCamera* pCamera, const K3DVector& rNear, const K3DVector& rFar, K3DVector& rPickedPoint ); // { [sonador][COLLIDABLE_CAMERA] bool GetPropLineCrossedPointTwoSidesWithCollisionMesh ( const K3DVector& rNear , const K3DVector& rFar , float& fNearestT , K3DVector& rPickedPoint #ifdef _DEBUG , K3DVector* pCollidedPolygon #endif ) const; // } /// { [sonador][7.1.7]충돌 처리 개선(Swept Shpere Collision Detection) bool GetTerrainEllipsoidCrossedPoint ( const K3DVector& rBase , const K3DVector& rVelocity , const K3DVector& rRadius , float& fNearestT , K3DVector& rPickedPoint #ifdef _DEBUG , K3DVector* pCollidedPolygon , std::vector< std::pair< K3DVector, KColor > >& vecDebugLine #endif ) const; bool GetPropEllipsoidCrossedPointTwoSides ( const K3DVector& rNear , const K3DVector& rFar , const K3DVector& rRadius , float& fNearestT , K3DVector& rPickedPoint #ifdef _DEBUG , K3DVector* pCollidedPolygon #endif ) const; // } bool GetTerrainHeight( float x, float y, float& out, WORD& wTile, bool* pOutOnProp = NULL ) const; bool GetOnlyTerrainHeight( float x, float y, float& out ) const; void GetTerrainTriangle(float x, float y, K3DVector& v1, K3DVector& v2, K3DVector& v3) const; bool GetTerrainColor( float x, float y, KTripleColor &out ) const; void GetNearVertices( float x, float y, int cx, int cy, K3DVertex* pGetVertices ) const; CTerrainProp* GetTerrainProp( float x, float y, float& out ) const; bool IsBlockedAttribute( float x, float y ) const { return IsBlockedAttribute( KPoint( int(x / m_fAttrCellLength), int(y / m_fAttrCellLength) ) ); } bool IsBlockedAttribute( const KPoint& rAttrPos ) const; const TERRAINMAP_PROPERTIES::COLORING& GetMapColoring() { return m_CurrentMapColoring; } /// 2011.11.09 월드 좌표를 맵 좌표로 변환 - prodongi void convertWorldToMapPos(int worldPosX, int worldPosY, int& mapX, int& mapY); /// 2011.11.09 preloadingDistance 추가 - prodongi void PreloadingSegments( float x, float y, bool bAsyncLoading = false, const K3DVector* pFrustum = NULL, int preloadingDistance = 0 ); /// 시야 범위 내의 세그먼트가 모두 로드되어 있는지 확인 ( 비동기 방식으로 PreloadingSegments() 호출 후 로딩여부 확인에 사용 ) bool IsCompletelyLoadedVisibleSegment() const; // const CTerrainScriptInfoForMap* GetMinimapInfo( int nMapPosX, int nMapPosY ) const; void SetCustomTexture( K3DTexture* pTexture = NULL ) { m_spCustomTexture = pTexture; } void SetCustomTextureMatrix( const K3DMatrix* pMatrix = NULL ) { m_pCustomMatrix = pMatrix; } float GetCustomTextureDistance() const { return ::sqrt( m_fCustomTextureSquareDist ); } void SetCustomTextureDistance( float fDistance ) { m_fCustomTextureSquareDist = (fDistance * fDistance); } void Render( unsigned long uRenderBitVector, K3DCamera* pCamera, KViewportObject** ppViewport, int nViewportCount, int nLimitDistance = 0 ); bool Process( DWORD dwTime, K3DCamera* pCamera = NULL ); void AfterRender( unsigned long uRenderBitVector ); void WarpClear( float fWarpPosX, float fWarpPosY ); static unsigned GetLastRenderedTime() { return m_unLastRenderedTime; } static unsigned GetLastRenderedTick() { return m_unLastRenderedTick; } static bool IsRenderedSegment( CTerrainSegment* pSeg ) { return pSeg->GetLastRenderedTick() == m_unLastRenderedTick; } bool CreateSegment( int nSegmentX, int nSegmentY, CTerrainInfoForSegment* pTerrainInfo, CTerrainInfoForSegment::PROPLOAD_INFO& PropLoadInfom, CTerrainInfoForSegment::SPEEDGRASSLOAD_INFO & SpeedGrassInfo); /// GetSegmentIndex()의 역변환 KPoint GetSegmentPos( int nSegmentIndex ) const { return KPoint( (nSegmentIndex % m_nSegmentXCount), (nSegmentIndex / m_nSegmentXCount) ); } /// 이벤트 폴리곤 스캐너 struct EventPolygon : X2D::Polygon< int > { int nPriority; std::string strScript; }; /// 이벤트 폴리곤 스캐너 struct EventAreaPolygon : X2D::Polygon< int > { public: int nID; int nPolygonNum; ///< 위의 ID의 영역을 구성하는 폴리곤중 몇번째에 위치하는 폴리곤에 걸렸는가? }; enum PLAYER_LOCAL_POSITION { _IN_ = 0, ///< 지역에 들어섬 _OUT_, ///< 지역에서 나감 _LOCAL_, ///< 지역 안 _WORLD_, ///< 지역 밖 }; /// 지역 찾기 PLAYER_LOCAL_POSITION FindLocationInfoForMap( K3DVector* vPosition ); /// 지역 정보 생성 void CreateLocationInfoForMap( const char* szLocationFileName, int nMapX, int nMapY ); void SetEventPolygon( struct EventPolygon* EvPolygon ); void SetEventAreaPolygon( struct EventAreaPolygon* EvPolygon ); void ResetLocationInfo(); void CreateEventAreaInfoForMap( const char* szLocationFileName, int nMapX, int nMapY ); /// 길 찾기 typedef std::vector< X2D::Point > PATH; bool CollisionToLine( const K3DVector& vStart, const K3DVector& vEnd ); void FindDetour( const K3DVector& vStart, const K3DVector& vEnd, PATH& vPath, bool bRestraint ); const PATH& GetDetour(); void CreateAttributePolygonInfoForMap( const K3DVector& vStart, const K3DVector& vEnd ); void AddAttributePolygon( struct X2D::Polygon* pPolygon ); //void AddGrassContainer( CGrassColonyInfoContainer* pContainer ); //void AddAttributePolygon( struct X2D::Polygon& rPolygon); //void ClearAttributePolygons(); void AddWireAttributePolygonLine(const K3DVertex& v1, const K3DVertex& v2); //KWireUtilPrimitive* GetWireAttributePolygon(); void SetDrawAttributePolygon(bool bDraw); std::string GetLocalScript(){ return m_strLocalScript; } int GetWorldID() { return m_nWorldID; } /// TODO : 저사양 물 관련 CTerrainLowQualityWaterInfo* FindLowQualityWaterInfo(int nMapX, int nMapY); void DeleteWaterSegmentCount(int nMapX, int nMapY ); std::vector< CTerrainLowQualityWaterInfo * >& GetLowQualityWaterInfo() { return m_LQWaterInfo; } int GetDefaultWorldID( K3DVector* vPosition ); void SetCameraState( const K3DVector& cam, const K3DVector& target ) { m_nTarX = (int)(target.x / m_fSegmentLength); m_nTarY = (int)(target.y / m_fSegmentLength); m_viewX = target.x - cam.x, m_viewY = target.y - cam.y; } typedef stdext::hash_map TERRAINSEGMENTMAP; const TERRAINSEGMENTMAP& GetSegmentMap() const {return m_SegmentMap;} void DeleteAttrQuadTree(); void CreateGrassColonyInfoForMap( int nMapX, int nMapY ); void AddTerrainGrassColonyInfoForMap( CTerrainGrassColonyInfoForMap* pTerrainGrassColonyInfoForMap ); CTerrainGrassColonyInfoForMap* GetTerrainGrassColonyInfoForMap( int nMapX, int nMapY ); GrassColonyInfo* GetGrassColonyInfoForMap( int nMapX, int nMapY, int nPolygonID ); void DeleteSpeedGrassSegmentCount( CTerrainSegment* pTerrainSegment ); void RefreshLightMapEnable(bool bLightmapEnable); void GetPlayerPositionLocalID( K3DVector& vPosition, std::string & strScript ); void GetPlayerPositionEventAreaID( K3DVector& vPosition, std::vector& vec, std::vector& polyNum ); static bool IsEnableTerrainLOD() { return s_bEnableTerrainLOD; } static void SetEnableTerrainLOD( bool bEnable ) { s_bEnableTerrainLOD = bEnable; } void GetMapXY( const K3DVector& vPosition, int& nMapX, int& nMapY ); void addCustomBlock(unsigned int handle, int* line); void delCustomBlock(unsigned int handle); /// sx, sy에서 ex, ey로 이동 할 때, 충돌여부와 충돌후 이동 각도를 구한다. bool collisionAttrQuad(float sx, float sy, float& ex, float& ey, float& collisionTheta, bool checkStartZeroLen = true); bool collisionCustomBlock(float sx, float sy, float& ex, float& ey); bool collisionCustomBlock(float sx, float sy, float& ex, float& ey, std::vector const& blockList); /// 충돌 했을 때의 충돌 위치와 거리를 구한다. bool getIntersectInfo(X2D::Point const& ptStart, X2D::Point const& ptEnd, X2D::Point& ptThePoint, int& intersectDistance, X2D::Line* intersectLine = NULL); /// 끝점 기준으로 충돌 했을 때의 충돌 위치와 거리를 구한다. bool getIntersectInfoNearbyEndPoint(X2D::Point const& ptStart, X2D::Point const& ptEnd, X2D::Point& ptThePoint, int& intersectDistance, X2D::Line* intersectLine = NULL); /// sp, ep와 i_sp, i_ep가 intersectP에서 교차 했을 때, 두 선의 사이각을 구한다. float getDegreeBetweenLine(X2D::Point const& sp, X2D::Point const& ep, X2D::Point const& i_sp, X2D::Point const& i_ep, X2D::Point const& intersectP); /// origin을 원점으로 해서 _p1과 _p2의 사이각을 구한다. float calcTheta(X2D::Point const& _p1, X2D::Point const& _p2, X2D::Point const& origin); #ifdef _EDIT_MAP_FILE_ void ReloadVisibleSegment(); void DeleteFileForReload(std::string* pFileName); #endif private: K3DRenderDevice* m_pDevice; CTerrainSeamlessWorldInfo* m_pSeamlessWorldInfo; CTerrainTextureInfo* m_pTextureInfo; CTerrainPropInfo* m_pPropInfo; CTerrainLocationInfoForMap* m_pCurLocationInfo; CTerrainEventAreaInfoForMap* m_pCurEventAreaInfo; K3DVector m_vOldTargetPosition; std::string m_strLocalScript; int m_nLocalPriority; int m_nWorldID; PLAYER_LOCAL_POSITION m_nLocalState; DWORD m_dwCurrentTime; typedef std::vector< CTerrainLowQualityWaterInfo * > TERRAIN_LQ_WATER_INFO; TERRAIN_LQ_WATER_INFO m_LQWaterInfo; ///< 최대 4개일듯 // TERRAIN_FILTERING m_FilteringType; // 지형 표현 필터링 방식 TERRAIN_RENDERMODE m_RenderMode; ///< 1 pass or 4 pass TERRAINMAP_PROPERTIES::COLORING m_CurrentMapColoring; ///< 현재 맵 컬러링 TERRAINMAP_PROPERTIES::COLORING m_PreviousColoring; TERRAINMAP_PROPERTIES::COLORING m_NextColoring; ///< 컬러링 변환시의 이전/다음 컬러링값 DWORD m_dwColoringChangingRemainTime; ///< 컬러링 변환 남은 시간 DWORD m_dwPreviousSetColoringTime; ///< 이전 컬러링 설정 시각 float m_fTileLength; ///< 타일의 한쪽면 길이 float m_fAttrCellLength; ///< 속성 셀의 한쪽면 길이 float m_fSegmentLength; ///< 세그먼트의 한쪽면 길이 int m_nTileCountPerSegment; ///< 세그먼트 한쪽면의 타일 갯수 int m_nAttrCellCountPerSegment; ///< 세그먼트 한쪽면의 속성 셀 갯수 int m_nSegmentXCount, m_nSegmentYCount; ///< 전체 seamless 중 가로/세로 한쪽면의 세그먼트 갯수 bool m_bEnableLightmap; private: TERRAINSEGMENTMAP m_SegmentMap; ///< 세그먼트 map // divide polygon 사용중단 /* #ifdef _DEV typedef X2D::QuadTree_divide_polygon< int, X2D::Polygon*, 100 > attribute_polygon_quadtree_t; #else */ typedef X2D::QuadTree< int, X2D::Polygon< int >*, false, 20, 12 > attribute_polygon_quadtree_t; //#endif typedef X2D::QuadTree< int, X2D::IndexedPoint< int >*, false, 20, 12 > attribute_point_quadtree_t; X2D::QuadTree< int, EventPolygon, true > m_EventPolygonScanner; attribute_polygon_quadtree_t m_AttrPolygonsQuadTree; std::vector< X2D::Polygon* > m_vecAttrPolygons; attribute_point_quadtree_t m_AttrPointQuadTree; std::vector< X2D::IndexedPoint< int >* > m_AttrIndexedPoints; std::vector m_vAttributeInfos; X2D::QuadTree< int, EventAreaPolygon, true > m_EventAreaPolygonScanner; KWireUtilPrimitive* m_prWireAttributePolygon; ///< 디버그용 KWireUtilPrimitive* m_prWireDetour; ///< 디버그용 KWireUtilPrimitive* m_prWireQuadTree; ///< 디버그용 PATH m_vDetourPath; bool m_bCreateAttributeWire; bool m_bDrawAttributeWire; DWORD m_dwSegmentExpireTime; ///< 세그먼트 유통기한(?). 일정 시간 이상 화면에 보이지 않은 세그먼트는 제거하기 위함. DWORD m_dwSegmentRemovePeriod; ///< 쓸모없어진 세그먼트를 제거하는 작업의 주기 DWORD m_dwPreviousSegmentRemoveTime; ///< 이전에 세그먼트 제거 작업한 시간 K3DIndexBufferSPtr m_spCommonIndexBuffer[TERRAIN_COMMON_IB_MAX]; ///< 세그먼트 공용 인덱스 버퍼 XBossWorker m_ThreadManager; ///< 스레드 처리 관리자 typedef std::vector< CTerrainSegmentLoadThread* > SEGMENTTHREADLIST; SEGMENTTHREADLIST m_SegmentThreadList; ///< 스레드 처리 객체들의 리스트 typedef std::vector< CTerrainGrassColonyInfoForMap* > GRASS_COLONY_INFO_FOR_MAP; GRASS_COLONY_INFO_FOR_MAP m_GrassColonyInfoForMap; TERRAINMIAPROP_VECTOR m_MiaPropVector; ///< 세그먼트를 못찾은 프랍들을 처리한다 /// 전체 seamless 월드의 세그먼트 인덱스를 구한다. 범위가 넘어갈 경우 (-1)을 리턴한다. int GetSegmentIndex( int nSegmentX, int nSegmentY ) const { return (0 <= nSegmentX && nSegmentX < m_nSegmentXCount && 0 <= nSegmentY && nSegmentY < m_nSegmentYCount) ? ((nSegmentY * m_nSegmentXCount) + nSegmentX) : (-1); } /// 해당 위치의 컬러링을 리턴 ( 위치가 잘못될 경우 디폴트값을 리턴 ) const TERRAINMAP_PROPERTIES::COLORING& GetSegmentColoring( float x, float y ) const; /// 현재의 첫번째 라이트를 세그먼트에 설정 void SetPrimaryLightToSegments(); void DrawSegments( const unsigned long uRenderBitVector, const K3DVertex& rCameraPos, const K3DVector& rTargetPos, const K3DVector* pFrustum, KViewportObject** ppViewportList, int nViewportcount, DWORD dwCurrentTime, int nLimitDistance=0 ); //전략 적인 프랍 로딩. //void LoadPropSegments( const K3DVertex& rCameraTargetPos ); void RemoveUnnecessarySegments(); float GetPropLineCrossedPointTwoSides( const K3DVector& rNear, const K3DVector& rFar, K3DVector& rPickedPoint ) const; TERRAIN_PICK_RESULT GetStoolLineCrossedPoint( const K3DVector& rNear, const K3DVector& rFar, K3DVector& rPickedPoint ) const; float GetTerrainLineCrossedPointTwoSides( const K3DVector& rNear, const K3DVector& rFar, K3DVector& rPickedPoint, const K3DCamera* pCamera ) const; TERRAIN_PICK_RESULT GetTerrainLineCrossedPoint( const K3DVector& rNear, const K3DVector& rFar, K3DVector& rPickedPoint, const K3DCamera* pCamera ) const; bool GetStoolHeight( const TERRAINPROP_VECTOR& rPropVector, float x, float y, float& rGetHeight ) const; void GetPropMinMaxVertices( const CTerrainPropForGame* pProp, K3DVertex& rMin, K3DVertex& rMax ) const; void CreateProps( TERRAINPROP_VECTOR& rPropVector, const K3DPoint& rOrigin, int nMapIndex, const CTerrainSegment* pThisSegment, const NFM_PROPSTRUCT_V15* pPropLoadStructs, int nStructCount ); void TakeNeighborsPropInfo( int nThisSegmentX, int nThisSegmentY, CTerrainSegment* pThisSegment ) const; void SetPropInfoToSegment(TERRAINPROP_VECTOR& rPropVector ); void CreateSpeedGrass( CTerrainInfoForSegment::SPEEDGRASSLOAD_INFO::SpeedGrassGroup & rSpeedGrassGroup, const K3DPoint& rOrigin, int nMapIndex, CTerrainSegment* pThisSegment, int nMapX, int nMapY ); /// 처리 준비가 끝난 스레드 처리 객체를 생성하여 리턴. CTerrainSegmentLoadThread* CreatePreparedThread( int nSegmentIndex ); void AddSegmentThread( int nSegmentIndex ); void ProcessSegmentThread(); void ClearSegmentThread(); void ProcessColoringChange( float x, float y ); // 시야 범위 관련 float m_fTerrainVisibleDistanceMax; float m_fTerrainSquareVisibleDistMax; float m_fTerrainVisibleDistanceRatio; float m_fTerrainSquareVisibleDistRatio; float m_fTerrainVisibleDistance; float m_fTerrainSquareVisibleDist; float m_fPickingSquareDistance; float m_fPropLodDistance; float m_fPropLodDistanceRatio; ///< sonador #2.1.7.1 스피드 트리 퍼포먼스 증가 KRect m_rcVisibleSegment; ///< 시야 범위에 있는 세그먼트 영역 K3DVertex m_vtOriginCorrection; ///< 좌표단위가 커짐에 따라 생기는 오차를 방지하기 위한 원점 보정 위치 K3DTextureSPtr m_spCustomTexture; ///< 지형에 custom으로 입힐 텍스쳐 const K3DMatrix* m_pCustomMatrix; ///< m_pCustomTexture 처리용 텍스쳐 매트릭스 float m_fCustomTextureSquareDist; ///< custom 텍스쳐 적용 거리의 제곱 static unsigned m_unLastRenderedTick; static DWORD m_unLastRenderedTime; std::vector< int > m_LoadSegmentList; ///< 로딩 std::vector< CTerrainSegment* > m_DeleteSegmentList; ///< 삭제 void ProcessLoadSegment(); void AddDrawSegment( int nSegmentIndex ); /// 2011.11.08 - prodongi void SetVisibleArea( float x, float y, int fixVisibleDistance = 0 ); bool IsInsideVisibleArea( int nSegmentX, int nSegmentY ) const { return (m_rcVisibleSegment.top <= nSegmentY && nSegmentY < m_rcVisibleSegment.bottom) && (m_rcVisibleSegment.left <= nSegmentX && nSegmentX < m_rcVisibleSegment.right ); } float GetSegmentCenterPosX( int nSegmentX ) const { return ( ( float(nSegmentX) + 0.5f ) * m_fSegmentLength ); } float GetSegmentCenterPosY( int nSegmentY ) const { return ( ( float(nSegmentY) + 0.5f ) * m_fSegmentLength ); } int m_nTarX, m_nTarY; float m_viewX, m_viewY; float m_maxDistSq; void ProcessMiaProp(); class PVSObjectManager* m_pPVSObjectManager; ///< PVS static bool s_bEnableTerrainLOD; int m_fixVisibleDistance; /// 2011.12.05 디비상에 설정한 고정 가시 거리 - prodongi public: static int MIN_ATTRIBUTE_COLLISION_LENGTH; /// 속성과 충돌되는 최소 거리 std::map*> m_blockList; };