ilk commit
This commit is contained in:
@@ -0,0 +1,357 @@
|
||||
#pragma once
|
||||
|
||||
#include <math.h>
|
||||
#include <cfloat>
|
||||
|
||||
/* Here follow the extremely few remaining D3D8 components we require */
|
||||
|
||||
// NOTE: We're using this over M_PI because of the precision
|
||||
#define D3DX_PI ((float) 3.141592654f)
|
||||
#define D3DXToRadian( degree ) ((degree) * (D3DX_PI / 180.0f))
|
||||
|
||||
/* D3D8 structs */
|
||||
typedef struct _D3DVECTOR {
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
} D3DVECTOR;
|
||||
|
||||
typedef struct _D3DMATRIX {
|
||||
union {
|
||||
struct {
|
||||
float _11, _12, _13, _14;
|
||||
float _21, _22, _23, _24;
|
||||
float _31, _32, _33, _34;
|
||||
float _41, _42, _43, _44;
|
||||
|
||||
};
|
||||
float m[4][4];
|
||||
};
|
||||
} D3DMATRIX;
|
||||
|
||||
struct __Matrix44;
|
||||
struct __Vector3 : public D3DVECTOR // 3D Vertex
|
||||
{
|
||||
public:
|
||||
INLINE __Vector3() {}
|
||||
INLINE __Vector3(float fx, float fy, float fz) { Set(fx, fy, fz); }
|
||||
|
||||
INLINE void Zero() { Set(0.0f, 0.0f, 0.0f); }
|
||||
INLINE void Set(float fx, float fy, float fz) { x = fx; y = fy; z = fz; }
|
||||
|
||||
void Normalize();
|
||||
float Magnitude() const;
|
||||
float Dot(const D3DVECTOR& vec) const;
|
||||
void Cross(const D3DVECTOR& v1, const D3DVECTOR& v2);
|
||||
void Absolute();
|
||||
|
||||
const __Vector3& operator = (const __Vector3& vec);
|
||||
|
||||
const __Vector3 operator * (const D3DMATRIX& mtx) const;
|
||||
void operator *= (float fDelta);
|
||||
void operator *= (const D3DMATRIX& mtx);
|
||||
__Vector3 operator + (const D3DVECTOR& vec) const;
|
||||
__Vector3 operator - (const D3DVECTOR& vec) const;
|
||||
__Vector3 operator * (const D3DVECTOR& vec) const;
|
||||
__Vector3 operator / (const D3DVECTOR& vec) const;
|
||||
|
||||
void operator += (const D3DVECTOR& vec);
|
||||
void operator -= (const D3DVECTOR& vec);
|
||||
void operator *= (const D3DVECTOR& vec);
|
||||
void operator /= (const D3DVECTOR& vec);
|
||||
|
||||
__Vector3 operator + (float fDelta) const;
|
||||
__Vector3 operator - (float fDelta) const;
|
||||
__Vector3 operator * (float fDelta) const;
|
||||
__Vector3 operator / (float fDelta) const;
|
||||
};
|
||||
|
||||
struct __Matrix44 : public D3DMATRIX // 4x4 Matrix
|
||||
{
|
||||
public:
|
||||
__Matrix44() {}
|
||||
void Zero();
|
||||
void Identity();
|
||||
void RotationY(float fDelta);
|
||||
};
|
||||
|
||||
INLINE void __Vector3::Normalize()
|
||||
{
|
||||
float fn = sqrtf(x*x + y*y + z*z);
|
||||
if(fn == 0) return;
|
||||
x /= fn; y /= fn; z /= fn;
|
||||
}
|
||||
|
||||
INLINE float __Vector3::Magnitude() const
|
||||
{
|
||||
return sqrtf(x*x + y*y + z*z);
|
||||
}
|
||||
|
||||
INLINE float __Vector3::Dot(const D3DVECTOR& vec) const
|
||||
{
|
||||
return x*vec.x + y*vec.y + z*vec.z;
|
||||
}
|
||||
|
||||
INLINE void __Vector3::Cross(const D3DVECTOR& v1, const D3DVECTOR& v2)
|
||||
{
|
||||
x = v1.y * v2.z - v1.z * v2.y;
|
||||
y = v1.z * v2.x - v1.x * v2.z;
|
||||
z = v1.x * v2.y - v1.y * v2.x;
|
||||
}
|
||||
|
||||
INLINE void __Vector3::Absolute()
|
||||
{
|
||||
if(x < 0) x *= -1.0f;
|
||||
if(y < 0) y *= -1.0f;
|
||||
if(z < 0) z *= -1.0f;
|
||||
}
|
||||
|
||||
INLINE const __Vector3& __Vector3::operator = (const __Vector3& vec)
|
||||
{
|
||||
x = vec.x; y = vec.y; z = vec.z;
|
||||
return *this;
|
||||
}
|
||||
|
||||
INLINE const __Vector3 __Vector3::operator * (const D3DMATRIX& mtx) const
|
||||
{
|
||||
static __Vector3 vTmp;
|
||||
|
||||
vTmp.x = x*mtx._11 + y*mtx._21 + z*mtx._31 + mtx._41;
|
||||
vTmp.y = x*mtx._12 + y*mtx._22 + z*mtx._32 + mtx._42;
|
||||
vTmp.z = x*mtx._13 + y*mtx._23 + z*mtx._33 + mtx._43;
|
||||
|
||||
return vTmp;
|
||||
}
|
||||
|
||||
INLINE void __Vector3::operator *= (float fDelta)
|
||||
{
|
||||
x *= fDelta;
|
||||
y *= fDelta;
|
||||
z *= fDelta;
|
||||
}
|
||||
|
||||
INLINE void __Vector3::operator *= (const D3DMATRIX& mtx)
|
||||
{
|
||||
static __Vector3 vTmp;
|
||||
|
||||
vTmp.Set(x,y,z);
|
||||
x = vTmp.x*mtx._11 + vTmp.y*mtx._21 + vTmp.z*mtx._31 + mtx._41;
|
||||
y = vTmp.x*mtx._12 + vTmp.y*mtx._22 + vTmp.z*mtx._32 + mtx._42;
|
||||
z = vTmp.x*mtx._13 + vTmp.y*mtx._23 + vTmp.z*mtx._33 + mtx._43;
|
||||
}
|
||||
|
||||
INLINE __Vector3 __Vector3::operator + (const D3DVECTOR& vec) const
|
||||
{
|
||||
static __Vector3 vTmp;
|
||||
|
||||
vTmp.x = x + vec.x;
|
||||
vTmp.y = y + vec.y;
|
||||
vTmp.z = z + vec.z;
|
||||
return vTmp;
|
||||
}
|
||||
|
||||
INLINE __Vector3 __Vector3::operator - (const D3DVECTOR& vec) const
|
||||
{
|
||||
static __Vector3 vTmp;
|
||||
|
||||
vTmp.x = x - vec.x;
|
||||
vTmp.y = y - vec.y;
|
||||
vTmp.z = z - vec.z;
|
||||
return vTmp;
|
||||
}
|
||||
|
||||
INLINE __Vector3 __Vector3::operator * (const D3DVECTOR& vec) const
|
||||
{
|
||||
static __Vector3 vTmp;
|
||||
|
||||
vTmp.x = x * vec.x;
|
||||
vTmp.y = y * vec.y;
|
||||
vTmp.z = z * vec.z;
|
||||
return vTmp;
|
||||
}
|
||||
|
||||
INLINE __Vector3 __Vector3::operator / (const D3DVECTOR& vec) const
|
||||
{
|
||||
static __Vector3 vTmp;
|
||||
|
||||
vTmp.x = x / vec.x;
|
||||
vTmp.y = y / vec.y;
|
||||
vTmp.z = z / vec.z;
|
||||
return vTmp;
|
||||
}
|
||||
|
||||
INLINE void __Vector3::operator += (const D3DVECTOR& vec)
|
||||
{
|
||||
x += vec.x;
|
||||
y += vec.y;
|
||||
z += vec.z;
|
||||
}
|
||||
|
||||
INLINE void __Vector3::operator -= (const D3DVECTOR& vec)
|
||||
{
|
||||
x -= vec.x;
|
||||
y -= vec.y;
|
||||
z -= vec.z;
|
||||
}
|
||||
|
||||
INLINE void __Vector3::operator *= (const D3DVECTOR& vec)
|
||||
{
|
||||
x *= vec.x;
|
||||
y *= vec.y;
|
||||
z *= vec.z;
|
||||
}
|
||||
|
||||
INLINE void __Vector3::operator /= (const D3DVECTOR& vec)
|
||||
{
|
||||
x /= vec.x;
|
||||
y /= vec.y;
|
||||
z /= vec.z;
|
||||
}
|
||||
|
||||
INLINE __Vector3 __Vector3::operator + (float fDelta) const
|
||||
{
|
||||
static __Vector3 vTmp;
|
||||
|
||||
vTmp.x = x + fDelta;
|
||||
vTmp.y = y + fDelta;
|
||||
vTmp.z = z + fDelta;
|
||||
return vTmp;
|
||||
}
|
||||
|
||||
INLINE __Vector3 __Vector3::operator - (float fDelta) const
|
||||
{
|
||||
static __Vector3 vTmp;
|
||||
|
||||
vTmp.x = x - fDelta;
|
||||
vTmp.y = y - fDelta;
|
||||
vTmp.z = z - fDelta;
|
||||
return vTmp;
|
||||
}
|
||||
|
||||
INLINE __Vector3 __Vector3::operator * (float fDelta) const
|
||||
{
|
||||
static __Vector3 vTmp;
|
||||
|
||||
vTmp.x = x * fDelta;
|
||||
vTmp.y = y * fDelta;
|
||||
vTmp.z = z * fDelta;
|
||||
return vTmp;
|
||||
}
|
||||
|
||||
INLINE __Vector3 __Vector3::operator / (float fDelta) const
|
||||
{
|
||||
static __Vector3 vTmp;
|
||||
|
||||
vTmp.x = x / fDelta;
|
||||
vTmp.y = y / fDelta;
|
||||
vTmp.z = z / fDelta;
|
||||
return vTmp;
|
||||
}
|
||||
|
||||
INLINE void __Matrix44::Identity()
|
||||
{
|
||||
_12 = _13 = _14 = _21 = _23 = _24 = _31 = _32 = _34 = _41 = _42 = _43 = 0;
|
||||
_11 = _22 = _33 = _44 = 1.0f;
|
||||
}
|
||||
|
||||
INLINE void __Matrix44::RotationY(float fDelta)
|
||||
{
|
||||
this->Identity();
|
||||
_11 = cosf(fDelta); _13 = -sinf(fDelta); _31 = -_13; _33 = _11;
|
||||
}
|
||||
|
||||
INLINE bool _IntersectTriangle(const __Vector3& vOrig, const __Vector3& vDir,
|
||||
const __Vector3& v0, const __Vector3& v1, const __Vector3& v2,
|
||||
float& fT, float& fU, float& fV, __Vector3* pVCol = nullptr)
|
||||
{
|
||||
// Find vectors for two edges sharing vert0
|
||||
static __Vector3 vEdge1, vEdge2;
|
||||
|
||||
vEdge1 = v1 - v0;
|
||||
vEdge2 = v2 - v0;
|
||||
|
||||
// Begin calculating determinant - also used to calculate U parameter
|
||||
__Vector3 pVec; float fDet;
|
||||
|
||||
pVec.Cross(vEdge1, vEdge2);
|
||||
fDet = pVec.Dot(vDir);
|
||||
if (fDet > -0.0001f )
|
||||
return false;
|
||||
|
||||
pVec.Cross(vDir, vEdge2);
|
||||
|
||||
// If determinant is near zero, ray lies in plane of triangle
|
||||
fDet = vEdge1.Dot(pVec);
|
||||
if( fDet < 0.0001f )
|
||||
return false;
|
||||
|
||||
// Calculate distance from vert0 to ray origin
|
||||
__Vector3 tVec = vOrig - v0;
|
||||
|
||||
// Calculate U parameter and test bounds
|
||||
fU = tVec.Dot(pVec);
|
||||
if( fU < 0.0f || fU > fDet )
|
||||
return false;
|
||||
|
||||
// Prepare to test V parameter
|
||||
__Vector3 qVec;
|
||||
qVec.Cross(tVec, vEdge1);
|
||||
|
||||
// Calculate V parameter and test bounds
|
||||
fV = vDir.Dot(qVec);
|
||||
if( fV < 0.0f || fU + fV > fDet )
|
||||
return false;
|
||||
|
||||
// Calculate t, scale parameters, ray intersects triangle
|
||||
fT = vEdge2.Dot(qVec);
|
||||
float fInvDet = 1.0f / fDet;
|
||||
fT *= fInvDet;
|
||||
fU *= fInvDet;
|
||||
fV *= fInvDet;
|
||||
|
||||
if(pVCol) (*pVCol) = vOrig + (vDir * fT);
|
||||
return (fT >= 0.0f);
|
||||
}
|
||||
|
||||
INLINE bool _IntersectTriangle(const __Vector3& vOrig, const __Vector3& vDir, const __Vector3& v0, const __Vector3& v1, const __Vector3& v2)
|
||||
{
|
||||
// Find vectors for two edges sharing vert0
|
||||
// Begin calculating determinant - also used to calculate U parameter
|
||||
static float fDet, fT, fU, fV;
|
||||
static __Vector3 vEdge1, vEdge2, tVec, pVec, qVec;
|
||||
|
||||
vEdge1 = v1 - v0;
|
||||
vEdge2 = v2 - v0;
|
||||
|
||||
pVec.Cross(vEdge1, vEdge2);
|
||||
fDet = pVec.Dot(vDir);
|
||||
if (fDet > -0.0001f )
|
||||
return false;
|
||||
|
||||
pVec.Cross(vDir, vEdge2);
|
||||
|
||||
// If determinant is near zero, ray lies in plane of triangle
|
||||
fDet = vEdge1.Dot(pVec);
|
||||
if( fDet < 0.0001f )
|
||||
return false;
|
||||
|
||||
// Calculate distance from vert0 to ray origin
|
||||
tVec = vOrig - v0;
|
||||
|
||||
// Calculate U parameter and test bounds
|
||||
fU = tVec.Dot(pVec);
|
||||
if( fU < 0.0f || fU > fDet )
|
||||
return false;
|
||||
|
||||
// Prepare to test V parameter
|
||||
qVec.Cross(tVec, vEdge1);
|
||||
|
||||
// Calculate V parameter and test bounds
|
||||
fV = vDir.Dot(qVec);
|
||||
if( fV < 0.0f || fU + fV > fDet )
|
||||
return false;
|
||||
|
||||
// Calculate t, scale parameters, ray intersects triangle
|
||||
fT = vEdge2.Dot(qVec) / fDet;
|
||||
return (fT >= 0.0f);
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
#include "stdafx.h"
|
||||
|
||||
CN3ShapeMgr::CN3ShapeMgr()
|
||||
{
|
||||
m_fMapWidth = 0.0f;
|
||||
m_fMapLength = 0.0f;
|
||||
m_nCollisionFaceCount = 0;
|
||||
m_pvCollisions = nullptr;
|
||||
memset(m_pCells, 0, sizeof(m_pCells));
|
||||
}
|
||||
|
||||
CN3ShapeMgr::~CN3ShapeMgr()
|
||||
{
|
||||
if (m_pvCollisions != nullptr)
|
||||
{
|
||||
delete [] m_pvCollisions;
|
||||
m_pvCollisions = nullptr;
|
||||
}
|
||||
|
||||
for(int z = 0; z < MAX_CELL_MAIN; z++)
|
||||
{
|
||||
for(int x = 0; x < MAX_CELL_MAIN; x++)
|
||||
{
|
||||
delete m_pCells[x][z];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CN3ShapeMgr::unlock()
|
||||
{
|
||||
m_fMapWidth = 0.0f;
|
||||
m_fMapLength = 0.0f;
|
||||
m_nCollisionFaceCount = 0;
|
||||
|
||||
if (m_pvCollisions != nullptr)
|
||||
{
|
||||
delete [] m_pvCollisions;
|
||||
m_pvCollisions = nullptr;
|
||||
}
|
||||
|
||||
for(int z = 0; z < MAX_CELL_MAIN; z++)
|
||||
{
|
||||
for(int x = 0; x < MAX_CELL_MAIN; x++)
|
||||
{
|
||||
delete m_pCells[x][z];
|
||||
m_pCells[x][z] = nullptr;
|
||||
}
|
||||
}
|
||||
memset(m_pCells, 0, sizeof(MAX_CELL_MAIN));
|
||||
}
|
||||
|
||||
bool CN3ShapeMgr::LoadCollisionData(FILE *fp)
|
||||
{
|
||||
if (fread(&m_fMapWidth, 4, 1, fp) != 1
|
||||
|| fread(&m_fMapLength, 4, 1, fp) != 1)
|
||||
{
|
||||
ASSERT(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
Create(m_fMapWidth, m_fMapLength);
|
||||
|
||||
if (fread(&m_nCollisionFaceCount, 4, 1, fp) != 1)
|
||||
{
|
||||
ASSERT(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_pvCollisions != nullptr)
|
||||
{
|
||||
delete [] m_pvCollisions;
|
||||
m_pvCollisions = nullptr;
|
||||
}
|
||||
|
||||
if (m_nCollisionFaceCount > 0)
|
||||
{
|
||||
m_pvCollisions = new __Vector3[m_nCollisionFaceCount * 3];
|
||||
if (fread(m_pvCollisions, sizeof(__Vector3) * m_nCollisionFaceCount * 3, 1, fp) != 1)
|
||||
{
|
||||
ASSERT(0);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Cell data
|
||||
int z = 0;
|
||||
for(float fZ = 0.0f; fZ < m_fMapLength; fZ += CELL_MAIN_SIZE, z++)
|
||||
{
|
||||
int x = 0;
|
||||
for(float fX = 0.0f; fX < m_fMapWidth; fX += CELL_MAIN_SIZE, x++)
|
||||
{
|
||||
if (m_pCells[x][z] != nullptr)
|
||||
{
|
||||
delete m_pCells[x][z];
|
||||
m_pCells[x][z] = nullptr;
|
||||
}
|
||||
|
||||
uint32 bExist;
|
||||
if (fread(&bExist, 4, 1, fp) != 1)
|
||||
{
|
||||
ASSERT(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!bExist)
|
||||
continue;
|
||||
|
||||
m_pCells[x][z] = new __CellMain;
|
||||
m_pCells[x][z]->Load(fp);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CN3ShapeMgr::Create(float fMapWidth, float fMapLength) // 맵의 너비와 높이를 미터 단위로 넣는다..
|
||||
{
|
||||
if( fMapWidth <= 0.0f || fMapWidth > MAX_CELL_MAIN * CELL_MAIN_SIZE ||
|
||||
fMapLength <= 0.0f || fMapLength > MAX_CELL_MAIN * CELL_MAIN_SIZE )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_fMapWidth = fMapWidth;
|
||||
m_fMapLength = fMapLength;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
#pragma once
|
||||
|
||||
#include "My_3DStruct.h"
|
||||
#include <cstdio>
|
||||
|
||||
const int CELL_MAIN_DEVIDE = 4;
|
||||
const int CELL_SUB_SIZE = 4; // 4m
|
||||
const int CELL_MAIN_SIZE = CELL_MAIN_DEVIDE * CELL_SUB_SIZE;
|
||||
const int MAX_CELL_MAIN = 4096 / CELL_MAIN_SIZE;
|
||||
const int MAX_CELL_SUB = MAX_CELL_MAIN * CELL_MAIN_DEVIDE;
|
||||
|
||||
class CN3ShapeMgr
|
||||
{
|
||||
public:
|
||||
struct __CellSub
|
||||
{
|
||||
int nCCPolyCount; // Collision Check Polygon Count
|
||||
uint32* pdwCCVertIndices; // Collision Check Polygon Vertex Indices - wCCPolyCount * 3
|
||||
|
||||
void Load(FILE *fp)
|
||||
{
|
||||
if (fread(&nCCPolyCount, sizeof(int), 1, fp) != 1)
|
||||
{
|
||||
ASSERT(0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (nCCPolyCount != 0)
|
||||
{
|
||||
if (pdwCCVertIndices)
|
||||
delete [] pdwCCVertIndices;
|
||||
|
||||
pdwCCVertIndices = new uint32[nCCPolyCount * 3];
|
||||
if (fread(pdwCCVertIndices, nCCPolyCount * 3 * 4, 1, fp) != 1)
|
||||
{
|
||||
ASSERT(0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__CellSub() { memset(this, 0, sizeof(__CellSub)); }
|
||||
~__CellSub() { delete [] pdwCCVertIndices; }
|
||||
};
|
||||
|
||||
struct __CellMain
|
||||
{
|
||||
int nShapeCount; // Shape Count;
|
||||
WORD* pwShapeIndices; // Shape Indices
|
||||
__CellSub SubCells[CELL_MAIN_DEVIDE][CELL_MAIN_DEVIDE];
|
||||
|
||||
void Load(FILE *fp)
|
||||
{
|
||||
if (fread(&nShapeCount, sizeof(int), 1, fp) != 1)
|
||||
{
|
||||
ASSERT(0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (nShapeCount != 0)
|
||||
{
|
||||
if (pwShapeIndices)
|
||||
delete [] pwShapeIndices;
|
||||
|
||||
pwShapeIndices = new WORD[nShapeCount];
|
||||
if (fread(pwShapeIndices, nShapeCount * 2, 1, fp) != 1)
|
||||
{
|
||||
ASSERT(0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (int z = 0; z < CELL_MAIN_DEVIDE; z++)
|
||||
{
|
||||
for (int x = 0; x < CELL_MAIN_DEVIDE; x++)
|
||||
SubCells[x][z].Load(fp);
|
||||
}
|
||||
}
|
||||
|
||||
__CellMain() { nShapeCount = 0; pwShapeIndices = nullptr; }
|
||||
~__CellMain() { delete [] pwShapeIndices; }
|
||||
};
|
||||
|
||||
__Vector3* m_pvCollisions;
|
||||
|
||||
protected:
|
||||
float m_fMapWidth;
|
||||
float m_fMapLength;
|
||||
int m_nCollisionFaceCount;
|
||||
__CellMain* m_pCells[MAX_CELL_MAIN][MAX_CELL_MAIN];
|
||||
|
||||
public:
|
||||
void SubCell(const __Vector3& vPos, __CellSub** ppSubCell);
|
||||
__CellSub* SubCell(float fX, float fZ)
|
||||
{
|
||||
int x = (int)(fX / CELL_MAIN_SIZE);
|
||||
int z = (int)(fZ / CELL_MAIN_SIZE);
|
||||
|
||||
// _ASSERT(x >= 0 && x < MAX_CELL_MAIN && z >= 0 && z < MAX_CELL_MAIN);
|
||||
if(nullptr == m_pCells[x][z]) return nullptr;
|
||||
|
||||
int xx = (((int)fX)%CELL_MAIN_SIZE)/CELL_SUB_SIZE;
|
||||
int zz = (((int)fZ)%CELL_MAIN_SIZE)/CELL_SUB_SIZE;
|
||||
|
||||
return &(m_pCells[x][z]->SubCells[xx][zz]);
|
||||
}
|
||||
float Width() { return m_fMapWidth; }
|
||||
float Height() { return m_fMapWidth; }
|
||||
|
||||
bool Create(float fMapWidth, float fMapLength);
|
||||
bool LoadCollisionData(FILE *fp);
|
||||
|
||||
void unlock();
|
||||
CN3ShapeMgr();
|
||||
virtual ~CN3ShapeMgr();
|
||||
};
|
||||
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "../shared/stdafx.h"
|
||||
|
||||
#include <limits>
|
||||
#include "N3ShapeMgr.h"
|
||||
Reference in New Issue
Block a user