CTerrain refactoring & fixes
- refactored CTerrain code - fixed some minor bugsdev-ui
parent
480b57a086
commit
c2c1294ec9
|
@ -35,7 +35,7 @@ struct Color
|
||||||
float r, g, b, a;
|
float r, g, b, a;
|
||||||
|
|
||||||
//! Constructor; default values are (0,0,0,0) = black
|
//! Constructor; default values are (0,0,0,0) = black
|
||||||
Color(float aR = 0.0f, float aG = 0.0f, float aB = 0.0f, float aA = 0.0f)
|
explicit Color(float aR = 0.0f, float aG = 0.0f, float aB = 0.0f, float aA = 0.0f)
|
||||||
: r(aR), g(aG), b(aB), a(aA) {}
|
: r(aR), g(aG), b(aB), a(aA) {}
|
||||||
|
|
||||||
inline Gfx::Color Inverse() const
|
inline Gfx::Color Inverse() const
|
||||||
|
|
|
@ -47,9 +47,9 @@ struct Vertex
|
||||||
Math::Vector normal;
|
Math::Vector normal;
|
||||||
Math::Point texCoord;
|
Math::Point texCoord;
|
||||||
|
|
||||||
Vertex(Math::Vector aCoord = Math::Vector(),
|
explicit Vertex(Math::Vector aCoord = Math::Vector(),
|
||||||
Math::Vector aNormal = Math::Vector(),
|
Math::Vector aNormal = Math::Vector(),
|
||||||
Math::Point aTexCoord = Math::Point())
|
Math::Point aTexCoord = Math::Point())
|
||||||
: coord(aCoord), normal(aNormal), texCoord(aTexCoord) {}
|
: coord(aCoord), normal(aNormal), texCoord(aTexCoord) {}
|
||||||
|
|
||||||
|
|
||||||
|
@ -83,10 +83,10 @@ struct VertexCol
|
||||||
Gfx::Color specular;
|
Gfx::Color specular;
|
||||||
Math::Point texCoord;
|
Math::Point texCoord;
|
||||||
|
|
||||||
VertexCol(Math::Vector aCoord = Math::Vector(),
|
explicit VertexCol(Math::Vector aCoord = Math::Vector(),
|
||||||
Gfx::Color aColor = Gfx::Color(),
|
Gfx::Color aColor = Gfx::Color(),
|
||||||
Gfx::Color aSpecular = Gfx::Color(),
|
Gfx::Color aSpecular = Gfx::Color(),
|
||||||
Math::Point aTexCoord = Math::Point())
|
Math::Point aTexCoord = Math::Point())
|
||||||
: coord(aCoord), color(aColor), specular(aSpecular), texCoord(aTexCoord) {}
|
: coord(aCoord), color(aColor), specular(aSpecular), texCoord(aTexCoord) {}
|
||||||
|
|
||||||
//! Returns a string "(c: [...], col: [...], sp: [...], tc: [...])"
|
//! Returns a string "(c: [...], col: [...], sp: [...], tc: [...])"
|
||||||
|
@ -115,10 +115,10 @@ struct VertexTex2
|
||||||
Math::Point texCoord;
|
Math::Point texCoord;
|
||||||
Math::Point texCoord2;
|
Math::Point texCoord2;
|
||||||
|
|
||||||
VertexTex2(Math::Vector aCoord = Math::Vector(),
|
explicit VertexTex2(Math::Vector aCoord = Math::Vector(),
|
||||||
Math::Vector aNormal = Math::Vector(),
|
Math::Vector aNormal = Math::Vector(),
|
||||||
Math::Point aTexCoord = Math::Point(),
|
Math::Point aTexCoord = Math::Point(),
|
||||||
Math::Point aTexCoord2 = Math::Point())
|
Math::Point aTexCoord2 = Math::Point())
|
||||||
: coord(aCoord), normal(aNormal), texCoord(aTexCoord), texCoord2(aTexCoord2) {}
|
: coord(aCoord), normal(aNormal), texCoord(aTexCoord), texCoord2(aTexCoord2) {}
|
||||||
|
|
||||||
//! Sets the fields from Gfx::Vertex with texCoord2 = (0,0)
|
//! Sets the fields from Gfx::Vertex with texCoord2 = (0,0)
|
||||||
|
|
|
@ -1272,14 +1272,14 @@ bool Gfx::CCamera::EventFrameFree(const Event &event)
|
||||||
m_heightEye -= event.rTime * factor * m_speed;
|
m_heightEye -= event.rTime * factor * m_speed;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_terrain->ValidPosition(m_eyePt, 10.0f);
|
m_terrain->AdjustToBounds(m_eyePt, 10.0f);
|
||||||
|
|
||||||
if (m_terrain->MoveOnFloor(m_eyePt, true))
|
if (m_terrain->AdjustToFloor(m_eyePt, true))
|
||||||
{
|
{
|
||||||
m_eyePt.y += m_heightEye;
|
m_eyePt.y += m_heightEye;
|
||||||
|
|
||||||
Math::Vector pos = m_eyePt;
|
Math::Vector pos = m_eyePt;
|
||||||
if (m_terrain->MoveOnFloor(pos, true))
|
if (m_terrain->AdjustToFloor(pos, true))
|
||||||
{
|
{
|
||||||
pos.y -= 2.0f;
|
pos.y -= 2.0f;
|
||||||
if (m_eyePt.y < pos.y)
|
if (m_eyePt.y < pos.y)
|
||||||
|
@ -1290,7 +1290,7 @@ bool Gfx::CCamera::EventFrameFree(const Event &event)
|
||||||
|
|
||||||
Math::Vector lookatPt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, 50.0f);
|
Math::Vector lookatPt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, 50.0f);
|
||||||
|
|
||||||
if (m_terrain->MoveOnFloor(lookatPt, true))
|
if (m_terrain->AdjustToFloor(lookatPt, true))
|
||||||
lookatPt.y += m_heightLookat;
|
lookatPt.y += m_heightLookat;
|
||||||
|
|
||||||
SetViewTime(m_eyePt, lookatPt, event.rTime);
|
SetViewTime(m_eyePt, lookatPt, event.rTime);
|
||||||
|
@ -1314,14 +1314,14 @@ bool Gfx::CCamera::EventFrameEdit(const Event &event)
|
||||||
m_fixDirectionH = Math::NormAngle(m_fixDirectionH);
|
m_fixDirectionH = Math::NormAngle(m_fixDirectionH);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_terrain->ValidPosition(m_eyePt, 10.0f);
|
m_terrain->AdjustToBounds(m_eyePt, 10.0f);
|
||||||
|
|
||||||
if (m_terrain->MoveOnFloor(m_eyePt, false))
|
if (m_terrain->AdjustToFloor(m_eyePt, false))
|
||||||
{
|
{
|
||||||
m_eyePt.y += m_editHeight;
|
m_eyePt.y += m_editHeight;
|
||||||
|
|
||||||
Math::Vector pos = m_eyePt;
|
Math::Vector pos = m_eyePt;
|
||||||
if (m_terrain->MoveOnFloor(pos, false))
|
if (m_terrain->AdjustToFloor(pos, false))
|
||||||
{
|
{
|
||||||
pos.y += 2.0f;
|
pos.y += 2.0f;
|
||||||
if (m_eyePt.y < pos.y)
|
if (m_eyePt.y < pos.y)
|
||||||
|
@ -1332,7 +1332,7 @@ bool Gfx::CCamera::EventFrameEdit(const Event &event)
|
||||||
|
|
||||||
Math::Vector lookatPt = Math::LookatPoint( m_eyePt, m_directionH, m_directionV, 50.0f );
|
Math::Vector lookatPt = Math::LookatPoint( m_eyePt, m_directionH, m_directionV, 50.0f );
|
||||||
|
|
||||||
if ( m_terrain->MoveOnFloor(lookatPt, true))
|
if ( m_terrain->AdjustToFloor(lookatPt, true))
|
||||||
lookatPt.y += m_heightLookat;
|
lookatPt.y += m_heightLookat;
|
||||||
|
|
||||||
SetViewTime(m_eyePt, lookatPt, event.rTime);
|
SetViewTime(m_eyePt, lookatPt, event.rTime);
|
||||||
|
@ -1483,7 +1483,7 @@ bool Gfx::CCamera::EventFrameBack(const Event &event)
|
||||||
if ( (physics != NULL) && physics->GetLand() ) // ground?
|
if ( (physics != NULL) && physics->GetLand() ) // ground?
|
||||||
{
|
{
|
||||||
Math::Vector pos = lookatPt + (lookatPt - m_eyePt);
|
Math::Vector pos = lookatPt + (lookatPt - m_eyePt);
|
||||||
float floor = m_terrain->GetFloorHeight(pos) - 4.0f;
|
float floor = m_terrain->GetHeightToFloor(pos) - 4.0f;
|
||||||
if (floor > 0.0f)
|
if (floor > 0.0f)
|
||||||
m_eyePt.y += floor; // shows the descent in front
|
m_eyePt.y += floor; // shows the descent in front
|
||||||
}
|
}
|
||||||
|
@ -1551,14 +1551,14 @@ bool Gfx::CCamera::EventFrameExplo(const Event &event)
|
||||||
if (m_mouseDirH != 0.0f)
|
if (m_mouseDirH != 0.0f)
|
||||||
m_directionH -= m_mouseDirH * event.rTime * 0.7f * m_speed;
|
m_directionH -= m_mouseDirH * event.rTime * 0.7f * m_speed;
|
||||||
|
|
||||||
m_terrain->ValidPosition(m_eyePt, 10.0f);
|
m_terrain->AdjustToBounds(m_eyePt, 10.0f);
|
||||||
|
|
||||||
if ( m_terrain->MoveOnFloor(m_eyePt, false) )
|
if ( m_terrain->AdjustToFloor(m_eyePt, false) )
|
||||||
{
|
{
|
||||||
m_eyePt.y += m_heightEye;
|
m_eyePt.y += m_heightEye;
|
||||||
|
|
||||||
Math::Vector pos = m_eyePt;
|
Math::Vector pos = m_eyePt;
|
||||||
if ( m_terrain->MoveOnFloor(pos, false) )
|
if ( m_terrain->AdjustToFloor(pos, false) )
|
||||||
{
|
{
|
||||||
pos.y += 2.0f;
|
pos.y += 2.0f;
|
||||||
if ( m_eyePt.y < pos.y )
|
if ( m_eyePt.y < pos.y )
|
||||||
|
@ -1569,7 +1569,7 @@ bool Gfx::CCamera::EventFrameExplo(const Event &event)
|
||||||
|
|
||||||
Math::Vector lookatPt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, 50.0f);
|
Math::Vector lookatPt = Math::LookatPoint(m_eyePt, m_directionH, m_directionV, 50.0f);
|
||||||
|
|
||||||
if (m_terrain->MoveOnFloor(lookatPt, true))
|
if (m_terrain->AdjustToFloor(lookatPt, true))
|
||||||
lookatPt.y += m_heightLookat;
|
lookatPt.y += m_heightLookat;
|
||||||
|
|
||||||
SetViewTime(m_eyePt, lookatPt, event.rTime);
|
SetViewTime(m_eyePt, lookatPt, event.rTime);
|
||||||
|
@ -1680,7 +1680,7 @@ Math::Vector Gfx::CCamera::ExcludeTerrain(Math::Vector eye, Math::Vector lookat,
|
||||||
float &angleH, float &angleV)
|
float &angleH, float &angleV)
|
||||||
{
|
{
|
||||||
Math::Vector pos = eye;
|
Math::Vector pos = eye;
|
||||||
if (m_terrain->MoveOnFloor(pos))
|
if (m_terrain->AdjustToFloor(pos))
|
||||||
{
|
{
|
||||||
float dist = Math::DistanceProjected(lookat, pos);
|
float dist = Math::DistanceProjected(lookat, pos);
|
||||||
pos.y += 2.0f+dist*0.1f;
|
pos.y += 2.0f+dist*0.1f;
|
||||||
|
|
|
@ -28,7 +28,8 @@
|
||||||
|
|
||||||
const int CLOUD_LINE_PREALLOCATE_COUNT = 100;
|
const int CLOUD_LINE_PREALLOCATE_COUNT = 100;
|
||||||
|
|
||||||
const int DIMEXPAND = 4; // extension of the dimensions
|
//! Extension of the bricks dimensions
|
||||||
|
const int CLOUD_SIZE_EXPAND = 4;
|
||||||
|
|
||||||
|
|
||||||
Gfx::CCloud::CCloud(CInstanceManager* iMan, Gfx::CEngine* engine)
|
Gfx::CCloud::CCloud(CInstanceManager* iMan, Gfx::CEngine* engine)
|
||||||
|
@ -99,10 +100,10 @@ void Gfx::CCloud::Draw()
|
||||||
if (m_level == 0.0f) return;
|
if (m_level == 0.0f) return;
|
||||||
if (m_lines.empty()) return;
|
if (m_lines.empty()) return;
|
||||||
|
|
||||||
std::vector<Gfx::VertexTex2> vertices((m_brick+2)*2, Gfx::VertexTex2());
|
std::vector<Gfx::VertexTex2> vertices((m_brickCount+2)*2, Gfx::VertexTex2());
|
||||||
|
|
||||||
float iDeep = m_engine->GetDeepView();
|
float iDeep = m_engine->GetDeepView();
|
||||||
float deep = (m_brick*m_size)/2.0f;
|
float deep = (m_brickCount*m_brickSize)/2.0f;
|
||||||
m_engine->SetDeepView(deep);
|
m_engine->SetDeepView(deep);
|
||||||
m_engine->SetFocus(m_engine->GetFocus());
|
m_engine->SetFocus(m_engine->GetFocus());
|
||||||
m_engine->UpdateMatProj(); // increases the depth of view
|
m_engine->UpdateMatProj(); // increases the depth of view
|
||||||
|
@ -132,7 +133,7 @@ void Gfx::CCloud::Draw()
|
||||||
matrix.LoadIdentity();
|
matrix.LoadIdentity();
|
||||||
device->SetTransform(Gfx::TRANSFORM_WORLD, matrix);
|
device->SetTransform(Gfx::TRANSFORM_WORLD, matrix);
|
||||||
|
|
||||||
float size = m_size/2.0f;
|
float size = m_brickSize/2.0f;
|
||||||
Math::Vector eye = m_engine->GetEyePt();
|
Math::Vector eye = m_engine->GetEyePt();
|
||||||
Math::Vector n = Math::Vector(0.0f, -1.0f, 0.0f);
|
Math::Vector n = Math::Vector(0.0f, -1.0f, 0.0f);
|
||||||
|
|
||||||
|
@ -195,11 +196,11 @@ void Gfx::CCloud::CreateLine(int x, int y, int len)
|
||||||
line.y = y;
|
line.y = y;
|
||||||
line.len = len;
|
line.len = len;
|
||||||
|
|
||||||
float offset = m_brick*m_size/2.0f - m_size/2.0f;
|
float offset = m_brickCount*m_brickSize/2.0f - m_brickSize/2.0f;
|
||||||
|
|
||||||
line.px1 = m_size* line.x - offset;
|
line.px1 = m_brickSize* line.x - offset;
|
||||||
line.px2 = m_size*(line.x+line.len) - offset;
|
line.px2 = m_brickSize*(line.x+line.len) - offset;
|
||||||
line.pz = m_size* line.y - offset;
|
line.pz = m_brickSize* line.y - offset;
|
||||||
|
|
||||||
m_lines.push_back(line);
|
m_lines.push_back(line);
|
||||||
}
|
}
|
||||||
|
@ -223,18 +224,18 @@ void Gfx::CCloud::Create(const std::string& fileName,
|
||||||
|
|
||||||
m_wind = m_terrain->GetWind();
|
m_wind = m_terrain->GetWind();
|
||||||
|
|
||||||
m_brick = m_terrain->GetBrick()*m_terrain->GetMosaic()*DIMEXPAND;
|
m_brickCount = m_terrain->GetBrickCount()*m_terrain->GetMosaicCount()*CLOUD_SIZE_EXPAND;
|
||||||
m_size = m_terrain->GetSize();
|
m_brickSize = m_terrain->GetBrickSize();
|
||||||
|
|
||||||
m_brick /= m_subdiv*DIMEXPAND;
|
m_brickCount /= m_subdiv*CLOUD_SIZE_EXPAND;
|
||||||
m_size *= m_subdiv*DIMEXPAND;
|
m_brickSize *= m_subdiv*CLOUD_SIZE_EXPAND;
|
||||||
|
|
||||||
if (m_level == 0.0f)
|
if (m_level == 0.0f)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_lines.clear();
|
m_lines.clear();
|
||||||
for (int y = 0; y < m_brick; y++)
|
for (int y = 0; y < m_brickCount; y++)
|
||||||
CreateLine(0, y, m_brick);
|
CreateLine(0, y, m_brickCount);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,9 +126,9 @@ protected:
|
||||||
//! Wind speed
|
//! Wind speed
|
||||||
Math::Vector m_wind;
|
Math::Vector m_wind;
|
||||||
//! Brick mosaic
|
//! Brick mosaic
|
||||||
int m_brick;
|
int m_brickCount;
|
||||||
//! Size of a brick element
|
//! Size of a brick element
|
||||||
float m_size;
|
float m_brickSize;
|
||||||
|
|
||||||
std::vector<Gfx::CloudLine> m_lines;
|
std::vector<Gfx::CloudLine> m_lines;
|
||||||
|
|
||||||
|
|
|
@ -142,14 +142,14 @@ Gfx::CEngine::CEngine(CInstanceManager *iMan, CApplication *app)
|
||||||
m_eyeDirH = 0.0f;
|
m_eyeDirH = 0.0f;
|
||||||
m_eyeDirV = 0.0f;
|
m_eyeDirV = 0.0f;
|
||||||
m_backgroundName = ""; // no background image
|
m_backgroundName = ""; // no background image
|
||||||
m_backgroundColorUp = 0;
|
m_backgroundColorUp = Gfx::Color();
|
||||||
m_backgroundColorDown = 0;
|
m_backgroundColorDown = Gfx::Color();
|
||||||
m_backgroundCloudUp = 0;
|
m_backgroundCloudUp = Gfx::Color();
|
||||||
m_backgroundCloudDown = 0;
|
m_backgroundCloudDown = Gfx::Color();
|
||||||
m_backgroundFull = false;
|
m_backgroundFull = false;
|
||||||
m_backgroundQuarter = false;
|
m_backgroundQuarter = false;
|
||||||
m_overFront = true;
|
m_overFront = true;
|
||||||
m_overColor = 0;
|
m_overColor = Gfx::Color();
|
||||||
m_overMode = ENG_RSTATE_TCOLOR_BLACK;
|
m_overMode = ENG_RSTATE_TCOLOR_BLACK;
|
||||||
m_highlightRank[0] = -1; // empty list
|
m_highlightRank[0] = -1; // empty list
|
||||||
m_highlightTime = 0.0f;
|
m_highlightTime = 0.0f;
|
||||||
|
@ -2839,7 +2839,7 @@ void Gfx::CEngine::Render()
|
||||||
|
|
||||||
m_statisticTriangle = 0;
|
m_statisticTriangle = 0;
|
||||||
m_lastState = -1;
|
m_lastState = -1;
|
||||||
m_lastColor = 999;
|
m_lastColor = Gfx::Color(-1.0f);
|
||||||
m_lastMaterial = Gfx::Material();
|
m_lastMaterial = Gfx::Material();
|
||||||
|
|
||||||
m_lightMan->UpdateLights();
|
m_lightMan->UpdateLights();
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -35,7 +35,7 @@ class CWater;
|
||||||
|
|
||||||
|
|
||||||
//! Limit of slope considered a flat piece of land
|
//! Limit of slope considered a flat piece of land
|
||||||
const short FLATLIMIT = (5.0f*Math::PI/180.0f);
|
const short TERRAIN_FLATLIMIT = (5.0f*Math::PI/180.0f);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -61,6 +61,10 @@ enum TerrainRes
|
||||||
//@}
|
//@}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \struct BuildingLevel
|
||||||
|
* \brief Flat level for building
|
||||||
|
*/
|
||||||
struct BuildingLevel
|
struct BuildingLevel
|
||||||
{
|
{
|
||||||
Math::Vector center;
|
Math::Vector center;
|
||||||
|
@ -81,29 +85,43 @@ struct BuildingLevel
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \struct TerrainMaterial
|
||||||
|
* \brief Material for ground surface
|
||||||
|
*/
|
||||||
struct TerrainMaterial
|
struct TerrainMaterial
|
||||||
{
|
{
|
||||||
|
//! Unique ID
|
||||||
short id;
|
short id;
|
||||||
|
//! Texture
|
||||||
std::string texName;
|
std::string texName;
|
||||||
float u,v;
|
//! UV texture coordinates
|
||||||
|
Math::Point uv;
|
||||||
|
//! Terrain hardness (defines e.g. sound of walking)
|
||||||
float hardness;
|
float hardness;
|
||||||
char mat[4]; // up, right, down, left
|
//! IDs of neighbor materials: up, right, down, left
|
||||||
|
char mat[4];
|
||||||
|
|
||||||
TerrainMaterial()
|
TerrainMaterial()
|
||||||
{
|
{
|
||||||
id = 0;
|
id = 0;
|
||||||
u = v = 0.0f;
|
|
||||||
hardness = 0.0f;
|
hardness = 0.0f;
|
||||||
mat[0] = mat[1] = mat[2] = mat[3] = 0;
|
mat[0] = mat[1] = mat[2] = mat[3] = 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DotLevel
|
/**
|
||||||
|
* \struct TerrainMaterialPoint
|
||||||
|
* \brief Material used for terrain point
|
||||||
|
*/
|
||||||
|
struct TerrainMaterialPoint
|
||||||
{
|
{
|
||||||
|
//! ID of material
|
||||||
short id;
|
short id;
|
||||||
char mat[4]; // up, right, down, left
|
//! IDs of neighbor materials: up, right, down, left
|
||||||
|
char mat[4];
|
||||||
|
|
||||||
DotLevel()
|
TerrainMaterialPoint()
|
||||||
{
|
{
|
||||||
id = 0;
|
id = 0;
|
||||||
mat[0] = mat[1] = mat[2] = mat[3] = 0;
|
mat[0] = mat[1] = mat[2] = mat[3] = 0;
|
||||||
|
@ -132,17 +150,73 @@ struct FlyingLimit
|
||||||
* \class CTerrain
|
* \class CTerrain
|
||||||
* \brief Terrain loader/generator and manager
|
* \brief Terrain loader/generator and manager
|
||||||
*
|
*
|
||||||
|
* \section Mapping Terrain mapping
|
||||||
|
*
|
||||||
* Terrain is created from relief textures specifying a XY plane with height
|
* Terrain is created from relief textures specifying a XY plane with height
|
||||||
* values which are then scaled and translated into XZ surface forming the
|
* values which are then scaled and translated into XZ surface forming the
|
||||||
* terrain of game level.
|
* terrain of game level.
|
||||||
*
|
*
|
||||||
* The class also facilitates creating and searching for flat space expanses
|
* The basic unit of terrain is called "brick", which is two triangles
|
||||||
* for construction of buildings.
|
* forming a quad. Bricks have constant size (brick size)
|
||||||
|
* in X and Z direction.
|
||||||
|
* Points forming the bricks correspond one-to-one to relief data points
|
||||||
|
* (pixels in relief image).
|
||||||
*
|
*
|
||||||
* The terrain also specifies underground resources loaded from texture
|
* Bricks are grouped into "mosaics". Mosaic is a square containing
|
||||||
* and flying limits for the player.
|
* brickCount x brickCount bricks where brickCount is an even power of 2.
|
||||||
|
* Each mosaic corresponds to one created engine object.
|
||||||
*
|
*
|
||||||
* ...
|
* The whole terrain is also a square formed by mosaicCount * mosaicCount
|
||||||
|
* of mosaics.
|
||||||
|
*
|
||||||
|
* Image coordinates are converted in the following way to world coordinates
|
||||||
|
* of brick points (Wx, Wy, Wz - world coordinates, Ix, Iy - image coordinates,
|
||||||
|
* Pxy - pixel value at Ix,Iy):
|
||||||
|
*
|
||||||
|
* Wx = (Ix - brickCount*mosaicCount / 2.0f) * brickSize \n
|
||||||
|
* Wz = (Iy - brickCount*mosaicCount / 2.0f) * brickSize \n
|
||||||
|
* Wy = (Pxy / 255.0f) * reliefScale
|
||||||
|
*
|
||||||
|
* To create and initialize a terrain, you must call Generate() as the first function,
|
||||||
|
* setting the number of bricks, mosaics etc.
|
||||||
|
*
|
||||||
|
* \section Materials Materials and textures
|
||||||
|
*
|
||||||
|
* The terrain can be textured in two ways:
|
||||||
|
* - by applying texture index table
|
||||||
|
* - by specifying one or more "materials" that cover "material points"
|
||||||
|
*
|
||||||
|
* Textures are applied to subdivisions of mosaics (groups of bricks of size
|
||||||
|
* brickCount / textureSubdivCount).
|
||||||
|
*
|
||||||
|
* \subsection TextureIndexes Texture indexes
|
||||||
|
*
|
||||||
|
* Texture indexes specify the texture for each textured point by concatenating
|
||||||
|
* base name of texture, the index number and texture extension.
|
||||||
|
*
|
||||||
|
* Texture indexes are specified directly in InitTextures().
|
||||||
|
*
|
||||||
|
* \subsection TerrainMaterials Terrain materials
|
||||||
|
*
|
||||||
|
* Terrain materials are more sophisticated system. Each material is a texture,
|
||||||
|
* applied to one area, but specifying also the textures to use on surrounding areas:
|
||||||
|
* left, right, bottom and top.
|
||||||
|
*
|
||||||
|
* You specify one or more terrain materials in AddMaterial() function.
|
||||||
|
* The function will add a material for given circle on the ground, with some
|
||||||
|
* randomized matching of supplied materials and sophisticated logic for ensuring
|
||||||
|
* that borders between neighboring materials follow the specified rules.
|
||||||
|
*
|
||||||
|
* \subsection BuildingLevels Other features
|
||||||
|
*
|
||||||
|
* Terrain can have specified building levels - flat space expanses,
|
||||||
|
* where relief data is specifically adjusted to level space to allow
|
||||||
|
* construction of buildings.
|
||||||
|
*
|
||||||
|
* Undergound resources can be supplied by loading them from image like relief data.
|
||||||
|
*
|
||||||
|
* Terrain also specifies flying limits for player: one global level and possible
|
||||||
|
* additional spherical restrictions.
|
||||||
*/
|
*/
|
||||||
class CTerrain
|
class CTerrain
|
||||||
{
|
{
|
||||||
|
@ -151,25 +225,32 @@ public:
|
||||||
~CTerrain();
|
~CTerrain();
|
||||||
|
|
||||||
//! Generates a new flat terrain
|
//! Generates a new flat terrain
|
||||||
bool Generate(int mosaic, int brickPow2, float size, float vision, int depth, float hardness);
|
bool Generate(int mosaicCount, int brickCountPow2, float brickSize, float vision, int depth, float hardness);
|
||||||
|
|
||||||
//! Initializes the names of textures to use for the land
|
//! Initializes the names of textures to use for the land
|
||||||
bool InitTextures(const std::string& baseName, int* table, int dx, int dy);
|
bool InitTextures(const std::string& baseName, int* table, int dx, int dy);
|
||||||
//! Empties level
|
|
||||||
void LevelFlush();
|
//! Clears all terrain materials
|
||||||
//! Initializes the names of textures to use for the land
|
void FlushMaterials();
|
||||||
void LevelMaterial(int id, const std::string& baseName, float u, float v, int up, int right, int down, int left, float hardness);
|
//! Adds a terrain material the names of textures to use for the land
|
||||||
//! Initializes all the ground with a material
|
void AddMaterial(int id, const std::string& baseName, const Math::Point& uv,
|
||||||
bool LevelInit(int id);
|
int up, int right, int down, int left, float hardness);
|
||||||
|
//! Initializes all the ground with one material
|
||||||
|
bool InitMaterials(int id);
|
||||||
//! Generates a level in the terrain
|
//! Generates a level in the terrain
|
||||||
bool LevelGenerate(int *id, float min, float max, float slope, float freq, Math::Vector center, float radius);
|
bool GenerateMaterials(int *id, float min, float max, float slope, float freq, Math::Vector center, float radius);
|
||||||
//! Initializes a completely flat terrain
|
|
||||||
|
//! Clears the relief data to zero
|
||||||
void FlushRelief();
|
void FlushRelief();
|
||||||
//! Load relief from a PNG file
|
//! Load relief from image
|
||||||
bool ReliefFromPNG(const std::string& filename, float scaleRelief, bool adjustBorder);
|
bool LoadRelief(const std::string& fileName, float scaleRelief, bool adjustBorder);
|
||||||
//! Load resources from a PNG file
|
|
||||||
bool ResFromPNG(const std::string& filename);
|
//! Load resources from image
|
||||||
|
bool LoadResources(const std::string& fileName);
|
||||||
|
|
||||||
//! Creates all objects of the terrain within the 3D engine
|
//! Creates all objects of the terrain within the 3D engine
|
||||||
bool CreateObjects(bool multiRes);
|
bool CreateObjects();
|
||||||
|
|
||||||
//! Modifies the terrain's relief
|
//! Modifies the terrain's relief
|
||||||
bool Terraform(const Math::Vector& p1, const Math::Vector& p2, float height);
|
bool Terraform(const Math::Vector& p1, const Math::Vector& p2, float height);
|
||||||
|
|
||||||
|
@ -179,24 +260,24 @@ public:
|
||||||
Math::Vector GetWind();
|
Math::Vector GetWind();
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
//! Gives the exact slope of the terrain of a place given
|
//! Gives the exact slope of the terrain at 2D (XZ) position
|
||||||
float GetFineSlope(const Math::Vector& pos);
|
float GetFineSlope(const Math::Vector& pos);
|
||||||
//! Gives the approximate slope of the terrain of a specific location
|
//! Gives the approximate slope of the terrain at 2D (XZ) position
|
||||||
float GetCoarseSlope(const Math::Vector& pos);
|
float GetCoarseSlope(const Math::Vector& pos);
|
||||||
//! Gives the normal vector at the position p (x,-,z) of the ground
|
//! Gives the normal vector at 2D (XZ) position
|
||||||
bool GetNormal(Math::Vector& n, const Math::Vector &p);
|
bool GetNormal(Math::Vector& n, const Math::Vector &p);
|
||||||
//! returns the height of the ground
|
//! Returns the height of the ground level at 2D (XZ) position
|
||||||
float GetFloorLevel(const Math::Vector& p, bool brut=false, bool water=false);
|
float GetFloorLevel(const Math::Vector& pos, bool brut=false, bool water=false);
|
||||||
//! Returns the height to the ground
|
//! Returns the distance to the ground level from 3D position
|
||||||
float GetFloorHeight(const Math::Vector& p, bool brut=false, bool water=false);
|
float GetHeightToFloor(const Math::Vector& pos, bool brut=false, bool water=false);
|
||||||
//! Modifies the coordinate "y" of point "p" to rest on the ground floor
|
//! Modifies the Y coordinate of 3D position to rest on the ground floor
|
||||||
bool MoveOnFloor(Math::Vector& p, bool brut=false, bool water=false);
|
bool AdjustToFloor(Math::Vector& pos, bool brut=false, bool water=false);
|
||||||
//! Modifies a coordinate so that it is on the ground
|
//! Adjusts 3D position so that it is within standard terrain boundaries
|
||||||
bool ValidPosition(Math::Vector& p, float marging);
|
bool AdjustToStandardBounds(Math::Vector &pos);
|
||||||
//! Returns the resource type available underground
|
//! Adjusts 3D position so that it is within terrain boundaries and the given margin
|
||||||
Gfx::TerrainRes GetResource(const Math::Vector& p);
|
bool AdjustToBounds(Math::Vector& pos, float margin);
|
||||||
//! Adjusts a position so that it does not exceed the boundaries
|
//! Returns the resource type available underground at 2D (XZ) position
|
||||||
void LimitPos(Math::Vector &pos);
|
Gfx::TerrainRes GetResource(const Math::Vector& pos);
|
||||||
|
|
||||||
//! Empty the table of elevations
|
//! Empty the table of elevations
|
||||||
void FlushBuildingLevel();
|
void FlushBuildingLevel();
|
||||||
|
@ -207,16 +288,21 @@ public:
|
||||||
//! Removes the elevation for a building when it was destroyed
|
//! Removes the elevation for a building when it was destroyed
|
||||||
bool DeleteBuildingLevel(Math::Vector center);
|
bool DeleteBuildingLevel(Math::Vector center);
|
||||||
//! Returns the influence factor whether a position is on a possible rise
|
//! Returns the influence factor whether a position is on a possible rise
|
||||||
float GetBuildingFactor(const Math::Vector& p);
|
float GetBuildingFactor(const Math::Vector& pos);
|
||||||
float GetHardness(const Math::Vector& p);
|
//! Returns the hardness of the ground in a given place
|
||||||
|
float GetHardness(const Math::Vector& pos);
|
||||||
|
|
||||||
int GetMosaic();
|
//! Returns number of mosaics
|
||||||
int GetBrick();
|
int GetMosaicCount();
|
||||||
float GetSize();
|
//! Returns number of bricks in mosaic
|
||||||
float GetScaleRelief();
|
int GetBrickCount();
|
||||||
|
//! Returns brick size
|
||||||
|
float GetBrickSize();
|
||||||
|
//! Returns the vertical scale of relief
|
||||||
|
float GetReliefScale();
|
||||||
|
|
||||||
//! Shows the flat areas on the ground
|
//! Shows the flat areas on the ground
|
||||||
void GroundFlat(Math::Vector pos);
|
void ShowFlatGround(Math::Vector pos);
|
||||||
//! Calculates the radius of the largest flat area available
|
//! Calculates the radius of the largest flat area available
|
||||||
float GetFlatZoneRadius(Math::Vector center, float max);
|
float GetFlatZoneRadius(Math::Vector center, float max);
|
||||||
|
|
||||||
|
@ -234,7 +320,7 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
//! Adds a point of elevation in the buffer of relief
|
//! Adds a point of elevation in the buffer of relief
|
||||||
bool ReliefAddDot(Math::Vector pos, float scaleRelief);
|
bool AddReliefPoint(Math::Vector pos, float scaleRelief);
|
||||||
//! Adjust the edges of each mosaic to be compatible with all lower resolutions
|
//! Adjust the edges of each mosaic to be compatible with all lower resolutions
|
||||||
void AdjustRelief();
|
void AdjustRelief();
|
||||||
//! Calculates a vector of the terrain
|
//! Calculates a vector of the terrain
|
||||||
|
@ -244,28 +330,28 @@ protected:
|
||||||
//! Creates all objects of a mosaic
|
//! Creates all objects of a mosaic
|
||||||
bool CreateMosaic(int ox, int oy, int step, int objRank, const Gfx::Material& mat, float min, float max);
|
bool CreateMosaic(int ox, int oy, int step, int objRank, const Gfx::Material& mat, float min, float max);
|
||||||
//! Creates all objects in a mesh square ground
|
//! Creates all objects in a mesh square ground
|
||||||
bool CreateSquare(bool multiRes, int x, int y);
|
bool CreateSquare(int x, int y);
|
||||||
|
|
||||||
//! Seeks a materials based on theirs identifier
|
//! Seeks a material based on its ID
|
||||||
Gfx::TerrainMaterial* LevelSearchMat(int id);
|
Gfx::TerrainMaterial* FindMaterial(int id);
|
||||||
//! Chooses texture to use for a given square
|
//! Seeks a material based on neighbor values
|
||||||
void LevelTextureName(int x, int y, std::string& name, Math::Point &uv);
|
int FindMaterialByNeighbors(char *mat);
|
||||||
|
//! Returns the texture name and UV coords to use for a given square
|
||||||
|
void GetTexture(int x, int y, std::string& name, Math::Point& uv);
|
||||||
//! Returns the height of the terrain
|
//! Returns the height of the terrain
|
||||||
float LevelGetHeight(int x, int y);
|
float GetHeight(int x, int y);
|
||||||
//! Decide whether a point is using the materials
|
//! Decide whether a point is using the materials
|
||||||
bool LevelGetDot(int x, int y, float min, float max, float slope);
|
bool CheckMaterialPoint(int x, int y, float min, float max, float slope);
|
||||||
//! Seeks if material exists
|
|
||||||
int LevelTestMat(char *mat);
|
|
||||||
//! Modifies the state of a point and its four neighbors, without testing if possible
|
//! Modifies the state of a point and its four neighbors, without testing if possible
|
||||||
void LevelSetDot(int x, int y, int id, char *mat);
|
void SetMaterialPoint(int x, int y, int id, char *mat);
|
||||||
//! Tests if a material can give a place, according to its four neighbors. If yes, puts the point.
|
|
||||||
bool LevelIfDot(int x, int y, int id, char *mat);
|
|
||||||
//! Modifies the state of a point
|
//! Modifies the state of a point
|
||||||
bool LevelPutDot(int x, int y, int id);
|
bool ChangeMaterialPoint(int x, int y, int id);
|
||||||
//! Initializes a table with empty levels
|
//! Tests if a material can give a place, according to its four neighbors. If yes, puts the point.
|
||||||
void LevelOpenTable();
|
bool CondChangeMaterialPoint(int x, int y, int id, char *mat);
|
||||||
//! Closes the level table
|
//! Initializes material points array
|
||||||
void LevelCloseTable();
|
void InitMaterialPoints();
|
||||||
|
//! Clears the material points
|
||||||
|
void FlushMaterialPoints();
|
||||||
|
|
||||||
//! Adjusts a position according to a possible rise
|
//! Adjusts a position according to a possible rise
|
||||||
void AdjustBuildingLevel(Math::Vector &p);
|
void AdjustBuildingLevel(Math::Vector &p);
|
||||||
|
@ -275,39 +361,51 @@ protected:
|
||||||
CEngine* m_engine;
|
CEngine* m_engine;
|
||||||
CWater* m_water;
|
CWater* m_water;
|
||||||
|
|
||||||
//! Number of mosaics
|
//! Relief data points
|
||||||
int m_mosaic;
|
|
||||||
//! Number of bricks per mosaics
|
|
||||||
int m_brick;
|
|
||||||
int m_levelDotSize;
|
|
||||||
//! Size of an item in a brick
|
|
||||||
float m_size;
|
|
||||||
//! Vision before a change of resolution
|
|
||||||
float m_vision;
|
|
||||||
//! Table of the relief
|
|
||||||
std::vector<float> m_relief;
|
std::vector<float> m_relief;
|
||||||
//! Table of textures
|
//! Resources data
|
||||||
std::vector<int> m_texture;
|
|
||||||
//! Table of rows of objects
|
|
||||||
std::vector<int> m_objRank;
|
|
||||||
//! Table of resources
|
|
||||||
std::vector<unsigned char> m_resources;
|
std::vector<unsigned char> m_resources;
|
||||||
bool m_multiText;
|
//! Texture indices
|
||||||
bool m_levelText;
|
std::vector<int> m_textures;
|
||||||
//! Scale of the mapping
|
//! Object ranks for mosaic objects
|
||||||
float m_scaleMapping;
|
std::vector<int> m_objRanks;
|
||||||
|
|
||||||
|
//! Number of mosaics (along one dimension)
|
||||||
|
int m_mosaicCount;
|
||||||
|
//! Number of bricks per mosaic (along one dimension)
|
||||||
|
int m_brickCount;
|
||||||
|
//! Number of terrain material dots (along one dimension)
|
||||||
|
int m_materialPointCount;
|
||||||
|
//! Size of single brick (along X and Z axis)
|
||||||
|
float m_brickSize;
|
||||||
|
//! Vertical (relief) scale
|
||||||
float m_scaleRelief;
|
float m_scaleRelief;
|
||||||
int m_subdivMapping;
|
//! Subdivision of material points in mosaic
|
||||||
|
int m_textureSubdivCount;
|
||||||
//! Number of different resolutions (1,2,3,4)
|
//! Number of different resolutions (1,2,3,4)
|
||||||
int m_depth;
|
int m_depth;
|
||||||
std::string m_texBaseName;
|
//! Scale of texture mapping
|
||||||
std::string m_texBaseExt;
|
float m_textureScale;
|
||||||
float m_defHardness;
|
//! Vision before a change of resolution
|
||||||
|
float m_vision;
|
||||||
|
|
||||||
std::vector<TerrainMaterial> m_levelMats;
|
//! Base name for single texture
|
||||||
std::vector<Gfx::DotLevel> m_levelDots;
|
std::string m_texBaseName;
|
||||||
int m_levelMatMax;
|
//! Extension for single texture
|
||||||
int m_levelID;
|
std::string m_texBaseExt;
|
||||||
|
//! Default hardness for level material
|
||||||
|
float m_defaultHardness;
|
||||||
|
|
||||||
|
//! True if using terrain material mapping
|
||||||
|
bool m_useMaterials;
|
||||||
|
//! Terrain materials
|
||||||
|
std::vector<Gfx::TerrainMaterial> m_materials;
|
||||||
|
//! Material for terrain points
|
||||||
|
std::vector<Gfx::TerrainMaterialPoint> m_materialPoints;
|
||||||
|
//! Maximum level ID (no ID is >= to this)
|
||||||
|
int m_maxMaterialID;
|
||||||
|
//! Internal counter for auto generation of material IDs
|
||||||
|
int m_materialAutoID;
|
||||||
|
|
||||||
std::vector<Gfx::BuildingLevel> m_buildingLevels;
|
std::vector<Gfx::BuildingLevel> m_buildingLevels;
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@ Gfx::CWater::CWater(CInstanceManager* iMan, Gfx::CEngine* engine)
|
||||||
m_level = 0.0f;
|
m_level = 0.0f;
|
||||||
m_draw = true;
|
m_draw = true;
|
||||||
m_lava = false;
|
m_lava = false;
|
||||||
m_color = 0xffffffff;
|
m_color = Gfx::Color(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
m_subdiv = 4;
|
m_subdiv = 4;
|
||||||
|
|
||||||
m_lines.reserve(WATERLINE_PREALLOCATE_COUNT);
|
m_lines.reserve(WATERLINE_PREALLOCATE_COUNT);
|
||||||
|
@ -330,7 +330,7 @@ void Gfx::CWater::DrawSurf()
|
||||||
if (m_type[0] == Gfx::WATER_NULL) return;
|
if (m_type[0] == Gfx::WATER_NULL) return;
|
||||||
if (m_lines.empty()) return;
|
if (m_lines.empty()) return;
|
||||||
|
|
||||||
std::vector<Gfx::VertexTex2> vertices((m_brick+2)*2, Gfx::VertexTex2());
|
std::vector<Gfx::VertexTex2> vertices((m_brickCount+2)*2, Gfx::VertexTex2());
|
||||||
|
|
||||||
Math::Vector eye = m_engine->GetEyePt();
|
Math::Vector eye = m_engine->GetEyePt();
|
||||||
|
|
||||||
|
@ -365,7 +365,7 @@ void Gfx::CWater::DrawSurf()
|
||||||
|
|
||||||
device->SetRenderState(Gfx::RENDER_STATE_FOG, true);
|
device->SetRenderState(Gfx::RENDER_STATE_FOG, true);
|
||||||
|
|
||||||
float size = m_size/2.0f;
|
float size = m_brickSize/2.0f;
|
||||||
float sizez = 0.0f;
|
float sizez = 0.0f;
|
||||||
if (under) sizez = -size;
|
if (under) sizez = -size;
|
||||||
else sizez = size;
|
else sizez = size;
|
||||||
|
@ -436,8 +436,8 @@ bool Gfx::CWater::GetWater(int x, int y)
|
||||||
x *= m_subdiv;
|
x *= m_subdiv;
|
||||||
y *= m_subdiv;
|
y *= m_subdiv;
|
||||||
|
|
||||||
float size = m_size/m_subdiv;
|
float size = m_brickSize/m_subdiv;
|
||||||
float offset = m_brick*m_size/2.0f;
|
float offset = m_brickCount*m_brickSize/2.0f;
|
||||||
|
|
||||||
for (int dy = 0; dy <= m_subdiv; dy++)
|
for (int dy = 0; dy <= m_subdiv; dy++)
|
||||||
{
|
{
|
||||||
|
@ -463,11 +463,11 @@ void Gfx::CWater::CreateLine(int x, int y, int len)
|
||||||
line.y = y;
|
line.y = y;
|
||||||
line.len = len;
|
line.len = len;
|
||||||
|
|
||||||
float offset = m_brick*m_size/2.0f - m_size/2.0f;
|
float offset = m_brickCount*m_brickSize/2.0f - m_brickSize/2.0f;
|
||||||
|
|
||||||
line.px1 = m_size* line.x - offset;
|
line.px1 = m_brickSize* line.x - offset;
|
||||||
line.px2 = m_size*(line.x+line.len) - offset;
|
line.px2 = m_brickSize*(line.x+line.len) - offset;
|
||||||
line.pz = m_size* line.y - offset;
|
line.pz = m_brickSize* line.y - offset;
|
||||||
|
|
||||||
m_lines.push_back(line);
|
m_lines.push_back(line);
|
||||||
}
|
}
|
||||||
|
@ -495,21 +495,21 @@ void Gfx::CWater::Create(Gfx::WaterType type1, Gfx::WaterType type2, const std::
|
||||||
if (m_terrain == nullptr)
|
if (m_terrain == nullptr)
|
||||||
m_terrain = static_cast<CTerrain*>(m_iMan->SearchInstance(CLASS_TERRAIN));
|
m_terrain = static_cast<CTerrain*>(m_iMan->SearchInstance(CLASS_TERRAIN));
|
||||||
|
|
||||||
m_brick = m_terrain->GetBrick()*m_terrain->GetMosaic();
|
m_brickCount = m_terrain->GetBrickCount()*m_terrain->GetMosaicCount();
|
||||||
m_size = m_terrain->GetSize();
|
m_brickSize = m_terrain->GetBrickSize();
|
||||||
|
|
||||||
m_brick /= m_subdiv;
|
m_brickCount /= m_subdiv;
|
||||||
m_size *= m_subdiv;
|
m_brickSize *= m_subdiv;
|
||||||
|
|
||||||
if (m_type[0] == WATER_NULL)
|
if (m_type[0] == WATER_NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_lines.clear();
|
m_lines.clear();
|
||||||
|
|
||||||
for (int y = 0; y < m_brick; y++)
|
for (int y = 0; y < m_brickCount; y++)
|
||||||
{
|
{
|
||||||
int len = 0;
|
int len = 0;
|
||||||
for (int x = 0; x < m_brick; x++)
|
for (int x = 0; x < m_brickCount; x++)
|
||||||
{
|
{
|
||||||
if (GetWater(x,y)) // water here?
|
if (GetWater(x,y)) // water here?
|
||||||
{
|
{
|
||||||
|
@ -530,7 +530,7 @@ void Gfx::CWater::Create(Gfx::WaterType type1, Gfx::WaterType type2, const std::
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (len != 0)
|
if (len != 0)
|
||||||
CreateLine(m_brick - len, y, len);
|
CreateLine(m_brickCount - len, y, len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -188,16 +188,16 @@ protected:
|
||||||
int m_subdiv;
|
int m_subdiv;
|
||||||
|
|
||||||
//! Number of brick*mosaics
|
//! Number of brick*mosaics
|
||||||
int m_brick;
|
int m_brickCount;
|
||||||
//! Size of a item in an brick
|
//! Size of a item in an brick
|
||||||
float m_size;
|
float m_brickSize;
|
||||||
|
|
||||||
std::vector<WaterLine> m_lines;
|
std::vector<WaterLine> m_lines;
|
||||||
std::vector<WaterVapor> m_vapors;
|
std::vector<WaterVapor> m_vapors;
|
||||||
|
|
||||||
bool m_draw;
|
bool m_draw;
|
||||||
bool m_lava;
|
bool m_lava;
|
||||||
long m_color;
|
Gfx::Color m_color;
|
||||||
};
|
};
|
||||||
|
|
||||||
}; // namespace Gfx
|
}; // namespace Gfx
|
||||||
|
|
Loading…
Reference in New Issue