Files
Leviathan/Client/Game/engine/TerrainEngine/TerrainAttributeInfoForMap.h
T
2026-06-01 12:46:52 +02:00

266 lines
8.2 KiB
C++

#pragma once
//#include "EnvironmentInfo.h"
class CTerrainAttributeInfoForMap
{
private:
std::string m_strAttributeFileName;
int m_nMapX;
int m_nMapY;
X2D::Point<int> *m_pPoints;
size_t m_unPointArraySize;
public:
bool CheckMap( int nMapX, int nMapY )
{
if( nMapX != m_nMapX || nMapY != m_nMapY )
return true;
return false;
}
public:
CTerrainAttributeInfoForMap( CTerrainMapEngine *pTerrainMapEngine, const char* szAttributeFileName, int nMapX, int nMapY, bool bCreateWire )
: m_nMapX( nMapX ) , m_nMapY( nMapY ), m_pPoints( NULL ), m_unPointArraySize( 0 )
{
// 파일 열기
KStream* pStream = KFileManager::Instance().CreateStreamFromResource( szAttributeFileName, true );
if( NULL == pStream )
{
// assert( false && "속성 정보 파일이 없음." );
return;
}
const CTerrainSeamlessWorldInfo* pSeamlessWorldInfo = pTerrainMapEngine->GetSeamlessWorldInfo();
if(pSeamlessWorldInfo == NULL)
{
delete pStream;
// assert( false && "pSeamlessWorldInfo == NULL 이네" );
return;
}
float fMapLen = (float)( pSeamlessWorldInfo->GetTileCountPerSegment() * pSeamlessWorldInfo->GetSegmentCountPerMap() ) * (float)pSeamlessWorldInfo->GetTileLength();
float fAttrLength = pSeamlessWorldInfo->GetTileLength() / (float)c_nAttrCountPerTile;
m_strAttributeFileName = szAttributeFileName;
m_nMapX = nMapX;
m_nMapY = nMapY;
int nPolygonCount = 0;
pStream->Read( &nPolygonCount, sizeof( nPolygonCount ) );
K3DVertex v1, v2;
//FILE *fp = fopen( "pl.txt", "w" );
//fprintf( fp, "TOTAL:%d\n\n", nPolygonCount );
int cnt = 0;
for( int i = 0; i < nPolygonCount ; i++ )
{
int nPointCount = 0;
pStream->Read( &nPointCount, sizeof( nPointCount ) );
if( nPointCount < 3 ) continue;
//X2D::Point<int> *m_pPoints = new X2D::Point<int>[nPointCount];
//static X2D::Point<int> *m_pPoints = NULL;
//static size_t m_unPointArraySize = 0;
if(m_pPoints && m_unPointArraySize > (size_t)nPointCount)
{
// do nothing
}
else
{
if(m_pPoints) delete[] m_pPoints;
m_pPoints = new X2D::Point<int>[nPointCount];
m_unPointArraySize = nPointCount;
}
pStream->Read( m_pPoints, sizeof( X2D::Point<int> ) * nPointCount );
//fprintf( fp, "COUNT:%d\n", nPointCount );
WORD wTile=0;
std::vector<X2D::Point<int>> vecPoint;
for( int j = 0; j < nPointCount; ++j )
{
vecPoint.push_back(m_pPoints[j]);
m_pPoints[j].x *= fAttrLength; //형 변환 하지 마셈!!!
m_pPoints[j].y *= fAttrLength; //형 변환 하지 마셈!!!
// * 맨날 컴파일할때마다 warning보는 다른 사람: 아악~~~ 형 변환 하고 싶어~~~~~ 이런 ambiguous한 코드를 그냥 두다니~~~~~~~~
m_pPoints[j].x += (int)( (float)nMapX * fMapLen );
m_pPoints[j].y += (int)( (float)nMapY * fMapLen );
//fprintf( fp, "%d,%d\n", m_pPoints[j].x, m_pPoints[j].y );
}
std::vector<X2D::Polygon<int>*> vecMaskPolygon;
/////////////////////////////// 1단위(변환전)짜리 작은 틈으로 캐릭터가 기어나가는걸 막는 마스킹 폴리곤 생성 by 정동섭
if (vecPoint.size() > 30) // 문제가 되는 폴리곤은 맵전체를 감싸는 폴리곤이 대부분이므로 너무 작은 폴리곤은 패스
{
for (int j=0; j<(int)vecPoint.size(); j++)
{
for (int k=j+7; k<(int)vecPoint.size(); k++)
{
if ( j + (int)vecPoint.size() - 7 > k ) // 바로 근처 있는 점끼리는 체크하지 않는다. 최소한 두 점 사이에 6개의 다른 점이 있어야 함. (맵을 한바퀴 돌아와야 하므로)
{
int xDist, yDist, _xDist, _yDist;
_xDist = vecPoint[j].x - vecPoint[k].x;
_yDist = vecPoint[j].y - vecPoint[k].y;
xDist = abs(_xDist);
yDist = abs(_yDist);
X2D::Point<int> addPt = vecPoint[k]; // 가까운 두 점과 삼각형을 이룰 다른 점
X2D::Point<int> addPt2 = vecPoint[k]; // 가까운 두 점과 삼각형을 이룰 다른 점
const int gapSize = 2;
bool isClose = false;
if ((xDist == 0) && (yDist <= gapSize)) // 두 점은 반드시 가로나 세로, 혹은 대각선으로 붙어있어야만 한다.
{
isClose = true;
addPt.x++;
addPt2.x--;
}
else if ((xDist <= gapSize) && (yDist == 0))
{
isClose = true;
addPt.y++;
addPt2.y--;
}
else if ((xDist <= gapSize) && (yDist <= gapSize))
{
isClose = true;
addPt.x = max(vecPoint[j].x, vecPoint[k].x);
addPt.y = max(vecPoint[j].y, vecPoint[k].y);
addPt2.x = min(vecPoint[j].x, vecPoint[k].x);
addPt2.y = min(vecPoint[j].y, vecPoint[k].y);
if ((addPt == vecPoint[j]) || addPt == vecPoint[k]) addPt.y = min(vecPoint[j].y, vecPoint[k].y);
if ((addPt2 == vecPoint[j]) || addPt2 == vecPoint[k]) addPt2.y = max(vecPoint[j].y, vecPoint[k].y);
}
if (isClose)
{
X2D::Point<int> tempBuf[4]; // 삼각형을 만든다
tempBuf[0] = vecPoint[j];
tempBuf[1] = addPt;
tempBuf[2] = vecPoint[k];
tempBuf[3] = addPt2;
tempBuf[0].x += _xDist; // 정확히 구멍에 꼭맞는 삼각형을 만들면 뚫릴때가 있어서
tempBuf[0].y += _yDist; // 구멍보다 큰 마개를 만든다.
tempBuf[2].x -= _xDist;
tempBuf[2].y -= _yDist;
for (int cnt=0; cnt<4; cnt++) // 맵좌표로 변환
{
tempBuf[cnt].x *= fAttrLength; //형 변환 하지 마셈!!!
tempBuf[cnt].y *= fAttrLength; //형 변환 하지 마셈!!!
// * 맨날 컴파일할때마다 warning보는 다른 사람: 아악~~~ 형 변환 하고 싶어~~~~~ 이런 ambiguous한 코드를 그냥 두다니~~~~~~~~
tempBuf[cnt].x += (int)( (float)nMapX * fMapLen );
tempBuf[cnt].y += (int)( (float)nMapY * fMapLen );
}
X2D::Polygon<int>* poly = new X2D::Polygon<int>;
bool bValid = poly->Set(tempBuf, tempBuf + 4);
if (bValid)
{
vecMaskPolygon.push_back(poly); // 저장해둔다
}
else
{
assert( bValid && "추가 마스킹 폴리곤 생성과정에서 에러" );
delete poly;
}
}
}
}
}
}
////////////////////////// 여기까지
X2D::Polygon<int>* pPolygon = new X2D::Polygon<int>;
bool bValidPolygon = pPolygon->Set(m_pPoints, m_pPoints + nPointCount);
assert( bValidPolygon && "일부 속성 겹쳐서 날아갔음!!!" );
if(bCreateWire && bValidPolygon)
{
for( int j = 0; j < nPointCount; ++j )
{
if(j >= 1)
{
v1.x = (float) m_pPoints[j - 1].x;
v1.y = (float) m_pPoints[j - 1].y;
pTerrainMapEngine->GetTerrainHeight(v1.x, v1.y, v1.z,wTile );
v1.z += 20.f;
v2.x = (float) m_pPoints[j].x;
v2.y = (float) m_pPoints[j].y;
pTerrainMapEngine->GetTerrainHeight(v2.x, v2.y, v2.z,wTile );
v2.z += 20.0f;
pTerrainMapEngine->AddWireAttributePolygonLine(v1, v2);
}
}
// 마지막 라인은 수동으로
v1.x = (float) m_pPoints[nPointCount - 1].x;
v1.y = (float) m_pPoints[nPointCount - 1].y;
pTerrainMapEngine->GetTerrainHeight(v1.x, v1.y, v1.z,wTile);
v1.z += 20.0f;
v2.x = (float) m_pPoints[0].x;
v2.y = (float) m_pPoints[0].y;
pTerrainMapEngine->GetTerrainHeight(v2.x, v2.y, v2.z,wTile);
v2.z += 20.0f;
pTerrainMapEngine->AddWireAttributePolygonLine(v1, v2);
}
size_t s_unLimit = 500;
if(m_unPointArraySize > s_unLimit)
{
if(m_pPoints) delete[] m_pPoints;
m_pPoints = NULL;
m_unPointArraySize = 0;
}
if( bValidPolygon ) pTerrainMapEngine->AddAttributePolygon( pPolygon );
else
{
assert( false && "유효하지 않는 지형 속성이 발견됨 맵팀에 문의해주세요" );
_oprint( "DELETE:%d\n", nPointCount );
delete pPolygon;
}
for (size_t pCnt=0; pCnt<vecMaskPolygon.size(); pCnt++)
{
pTerrainMapEngine->AddAttributePolygon( vecMaskPolygon[pCnt] ); // 위에서 찾은 마스크 폴리곤을 추가.
}
//fprintf( fp, "\n" );
}
//fclose( fp );
delete pStream;
}
~CTerrainAttributeInfoForMap()
{
if(m_pPoints) delete[] m_pPoints;
m_pPoints = NULL;
m_unPointArraySize = 0;
}
};