Files
2026-06-01 12:46:52 +02:00

459 lines
20 KiB
C++

#pragma once
#ifdef _DEV
#include <geometry/X2DQuadTree_divide_polygon.h>
#else
#include <geometry/X2DQuadTree.h>
#endif
#include <geometry/X2DPolygon.h>
#include <geometry/X2DLeakyPolygon.h>
#include "TerrainDefine.h"
#include "TerrainSegment.h"
#include "TerrainInfoForSegment.h"
#include "TerrainSegmentLoadThread.h"
#include <hash_map>
#include <map>
#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<int> > 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<int>* pPolygon );
//void AddGrassContainer( CGrassColonyInfoContainer* pContainer );
//void AddAttributePolygon( struct X2D::Polygon<int>& 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<int, CTerrainSegment*> 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<int>& vec, std::vector<int>& 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<K3DVector2> const& blockList);
/// 충돌 했을 때의 충돌 위치와 거리를 구한다.
bool getIntersectInfo(X2D::Point<int> const& ptStart, X2D::Point<int> const& ptEnd, X2D::Point<int>& ptThePoint, int& intersectDistance, X2D::Line<int>* intersectLine = NULL);
/// 끝점 기준으로 충돌 했을 때의 충돌 위치와 거리를 구한다.
bool getIntersectInfoNearbyEndPoint(X2D::Point<int> const& ptStart, X2D::Point<int> const& ptEnd, X2D::Point<int>& ptThePoint, int& intersectDistance, X2D::Line<int>* intersectLine = NULL);
/// sp, ep와 i_sp, i_ep가 intersectP에서 교차 했을 때, 두 선의 사이각을 구한다.
float getDegreeBetweenLine(X2D::Point<int> const& sp, X2D::Point<int> const& ep, X2D::Point<int> const& i_sp, X2D::Point<int> const& i_ep, X2D::Point<int> const& intersectP);
/// origin을 원점으로 해서 _p1과 _p2의 사이각을 구한다.
float calcTheta(X2D::Point<int> const& _p1, X2D::Point<int> const& _p2, X2D::Point<int> 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<int>*, 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<int>* > m_vecAttrPolygons;
attribute_point_quadtree_t m_AttrPointQuadTree;
std::vector< X2D::IndexedPoint< int >* > m_AttrIndexedPoints;
std::vector<class CTerrainAttributeInfoForMap*> 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<unsigned int, X2D::Point<int>*> m_blockList;
};