From c2c1294ec99e3dae593bb31d2f331738d5be91d5 Mon Sep 17 00:00:00 2001 From: Piotr Dziwinski Date: Sat, 8 Sep 2012 23:44:14 +0200 Subject: CTerrain refactoring & fixes - refactored CTerrain code - fixed some minor bugs --- src/graphics/engine/camera.cpp | 28 +- src/graphics/engine/cloud.cpp | 29 +- src/graphics/engine/cloud.h | 4 +- src/graphics/engine/engine.cpp | 12 +- src/graphics/engine/terrain.cpp | 957 +++++++++++++++++++--------------------- src/graphics/engine/terrain.h | 286 ++++++++---- src/graphics/engine/water.cpp | 32 +- src/graphics/engine/water.h | 6 +- 8 files changed, 703 insertions(+), 651 deletions(-) (limited to 'src/graphics/engine') diff --git a/src/graphics/engine/camera.cpp b/src/graphics/engine/camera.cpp index 2db6398..f077fff 100644 --- a/src/graphics/engine/camera.cpp +++ b/src/graphics/engine/camera.cpp @@ -1272,14 +1272,14 @@ bool Gfx::CCamera::EventFrameFree(const Event &event) 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; Math::Vector pos = m_eyePt; - if (m_terrain->MoveOnFloor(pos, true)) + if (m_terrain->AdjustToFloor(pos, true)) { pos.y -= 2.0f; 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); - if (m_terrain->MoveOnFloor(lookatPt, true)) + if (m_terrain->AdjustToFloor(lookatPt, true)) lookatPt.y += m_heightLookat; SetViewTime(m_eyePt, lookatPt, event.rTime); @@ -1314,14 +1314,14 @@ bool Gfx::CCamera::EventFrameEdit(const Event &event) 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; Math::Vector pos = m_eyePt; - if (m_terrain->MoveOnFloor(pos, false)) + if (m_terrain->AdjustToFloor(pos, false)) { pos.y += 2.0f; 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 ); - if ( m_terrain->MoveOnFloor(lookatPt, true)) + if ( m_terrain->AdjustToFloor(lookatPt, true)) lookatPt.y += m_heightLookat; SetViewTime(m_eyePt, lookatPt, event.rTime); @@ -1483,7 +1483,7 @@ bool Gfx::CCamera::EventFrameBack(const Event &event) if ( (physics != NULL) && physics->GetLand() ) // ground? { 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) 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) 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; Math::Vector pos = m_eyePt; - if ( m_terrain->MoveOnFloor(pos, false) ) + if ( m_terrain->AdjustToFloor(pos, false) ) { pos.y += 2.0f; 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); - if (m_terrain->MoveOnFloor(lookatPt, true)) + if (m_terrain->AdjustToFloor(lookatPt, true)) lookatPt.y += m_heightLookat; 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) { Math::Vector pos = eye; - if (m_terrain->MoveOnFloor(pos)) + if (m_terrain->AdjustToFloor(pos)) { float dist = Math::DistanceProjected(lookat, pos); pos.y += 2.0f+dist*0.1f; diff --git a/src/graphics/engine/cloud.cpp b/src/graphics/engine/cloud.cpp index 6f6bc57..4c1d179 100644 --- a/src/graphics/engine/cloud.cpp +++ b/src/graphics/engine/cloud.cpp @@ -28,7 +28,8 @@ 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) @@ -99,10 +100,10 @@ void Gfx::CCloud::Draw() if (m_level == 0.0f) return; if (m_lines.empty()) return; - std::vector vertices((m_brick+2)*2, Gfx::VertexTex2()); + std::vector vertices((m_brickCount+2)*2, Gfx::VertexTex2()); 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->SetFocus(m_engine->GetFocus()); m_engine->UpdateMatProj(); // increases the depth of view @@ -132,7 +133,7 @@ void Gfx::CCloud::Draw() matrix.LoadIdentity(); 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 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.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.px2 = m_size*(line.x+line.len) - offset; - line.pz = m_size* line.y - offset; + line.px1 = m_brickSize* line.x - offset; + line.px2 = m_brickSize*(line.x+line.len) - offset; + line.pz = m_brickSize* line.y - offset; m_lines.push_back(line); } @@ -223,18 +224,18 @@ void Gfx::CCloud::Create(const std::string& fileName, m_wind = m_terrain->GetWind(); - m_brick = m_terrain->GetBrick()*m_terrain->GetMosaic()*DIMEXPAND; - m_size = m_terrain->GetSize(); + m_brickCount = m_terrain->GetBrickCount()*m_terrain->GetMosaicCount()*CLOUD_SIZE_EXPAND; + m_brickSize = m_terrain->GetBrickSize(); - m_brick /= m_subdiv*DIMEXPAND; - m_size *= m_subdiv*DIMEXPAND; + m_brickCount /= m_subdiv*CLOUD_SIZE_EXPAND; + m_brickSize *= m_subdiv*CLOUD_SIZE_EXPAND; if (m_level == 0.0f) return; m_lines.clear(); - for (int y = 0; y < m_brick; y++) - CreateLine(0, y, m_brick); + for (int y = 0; y < m_brickCount; y++) + CreateLine(0, y, m_brickCount); return; } diff --git a/src/graphics/engine/cloud.h b/src/graphics/engine/cloud.h index abfaf26..9822c24 100644 --- a/src/graphics/engine/cloud.h +++ b/src/graphics/engine/cloud.h @@ -126,9 +126,9 @@ protected: //! Wind speed Math::Vector m_wind; //! Brick mosaic - int m_brick; + int m_brickCount; //! Size of a brick element - float m_size; + float m_brickSize; std::vector m_lines; diff --git a/src/graphics/engine/engine.cpp b/src/graphics/engine/engine.cpp index 1359cf6..ed7b9c7 100644 --- a/src/graphics/engine/engine.cpp +++ b/src/graphics/engine/engine.cpp @@ -142,14 +142,14 @@ Gfx::CEngine::CEngine(CInstanceManager *iMan, CApplication *app) m_eyeDirH = 0.0f; m_eyeDirV = 0.0f; m_backgroundName = ""; // no background image - m_backgroundColorUp = 0; - m_backgroundColorDown = 0; - m_backgroundCloudUp = 0; - m_backgroundCloudDown = 0; + m_backgroundColorUp = Gfx::Color(); + m_backgroundColorDown = Gfx::Color(); + m_backgroundCloudUp = Gfx::Color(); + m_backgroundCloudDown = Gfx::Color(); m_backgroundFull = false; m_backgroundQuarter = false; m_overFront = true; - m_overColor = 0; + m_overColor = Gfx::Color(); m_overMode = ENG_RSTATE_TCOLOR_BLACK; m_highlightRank[0] = -1; // empty list m_highlightTime = 0.0f; @@ -2839,7 +2839,7 @@ void Gfx::CEngine::Render() m_statisticTriangle = 0; m_lastState = -1; - m_lastColor = 999; + m_lastColor = Gfx::Color(-1.0f); m_lastMaterial = Gfx::Material(); m_lightMan->UpdateLights(); diff --git a/src/graphics/engine/terrain.cpp b/src/graphics/engine/terrain.cpp index 971eed1..3e70719 100644 --- a/src/graphics/engine/terrain.cpp +++ b/src/graphics/engine/terrain.cpp @@ -44,111 +44,88 @@ Gfx::CTerrain::CTerrain(CInstanceManager* iMan) m_engine = static_cast( m_iMan->SearchInstance(CLASS_ENGINE) ); m_water = static_cast( m_iMan->SearchInstance(CLASS_WATER) ); - m_mosaic = 20; - m_brick = 1 << 4; - m_size = 10.0f; - m_vision = 200.0f; - m_scaleMapping = 0.01f; - m_scaleRelief = 1.0f; - m_subdivMapping = 1; - m_depth = 2; - m_levelMatMax = 0; - m_multiText = true; - m_levelText = false; - m_wind = Math::Vector(0.0f, 0.0f, 0.0f); - m_defHardness = 0.5f; - - m_levelMats.reserve(LEVEL_MAT_PREALLOCATE_COUNT); + m_mosaicCount = 20; + m_brickCount = 1 << 4; + m_brickSize = 10.0f; + m_vision = 200.0f; + m_textureScale = 0.01f; + m_scaleRelief = 1.0f; + m_textureSubdivCount = 1; + m_depth = 2; + m_maxMaterialID = 0; + m_wind = Math::Vector(0.0f, 0.0f, 0.0f); + m_defaultHardness = 0.5f; + m_useMaterials = false; + + m_materials.reserve(LEVEL_MAT_PREALLOCATE_COUNT); m_flyingLimits.reserve(FLYING_LIMIT_PREALLOCATE_COUNT); m_buildingLevels.reserve(BUILDING_LEVEL_PREALLOCATE_COUNT); + + FlushBuildingLevel(); + FlushFlyingLimit(); + FlushMaterials(); } Gfx::CTerrain::~CTerrain() { } -/** - The terrain is composed of mosaics, themselves composed of bricks. - Each brick is composed of two triangles. - mosaic: number of mosaics along the axes X and Z - brick: number of bricks (power of 2) - size: size of a brick along the axes X and Z - vision: vision before a change of resolution - scaleMapping: scale textures for mapping - -\verbatim - ^ z - | <---> brick*size - +---+---+---+---+ - | | | |_|_| mosaic = 4 - | | | | | | brick = 2 (brickP2=1) - +---+---+---+---+ - |\ \| | | | - |\ \| | | | - +---+---o---+---+---> x - | | | | | - | | | | | - +---+---+---+---+ - | | | | | The land is viewed from above here. - | | | | | - +---+---+---+---+ - <---------------> mosaic*brick*size -\endverbatim */ -bool Gfx::CTerrain::Generate(int mosaic, int brickPow2, float size, float vision, - int depth, float hardness) +bool Gfx::CTerrain::Generate(int mosaicCount, int brickCountPow2, float brickSize, + float vision, int depth, float hardness) { - m_mosaic = mosaic; - m_brick = 1 << brickPow2; - m_size = size; + m_mosaicCount = mosaicCount; + m_brickCount = 1 << brickCountPow2; + m_brickSize = brickSize; m_vision = vision; m_depth = depth; - m_defHardness = hardness; + m_defaultHardness = hardness; m_engine->SetTerrainVision(vision); - m_multiText = true; - m_levelText = false; - m_scaleMapping = 1.0f / (m_brick*m_size); - m_subdivMapping = 1; + m_textureScale = 1.0f / (m_brickCount*m_brickSize); + m_textureSubdivCount = 1; + + m_useMaterials = false; int dim = 0; - dim = (m_mosaic*m_brick+1)*(m_mosaic*m_brick+1); + dim = (m_mosaicCount*m_brickCount+1)*(m_mosaicCount*m_brickCount+1); std::vector(dim).swap(m_relief); - dim = m_mosaic*m_subdivMapping*m_mosaic*m_subdivMapping; - std::vector(dim).swap(m_texture); + dim = m_mosaicCount*m_textureSubdivCount*m_mosaicCount*m_textureSubdivCount; + std::vector(dim).swap(m_textures); - dim = m_mosaic*m_mosaic; - std::vector(dim).swap(m_objRank); + dim = m_mosaicCount*m_mosaicCount; + std::vector(dim).swap(m_objRanks); return true; } -int Gfx::CTerrain::GetMosaic() +int Gfx::CTerrain::GetMosaicCount() { - return m_mosaic; + return m_mosaicCount; } -int Gfx::CTerrain::GetBrick() +int Gfx::CTerrain::GetBrickCount() { - return m_brick; + return m_brickCount; } -float Gfx::CTerrain::GetSize() +float Gfx::CTerrain::GetBrickSize() { - return m_size; + return m_brickSize; } -float Gfx::CTerrain::GetScaleRelief() +float Gfx::CTerrain::GetReliefScale() { return m_scaleRelief; } bool Gfx::CTerrain::InitTextures(const std::string& baseName, int* table, int dx, int dy) { - m_levelText = false; + m_useMaterials = false; + m_texBaseName = baseName; size_t pos = baseName.find('.'); if (pos == baseName.npos) @@ -161,69 +138,60 @@ bool Gfx::CTerrain::InitTextures(const std::string& baseName, int* table, int dx m_texBaseExt = m_texBaseName.substr(pos); } - for (int y = 0; y < m_mosaic*m_subdivMapping; y++) + for (int y = 0; y < m_mosaicCount*m_textureSubdivCount; y++) { - for (int x = 0; x < m_mosaic*m_subdivMapping; x++) + for (int x = 0; x < m_mosaicCount*m_textureSubdivCount; x++) { - m_texture[x+y*m_mosaic] = table[(x%dx)+(y%dy)*dx]; + m_textures[x+y*m_mosaicCount] = table[(x%dx)+(y%dy)*dx]; } } return true; } -void Gfx::CTerrain::LevelFlush() +void Gfx::CTerrain::FlushMaterials() { - m_levelMats.clear(); - m_levelMatMax = 0; - m_levelID = 1000; - LevelCloseTable(); + m_materials.clear(); + m_maxMaterialID = 0; + m_materialAutoID = 1000; + FlushMaterialPoints(); } -void Gfx::CTerrain::LevelMaterial(int id, const std::string& baseName, float u, float v, - int up, int right, int down, int left, - float hardness) +void Gfx::CTerrain::AddMaterial(int id, const std::string& texName, const Math::Point &uv, + int up, int right, int down, int left, + float hardness) { - LevelOpenTable(); + InitMaterialPoints(); if (id == 0) - id = m_levelID++; // puts an ID internal standard + id = m_materialAutoID++; Gfx::TerrainMaterial tm; - tm.texName = baseName; + tm.texName = texName; tm.id = id; - tm.u = u; - tm.v = v; + tm.uv = uv; tm.mat[0] = up; tm.mat[1] = right; tm.mat[2] = down; tm.mat[3] = left; tm.hardness = hardness; - m_levelMats.push_back(tm); + m_materials.push_back(tm); - if (m_levelMatMax < up+1 ) m_levelMatMax = up+1; - if (m_levelMatMax < right+1) m_levelMatMax = right+1; - if (m_levelMatMax < down+1 ) m_levelMatMax = down+1; - if (m_levelMatMax < left+1 ) m_levelMatMax = left+1; + if (m_maxMaterialID < up+1 ) m_maxMaterialID = up+1; + if (m_maxMaterialID < right+1) m_maxMaterialID = right+1; + if (m_maxMaterialID < down+1 ) m_maxMaterialID = down+1; + if (m_maxMaterialID < left+1 ) m_maxMaterialID = left+1; - m_levelText = true; - m_subdivMapping = 4; + m_useMaterials = true; + m_textureSubdivCount = 4; } /** - The size of the image must be dimension dx and dy with dx=dy=(mosaic*brick)+1. - The image must be 24 bits/pixel - - Converts coordinated image (x;y) -> world (x;-;z) : - Wx = 5*Ix-400 - Wz = -(5*Iy-400) - - Converts coordinated world (x;-;z) -> image (x;y) : - Ix = (400+Wx)/5 - Iy = (400-Wz)/5 */ -bool Gfx::CTerrain::ResFromPNG(const std::string& fileName) + * The image must be 24 bits/pixel and grayscale and dx x dy in size + * with dx = dy = (mosaic*brick)+1 */ +bool Gfx::CTerrain::LoadResources(const std::string& fileName) { CImage img; if (! img.Load(CApplication::GetInstance().GetDataFilePath(m_engine->GetTextureDir(), fileName))) @@ -231,7 +199,7 @@ bool Gfx::CTerrain::ResFromPNG(const std::string& fileName) ImageData *data = img.GetData(); - int size = (m_mosaic*m_brick)+1; + int size = (m_mosaicCount*m_brickCount)+1; m_resources.clear(); @@ -257,14 +225,14 @@ Gfx::TerrainRes Gfx::CTerrain::GetResource(const Math::Vector &p) if (m_resources.empty()) return Gfx::TR_NULL; - int x = static_cast((p.x + (m_mosaic*m_brick*m_size)/2.0f)/m_size); - int y = static_cast((p.z + (m_mosaic*m_brick*m_size)/2.0f)/m_size); + int x = static_cast((p.x + (m_mosaicCount*m_brickCount*m_brickSize)/2.0f)/m_brickSize); + int y = static_cast((p.z + (m_mosaicCount*m_brickCount*m_brickSize)/2.0f)/m_brickSize); - if ( x < 0 || x > m_mosaic*m_brick || - y < 0 || y > m_mosaic*m_brick ) + if ( x < 0 || x > m_mosaicCount*m_brickCount || + y < 0 || y > m_mosaicCount*m_brickCount ) return Gfx::TR_NULL; - int size = (m_mosaic*m_brick)+1; + int size = (m_mosaicCount*m_brickCount)+1; int resR = m_resources[3*x+3*size*(size-y-1)]; int resG = m_resources[3*x+3*size*(size-y-1)+1]; @@ -289,20 +257,10 @@ void Gfx::CTerrain::FlushRelief() } /** - The size of the image must be dimension dx and dy with dx=dy=(mosaic*brick)+1. - The image must be 24 bits/pixel, but gray scale: - white = ground (y=0) - black = mountain (y=255*scaleRelief) - - Converts coordinated image(x;y) -> world (x;-;z) : - Wx = 5*Ix-400 - Wz = -(5*Iy-400) - - Converts coordinated world (x;-;z) -> image (x;y) : - Ix = (400+Wx)/5 - Iy = (400-Wz)/5 */ -bool Gfx::CTerrain::ReliefFromPNG(const std::string &fileName, float scaleRelief, - bool adjustBorder) + * The image must be 24 bits/pixel and dx x dy in size + * with dx = dy = (mosaic*brick)+1 */ +bool Gfx::CTerrain::LoadRelief(const std::string &fileName, float scaleRelief, + bool adjustBorder) { m_scaleRelief = scaleRelief; @@ -312,7 +270,7 @@ bool Gfx::CTerrain::ReliefFromPNG(const std::string &fileName, float scaleRelief ImageData *data = img.GetData(); - int size = (m_mosaic*m_brick)+1; + int size = (m_mosaicCount*m_brickCount)+1; if ( (data->surface->w != size) || (data->surface->h != size) || (data->surface->format->BytesPerPixel != 3) ) @@ -346,13 +304,13 @@ bool Gfx::CTerrain::ReliefFromPNG(const std::string &fileName, float scaleRelief return true; } -bool Gfx::CTerrain::ReliefAddDot(Math::Vector pos, float scaleRelief) +bool Gfx::CTerrain::AddReliefPoint(Math::Vector pos, float scaleRelief) { - float dim = (m_mosaic*m_brick*m_size)/2.0f; - int size = (m_mosaic*m_brick)+1; + float dim = (m_mosaicCount*m_brickCount*m_brickSize)/2.0f; + int size = (m_mosaicCount*m_brickCount)+1; - pos.x = (pos.x+dim)/m_size; - pos.z = (pos.z+dim)/m_size; + pos.x = (pos.x+dim)/m_brickSize; + pos.z = (pos.z+dim)/m_brickSize; int x = static_cast(pos.x); int y = static_cast(pos.z); @@ -366,33 +324,20 @@ bool Gfx::CTerrain::ReliefAddDot(Math::Vector pos, float scaleRelief) return true; } -void Gfx::CTerrain::LimitPos(Math::Vector &pos) -{ -// TODO: #if _TEEN -// dim = (m_mosaic*m_brick*m_size)/2.0f*0.98f; - - float dim = (m_mosaic*m_brick*m_size)/2.0f*0.92f; - - if (pos.x < -dim) pos.x = -dim; - if (pos.x > dim) pos.x = dim; - if (pos.z < -dim) pos.z = -dim; - if (pos.z > dim) pos.z = dim; -} - void Gfx::CTerrain::AdjustRelief() { - if (m_depth == 1) return; + if (m_depth == 1) return; - int ii = m_mosaic*m_brick+1; + int ii = m_mosaicCount*m_brickCount+1; int b = 1 << (m_depth-1); - for (int y = 0; y < m_mosaic*m_brick; y += b) + for (int y = 0; y < m_mosaicCount*m_brickCount; y += b) { - for (int x = 0; x < m_mosaic*m_brick; x += b) + for (int x = 0; x < m_mosaicCount*m_brickCount; x += b) { int xx = 0; int yy = 0; - if ((y+yy)%m_brick == 0) + if ((y+yy)%m_brickCount == 0) { float level1 = m_relief[(x+0)+(y+yy)*ii]; float level2 = m_relief[(x+b)+(y+yy)*ii]; @@ -403,7 +348,7 @@ void Gfx::CTerrain::AdjustRelief() } yy = b; - if ((y+yy)%m_brick == 0) + if ((y+yy)%m_brickCount == 0) { float level1 = m_relief[(x+0)+(y+yy)*ii]; float level2 = m_relief[(x+b)+(y+yy)*ii]; @@ -414,7 +359,7 @@ void Gfx::CTerrain::AdjustRelief() } xx = 0; - if ((x+xx)%m_brick == 0) + if ((x+xx)%m_brickCount == 0) { float level1 = m_relief[(x+xx)+(y+0)*ii]; float level2 = m_relief[(x+xx)+(y+b)*ii]; @@ -425,7 +370,7 @@ void Gfx::CTerrain::AdjustRelief() } xx = b; - if ((x+xx)%m_brick == 0) + if ((x+xx)%m_brickCount == 0) { float level1 = m_relief[(x+xx)+(y+0)*ii]; float level2 = m_relief[(x+xx)+(y+b)*ii]; @@ -441,14 +386,14 @@ void Gfx::CTerrain::AdjustRelief() Math::Vector Gfx::CTerrain::GetVector(int x, int y) { Math::Vector p; - p.x = x*m_size - (m_mosaic*m_brick*m_size)/2; - p.z = y*m_size - (m_mosaic*m_brick*m_size)/2; + p.x = x*m_brickSize - (m_mosaicCount*m_brickCount*m_brickSize) / 2.0; + p.z = y*m_brickSize - (m_mosaicCount*m_brickCount*m_brickSize) / 2.0; - if ( !m_relief.empty() && - x >= 0 && x <= m_mosaic*m_brick && - y >= 0 && y <= m_mosaic*m_brick ) + if ( !m_relief.empty() && + x >= 0 && x <= m_mosaicCount*m_brickCount && + y >= 0 && y <= m_mosaicCount*m_brickCount ) { - p.y = m_relief[x+y*(m_mosaic*m_brick+1)]; + p.y = m_relief[x+y*(m_mosaicCount*m_brickCount+1)]; } else { @@ -458,7 +403,7 @@ Math::Vector Gfx::CTerrain::GetVector(int x, int y) return p; } -/** Calculates a normal soft, taking into account the six adjacent triangles: +/** Calculates an averaged normal, taking into account the six adjacent triangles: \verbatim ^ y @@ -487,16 +432,16 @@ Gfx::VertexTex2 Gfx::CTerrain::GetVertex(int x, int y, int step) Math::Vector s(0.0f, 0.0f, 0.0f); - if (x-step >= 0 && y+step <= m_mosaic*m_brick+1) + if (x-step >= 0 && y+step <= m_mosaicCount*m_brickCount+1) { s += Math::NormalToPlane(b,a,o); s += Math::NormalToPlane(c,b,o); } - if (x+step <= m_mosaic*m_brick+1 && y+step <= m_mosaic*m_brick+1) + if (x+step <= m_mosaicCount*m_brickCount+1 && y+step <= m_mosaicCount*m_brickCount+1) s += Math::NormalToPlane(d,c,o); - if (x+step <= m_mosaic*m_brick+1 && y-step >= 0) + if (x+step <= m_mosaicCount*m_brickCount+1 && y-step >= 0) { s += Math::NormalToPlane(e,d,o); s += Math::NormalToPlane(f,e,o); @@ -508,19 +453,11 @@ Gfx::VertexTex2 Gfx::CTerrain::GetVertex(int x, int y, int step) s = Normalize(s); v.normal = s; - if (m_multiText) - { - int brick = m_brick/m_subdivMapping; - Math::Vector oo = GetVector((x/brick)*brick, (y/brick)*brick); - o = GetVector(x, y); - v.texCoord.x = (o.x-oo.x)*m_scaleMapping*m_subdivMapping; - v.texCoord.y = 1.0f - (o.z-oo.z)*m_scaleMapping*m_subdivMapping; - } - else - { - v.texCoord.x = o.x*m_scaleMapping; - v.texCoord.y = o.z*m_scaleMapping; - } + int brick = m_brickCount/m_textureSubdivCount; + Math::Vector oo = GetVector((x/brick)*brick, (y/brick)*brick); + o = GetVector(x, y); + v.texCoord.x = (o.x-oo.x)*m_textureScale*m_textureSubdivCount; + v.texCoord.y = 1.0f - (o.z-oo.z)*m_textureScale*m_textureSubdivCount; return v; } @@ -545,7 +482,7 @@ bool Gfx::CTerrain::CreateMosaic(int ox, int oy, int step, int objRank, if ( step == 1 && m_engine->GetGroundSpot() ) { - int i = (ox/5) + (oy/5)*(m_mosaic/5); + int i = (ox/5) + (oy/5)*(m_mosaicCount/5); std::stringstream s; s << "shadow"; s.width(2); @@ -555,9 +492,9 @@ bool Gfx::CTerrain::CreateMosaic(int ox, int oy, int step, int objRank, texName2 = s.str(); } - int brick = m_brick/m_subdivMapping; + int brick = m_brickCount/m_textureSubdivCount; - Gfx::VertexTex2 o = GetVertex(ox*m_brick+m_brick/2, oy*m_brick+m_brick/2, step); + Gfx::VertexTex2 o = GetVertex(ox*m_brickCount+m_brickCount/2, oy*m_brickCount+m_brickCount/2, step); int total = ((brick/step)+1)*2; float pixel = 1.0f/256.0f; // 1 pixel cover (*) @@ -565,24 +502,24 @@ bool Gfx::CTerrain::CreateMosaic(int ox, int oy, int step, int objRank, Math::Point uv; - for (int my = 0; my < m_subdivMapping; my++) + for (int my = 0; my < m_textureSubdivCount; my++) { - for (int mx = 0; mx < m_subdivMapping; mx++) + for (int mx = 0; mx < m_textureSubdivCount; mx++) { - if (m_levelText) + if (m_useMaterials) { - int xx = ox*m_brick + mx*(m_brick/m_subdivMapping); - int yy = oy*m_brick + my*(m_brick/m_subdivMapping); - LevelTextureName(xx, yy, texName1, uv); + int xx = ox*m_brickCount + mx*(m_brickCount/m_textureSubdivCount); + int yy = oy*m_brickCount + my*(m_brickCount/m_textureSubdivCount); + GetTexture(xx, yy, texName1, uv); } else { - int i = (ox*m_subdivMapping+mx)+(oy*m_subdivMapping+my)*m_mosaic; + int i = (ox*m_textureSubdivCount+mx)+(oy*m_textureSubdivCount+my)*m_mosaicCount; std::stringstream s; s << m_texBaseName; s.width(3); s.fill('0'); - s << m_texture[i]; + s << m_textures[i]; s << m_texBaseExt; texName1 = s.str(); } @@ -603,36 +540,33 @@ bool Gfx::CTerrain::CreateMosaic(int ox, int oy, int step, int objRank, for (int x = 0; x <= brick; x += step) { - Gfx::VertexTex2 p1 = GetVertex(ox*m_brick+mx*brick+x, oy*m_brick+my*brick+y+0 , step); - Gfx::VertexTex2 p2 = GetVertex(ox*m_brick+mx*brick+x, oy*m_brick+my*brick+y+step, step); + Gfx::VertexTex2 p1 = GetVertex(ox*m_brickCount+mx*brick+x, oy*m_brickCount+my*brick+y+0 , step); + Gfx::VertexTex2 p2 = GetVertex(ox*m_brickCount+mx*brick+x, oy*m_brickCount+my*brick+y+step, step); p1.coord.x -= o.coord.x; p1.coord.z -= o.coord.z; p2.coord.x -= o.coord.x; p2.coord.z -= o.coord.z; - if (m_multiText) + if (x == 0) { - if (x == 0) - { - p1.texCoord.x = 0.0f+(0.5f/256.0f); - p2.texCoord.x = 0.0f+(0.5f/256.0f); - } - if (x == brick) - { - p1.texCoord.x = 1.0f-(0.5f/256.0f); - p2.texCoord.x = 1.0f-(0.5f/256.0f); - } - if (y == 0) - p1.texCoord.y = 1.0f-(0.5f/256.0f); - - if (y == brick - step) - p2.texCoord.y = 0.0f+(0.5f/256.0f); + p1.texCoord.x = 0.0f+(0.5f/256.0f); + p2.texCoord.x = 0.0f+(0.5f/256.0f); + } + if (x == brick) + { + p1.texCoord.x = 1.0f-(0.5f/256.0f); + p2.texCoord.x = 1.0f-(0.5f/256.0f); } + if (y == 0) + p1.texCoord.y = 1.0f-(0.5f/256.0f); + + if (y == brick - step) + p2.texCoord.y = 0.0f+(0.5f/256.0f); - if (m_levelText) + if (m_useMaterials) { - p1.texCoord.x /= m_subdivMapping; // 0..1 -> 0..0.25 - p1.texCoord.y /= m_subdivMapping; - p2.texCoord.x /= m_subdivMapping; - p2.texCoord.y /= m_subdivMapping; + p1.texCoord.x /= m_textureSubdivCount; // 0..1 -> 0..0.25 + p1.texCoord.y /= m_textureSubdivCount; + p2.texCoord.x /= m_textureSubdivCount; + p2.texCoord.y /= m_textureSubdivCount; if (x == 0) { @@ -641,11 +575,11 @@ bool Gfx::CTerrain::CreateMosaic(int ox, int oy, int step, int objRank, } if (x == brick) { - p1.texCoord.x = (1.0f/m_subdivMapping)-dp; - p2.texCoord.x = (1.0f/m_subdivMapping)-dp; + p1.texCoord.x = (1.0f/m_textureSubdivCount)-dp; + p2.texCoord.x = (1.0f/m_textureSubdivCount)-dp; } if (y == 0) - p1.texCoord.y = (1.0f/m_subdivMapping)-dp; + p1.texCoord.y = (1.0f/m_textureSubdivCount)-dp; if (y == brick - step) p2.texCoord.y = 0.0f+dp; @@ -656,12 +590,12 @@ bool Gfx::CTerrain::CreateMosaic(int ox, int oy, int step, int objRank, p2.texCoord.y += uv.y; } - int xx = mx*(m_brick/m_subdivMapping) + x; - int yy = my*(m_brick/m_subdivMapping) + y; - p1.texCoord2.x = (static_cast(ox%5)*m_brick+xx+0.0f)/(m_brick*5); - p1.texCoord2.y = (static_cast(oy%5)*m_brick+yy+0.0f)/(m_brick*5); - p2.texCoord2.x = (static_cast(ox%5)*m_brick+xx+0.0f)/(m_brick*5); - p2.texCoord2.y = (static_cast(oy%5)*m_brick+yy+1.0f)/(m_brick*5); + int xx = mx*(m_brickCount/m_textureSubdivCount) + x; + int yy = my*(m_brickCount/m_textureSubdivCount) + y; + p1.texCoord2.x = (static_cast(ox%5)*m_brickCount+xx+0.0f)/(m_brickCount*5); + p1.texCoord2.y = (static_cast(oy%5)*m_brickCount+yy+0.0f)/(m_brickCount*5); + p2.texCoord2.x = (static_cast(ox%5)*m_brickCount+xx+0.0f)/(m_brickCount*5); + p2.texCoord2.y = (static_cast(oy%5)*m_brickCount+yy+1.0f)/(m_brickCount*5); // Correction for 1 pixel cover // There is 1 pixel cover around each of the 16 surfaces: @@ -699,40 +633,38 @@ bool Gfx::CTerrain::CreateMosaic(int ox, int oy, int step, int objRank, return true; } -Gfx::TerrainMaterial* Gfx::CTerrain::LevelSearchMat(int id) +Gfx::TerrainMaterial* Gfx::CTerrain::FindMaterial(int id) { - for (int i = 0; i < static_cast( m_levelMats.size() ); i++) + for (int i = 0; i < static_cast( m_materials.size() ); i++) { - if (id == m_levelMats[i].id) - return &m_levelMats[i]; + if (id == m_materials[i].id) + return &m_materials[i]; } return nullptr; } -void Gfx::CTerrain::LevelTextureName(int x, int y, std::string& name, Math::Point &uv) +void Gfx::CTerrain::GetTexture(int x, int y, std::string& name, Math::Point &uv) { - x /= m_brick/m_subdivMapping; - y /= m_brick/m_subdivMapping; + x /= m_brickCount/m_textureSubdivCount; + y /= m_brickCount/m_textureSubdivCount; - TerrainMaterial* tm = LevelSearchMat(m_levelDots[x+y*m_levelDotSize].id); + TerrainMaterial* tm = FindMaterial(m_materialPoints[x+y*m_materialPointCount].id); if (tm == nullptr) { name = "xxx.png"; - uv.x = 0.0f; - uv.y = 0.0f; + uv = Math::Point(0.0f, 0.0f); } else { name = tm->texName; - uv.x = tm->u; - uv.y = tm->v; + uv = tm->uv; } } -float Gfx::CTerrain::LevelGetHeight(int x, int y) +float Gfx::CTerrain::GetHeight(int x, int y) { - int size = (m_mosaic*m_brick+1); + int size = (m_mosaicCount*m_brickCount+1); if (x < 0 ) x = 0; if (x >= size) x = size-1; @@ -742,15 +674,15 @@ float Gfx::CTerrain::LevelGetHeight(int x, int y) return m_relief[x+y*size]; } -bool Gfx::CTerrain::LevelGetDot(int x, int y, float min, float max, float slope) +bool Gfx::CTerrain::CheckMaterialPoint(int x, int y, float min, float max, float slope) { - float hc = LevelGetHeight(x, y); + float hc = GetHeight(x, y); float h[4] = { - LevelGetHeight(x+0, y+1), - LevelGetHeight(x+1, y+0), - LevelGetHeight(x+0, y-1), - LevelGetHeight(x-1, y+0) + GetHeight(x+0, y+1), + GetHeight(x+1, y+0), + GetHeight(x+0, y-1), + GetHeight(x-1, y+0) }; if (hc < min || hc > max) @@ -782,25 +714,22 @@ bool Gfx::CTerrain::LevelGetDot(int x, int y, float min, float max, float slope) return false; } - -/** Returns the index within m_levelMats or -1 if there is not. - m_levelMats[i].id gives the identifier. */ -int Gfx::CTerrain::LevelTestMat(char *mat) +int Gfx::CTerrain::FindMaterialByNeighbors(char *mat) { - for (int i = 0; i < static_cast( m_levelMats.size() ); i++) + for (int i = 0; i < static_cast( m_materials.size() ); i++) { - if ( m_levelMats[i].mat[0] == mat[0] && - m_levelMats[i].mat[1] == mat[1] && - m_levelMats[i].mat[2] == mat[2] && - m_levelMats[i].mat[3] == mat[3] ) return i; + if ( m_materials[i].mat[0] == mat[0] && + m_materials[i].mat[1] == mat[1] && + m_materials[i].mat[2] == mat[2] && + m_materials[i].mat[3] == mat[3] ) return i; } return -1; } -void Gfx::CTerrain::LevelSetDot(int x, int y, int id, char *mat) +void Gfx::CTerrain::SetMaterialPoint(int x, int y, int id, char *mat) { - TerrainMaterial* tm = LevelSearchMat(id); + TerrainMaterial* tm = FindMaterial(id); if (tm == nullptr) return; if ( tm->mat[0] != mat[0] || @@ -808,310 +737,310 @@ void Gfx::CTerrain::LevelSetDot(int x, int y, int id, char *mat) tm->mat[2] != mat[2] || tm->mat[3] != mat[3] ) // id incompatible with mat? { - int ii = LevelTestMat(mat); + int ii = FindMaterialByNeighbors(mat); if (ii == -1) return; - id = m_levelMats[ii].id; // looking for a id compatible with mat + id = m_materials[ii].id; // looking for a id compatible with mat } // Changes the point - m_levelDots[x+y*m_levelDotSize].id = id; - m_levelDots[x+y*m_levelDotSize].mat[0] = mat[0]; - m_levelDots[x+y*m_levelDotSize].mat[1] = mat[1]; - m_levelDots[x+y*m_levelDotSize].mat[2] = mat[2]; - m_levelDots[x+y*m_levelDotSize].mat[3] = mat[3]; + m_materialPoints[x+y*m_materialPointCount].id = id; + m_materialPoints[x+y*m_materialPointCount].mat[0] = mat[0]; + m_materialPoints[x+y*m_materialPointCount].mat[1] = mat[1]; + m_materialPoints[x+y*m_materialPointCount].mat[2] = mat[2]; + m_materialPoints[x+y*m_materialPointCount].mat[3] = mat[3]; // Changes the lower neighbor - if ( (x+0) >= 0 && (x+0) < m_levelDotSize && - (y-1) >= 0 && (y-1) < m_levelDotSize ) + if ( (x+0) >= 0 && (x+0) < m_materialPointCount && + (y-1) >= 0 && (y-1) < m_materialPointCount ) { - int i = (x+0)+(y-1)*m_levelDotSize; - if (m_levelDots[i].mat[0] != mat[2]) + int i = (x+0)+(y-1)*m_materialPointCount; + if (m_materialPoints[i].mat[0] != mat[2]) { - m_levelDots[i].mat[0] = mat[2]; - int ii = LevelTestMat(m_levelDots[i].mat); + m_materialPoints[i].mat[0] = mat[2]; + int ii = FindMaterialByNeighbors(m_materialPoints[i].mat); if (ii != -1) - m_levelDots[i].id = m_levelMats[ii].id; + m_materialPoints[i].id = m_materials[ii].id; } } // Modifies the left neighbor - if ( (x-1) >= 0 && (x-1) < m_levelDotSize && - (y+0) >= 0 && (y+0) < m_levelDotSize ) + if ( (x-1) >= 0 && (x-1) < m_materialPointCount && + (y+0) >= 0 && (y+0) < m_materialPointCount ) { - int i = (x-1)+(y+0)*m_levelDotSize; - if (m_levelDots[i].mat[1] != mat[3]) + int i = (x-1)+(y+0)*m_materialPointCount; + if (m_materialPoints[i].mat[1] != mat[3]) { - m_levelDots[i].mat[1] = mat[3]; - int ii = LevelTestMat(m_levelDots[i].mat); + m_materialPoints[i].mat[1] = mat[3]; + int ii = FindMaterialByNeighbors(m_materialPoints[i].mat); if (ii != -1) - m_levelDots[i].id = m_levelMats[ii].id; + m_materialPoints[i].id = m_materials[ii].id; } } // Changes the upper neighbor - if ( (x+0) >= 0 && (x+0) < m_levelDotSize && - (y+1) >= 0 && (y+1) < m_levelDotSize ) + if ( (x+0) >= 0 && (x+0) < m_materialPointCount && + (y+1) >= 0 && (y+1) < m_materialPointCount ) { - int i = (x+0)+(y+1)*m_levelDotSize; - if (m_levelDots[i].mat[2] != mat[0]) + int i = (x+0)+(y+1)*m_materialPointCount; + if (m_materialPoints[i].mat[2] != mat[0]) { - m_levelDots[i].mat[2] = mat[0]; - int ii = LevelTestMat(m_levelDots[i].mat); + m_materialPoints[i].mat[2] = mat[0]; + int ii = FindMaterialByNeighbors(m_materialPoints[i].mat); if (ii != -1) - m_levelDots[i].id = m_levelMats[ii].id; + m_materialPoints[i].id = m_materials[ii].id; } } // Changes the right neighbor - if ( (x+1) >= 0 && (x+1) < m_levelDotSize && - (y+0) >= 0 && (y+0) < m_levelDotSize ) + if ( (x+1) >= 0 && (x+1) < m_materialPointCount && + (y+0) >= 0 && (y+0) < m_materialPointCount ) { - int i = (x+1)+(y+0)*m_levelDotSize; - if ( m_levelDots[i].mat[3] != mat[1] ) + int i = (x+1)+(y+0)*m_materialPointCount; + if ( m_materialPoints[i].mat[3] != mat[1] ) { - m_levelDots[i].mat[3] = mat[1]; - int ii = LevelTestMat(m_levelDots[i].mat); + m_materialPoints[i].mat[3] = mat[1]; + int ii = FindMaterialByNeighbors(m_materialPoints[i].mat); if (ii != -1) - m_levelDots[i].id = m_levelMats[ii].id; + m_materialPoints[i].id = m_materials[ii].id; } } } -bool Gfx::CTerrain::LevelIfDot(int x, int y, int id, char *mat) +bool Gfx::CTerrain::CondChangeMaterialPoint(int x, int y, int id, char *mat) { char test[4]; // Compatible with lower neighbor? - if ( x+0 >= 0 && x+0 < m_levelDotSize && - y-1 >= 0 && y-1 < m_levelDotSize ) + if ( x+0 >= 0 && x+0 < m_materialPointCount && + y-1 >= 0 && y-1 < m_materialPointCount ) { test[0] = mat[2]; - test[1] = m_levelDots[(x+0)+(y-1)*m_levelDotSize].mat[1]; - test[2] = m_levelDots[(x+0)+(y-1)*m_levelDotSize].mat[2]; - test[3] = m_levelDots[(x+0)+(y-1)*m_levelDotSize].mat[3]; + test[1] = m_materialPoints[(x+0)+(y-1)*m_materialPointCount].mat[1]; + test[2] = m_materialPoints[(x+0)+(y-1)*m_materialPointCount].mat[2]; + test[3] = m_materialPoints[(x+0)+(y-1)*m_materialPointCount].mat[3]; - if ( LevelTestMat(test) == -1 ) return false; + if ( FindMaterialByNeighbors(test) == -1 ) return false; } // Compatible with left neighbor? - if ( x-1 >= 0 && x-1 < m_levelDotSize && - y+0 >= 0 && y+0 < m_levelDotSize ) + if ( x-1 >= 0 && x-1 < m_materialPointCount && + y+0 >= 0 && y+0 < m_materialPointCount ) { - test[0] = m_levelDots[(x-1)+(y+0)*m_levelDotSize].mat[0]; + test[0] = m_materialPoints[(x-1)+(y+0)*m_materialPointCount].mat[0]; test[1] = mat[3]; - test[2] = m_levelDots[(x-1)+(y+0)*m_levelDotSize].mat[2]; - test[3] = m_levelDots[(x-1)+(y+0)*m_levelDotSize].mat[3]; + test[2] = m_materialPoints[(x-1)+(y+0)*m_materialPointCount].mat[2]; + test[3] = m_materialPoints[(x-1)+(y+0)*m_materialPointCount].mat[3]; - if ( LevelTestMat(test) == -1 ) return false; + if ( FindMaterialByNeighbors(test) == -1 ) return false; } // Compatible with upper neighbor? - if ( x+0 >= 0 && x+0 < m_levelDotSize && - y+1 >= 0 && y+1 < m_levelDotSize ) + if ( x+0 >= 0 && x+0 < m_materialPointCount && + y+1 >= 0 && y+1 < m_materialPointCount ) { - test[0] = m_levelDots[(x+0)+(y+1)*m_levelDotSize].mat[0]; - test[1] = m_levelDots[(x+0)+(y+1)*m_levelDotSize].mat[1]; + test[0] = m_materialPoints[(x+0)+(y+1)*m_materialPointCount].mat[0]; + test[1] = m_materialPoints[(x+0)+(y+1)*m_materialPointCount].mat[1]; test[2] = mat[0]; - test[3] = m_levelDots[(x+0)+(y+1)*m_levelDotSize].mat[3]; + test[3] = m_materialPoints[(x+0)+(y+1)*m_materialPointCount].mat[3]; - if ( LevelTestMat(test) == -1 ) return false; + if ( FindMaterialByNeighbors(test) == -1 ) return false; } // Compatible with right neighbor? - if ( x+1 >= 0 && x+1 < m_levelDotSize && - y+0 >= 0 && y+0 < m_levelDotSize ) + if ( x+1 >= 0 && x+1 < m_materialPointCount && + y+0 >= 0 && y+0 < m_materialPointCount ) { - test[0] = m_levelDots[(x+1)+(y+0)*m_levelDotSize].mat[0]; - test[1] = m_levelDots[(x+1)+(y+0)*m_levelDotSize].mat[1]; - test[2] = m_levelDots[(x+1)+(y+0)*m_levelDotSize].mat[2]; + test[0] = m_materialPoints[(x+1)+(y+0)*m_materialPointCount].mat[0]; + test[1] = m_materialPoints[(x+1)+(y+0)*m_materialPointCount].mat[1]; + test[2] = m_materialPoints[(x+1)+(y+0)*m_materialPointCount].mat[2]; test[3] = mat[1]; - if ( LevelTestMat(test) == -1 ) return false; + if ( FindMaterialByNeighbors(test) == -1 ) return false; } - LevelSetDot(x, y, id, mat); // puts the point + SetMaterialPoint(x, y, id, mat); // puts the point return true; } -bool Gfx::CTerrain::LevelPutDot(int x, int y, int id) +bool Gfx::CTerrain::ChangeMaterialPoint(int x, int y, int id) { char mat[4]; - x /= m_brick/m_subdivMapping; - y /= m_brick/m_subdivMapping; + x /= m_brickCount/m_textureSubdivCount; + y /= m_brickCount/m_textureSubdivCount; - if ( x < 0 || x >= m_levelDotSize || - y < 0 || y >= m_levelDotSize ) return false; + if ( x < 0 || x >= m_materialPointCount || + y < 0 || y >= m_materialPointCount ) return false; - TerrainMaterial* tm = LevelSearchMat(id); + TerrainMaterial* tm = FindMaterial(id); if (tm == nullptr) return false; // Tries without changing neighbors. - if ( LevelIfDot(x, y, id, tm->mat) ) return true; + if ( CondChangeMaterialPoint(x, y, id, tm->mat) ) return true; // Tries changing a single neighbor (4x). - for (int up = 0; up < m_levelMatMax; up++) + for (int up = 0; up < m_maxMaterialID; up++) { mat[0] = up; mat[1] = tm->mat[1]; mat[2] = tm->mat[2]; mat[3] = tm->mat[3]; - if (LevelIfDot(x, y, id, mat)) return true; + if (CondChangeMaterialPoint(x, y, id, mat)) return true; } - for (int right = 0; right < m_levelMatMax; right++) + for (int right = 0; right < m_maxMaterialID; right++) { mat[0] = tm->mat[0]; mat[1] = right; mat[2] = tm->mat[2]; mat[3] = tm->mat[3]; - if (LevelIfDot(x, y, id, mat)) return true; + if (CondChangeMaterialPoint(x, y, id, mat)) return true; } - for (int down = 0; down < m_levelMatMax; down++) + for (int down = 0; down < m_maxMaterialID; down++) { mat[0] = tm->mat[0]; mat[1] = tm->mat[1]; mat[2] = down; mat[3] = tm->mat[3]; - if (LevelIfDot(x, y, id, mat)) return true; + if (CondChangeMaterialPoint(x, y, id, mat)) return true; } - for (int left = 0; left < m_levelMatMax; left++) + for (int left = 0; left < m_maxMaterialID; left++) { mat[0] = tm->mat[0]; mat[1] = tm->mat[1]; mat[2] = tm->mat[2]; mat[3] = left; - if (LevelIfDot(x, y, id, mat)) return true; + if (CondChangeMaterialPoint(x, y, id, mat)) return true; } // Tries changing two neighbors (6x). - for (int up = 0; up < m_levelMatMax; up++) + for (int up = 0; up < m_maxMaterialID; up++) { - for (int down = 0; down < m_levelMatMax; down++) + for (int down = 0; down < m_maxMaterialID; down++) { mat[0] = up; mat[1] = tm->mat[1]; mat[2] = down; mat[3] = tm->mat[3]; - if (LevelIfDot(x, y, id, mat)) return true; + if (CondChangeMaterialPoint(x, y, id, mat)) return true; } } - for (int right = 0; right < m_levelMatMax; right++) + for (int right = 0; right < m_maxMaterialID; right++) { - for (int left = 0; left < m_levelMatMax; left++) + for (int left = 0; left < m_maxMaterialID; left++) { mat[0] = tm->mat[0]; mat[1] = right; mat[2] = tm->mat[2]; mat[3] = left; - if (LevelIfDot(x, y, id, mat)) return true; + if (CondChangeMaterialPoint(x, y, id, mat)) return true; } } - for (int up = 0; up < m_levelMatMax; up++) + for (int up = 0; up < m_maxMaterialID; up++) { - for (int right = 0; right < m_levelMatMax; right++) + for (int right = 0; right < m_maxMaterialID; right++) { mat[0] = up; mat[1] = right; mat[2] = tm->mat[2]; mat[3] = tm->mat[3]; - if (LevelIfDot(x, y, id, mat)) return true; + if (CondChangeMaterialPoint(x, y, id, mat)) return true; } } - for (int right = 0; right < m_levelMatMax; right++) + for (int right = 0; right < m_maxMaterialID; right++) { - for (int down = 0; down < m_levelMatMax; down++) + for (int down = 0; down < m_maxMaterialID; down++) { mat[0] = tm->mat[0]; mat[1] = right; mat[2] = down; mat[3] = tm->mat[3]; - if (LevelIfDot(x, y, id, mat)) return true; + if (CondChangeMaterialPoint(x, y, id, mat)) return true; } } - for (int down = 0; down < m_levelMatMax; down++) + for (int down = 0; down < m_maxMaterialID; down++) { - for (int left = 0; left < m_levelMatMax; left++) + for (int left = 0; left < m_maxMaterialID; left++) { mat[0] = tm->mat[0]; mat[1] = tm->mat[1]; mat[2] = down; mat[3] = left; - if (LevelIfDot(x, y, id, mat)) return true; + if (CondChangeMaterialPoint(x, y, id, mat)) return true; } } - for (int up = 0; up < m_levelMatMax; up++) + for (int up = 0; up < m_maxMaterialID; up++) { - for (int left = 0; left < m_levelMatMax; left++) + for (int left = 0; left < m_maxMaterialID; left++) { mat[0] = up; mat[1] = tm->mat[1]; mat[2] = tm->mat[2]; mat[3] = left; - if (LevelIfDot(x, y, id, mat)) return true; + if (CondChangeMaterialPoint(x, y, id, mat)) return true; } } // Tries changing all the neighbors. - for (int up = 0; up < m_levelMatMax; up++) + for (int up = 0; up < m_maxMaterialID; up++) { - for (int right = 0; right < m_levelMatMax; right++) + for (int right = 0; right < m_maxMaterialID; right++) { - for (int down = 0; down < m_levelMatMax; down++) + for (int down = 0; down < m_maxMaterialID; down++) { - for (int left = 0; left < m_levelMatMax; left++) + for (int left = 0; left < m_maxMaterialID; left++) { mat[0] = up; mat[1] = right; mat[2] = down; mat[3] = left; - if (LevelIfDot(x, y, id, mat)) return true; + if (CondChangeMaterialPoint(x, y, id, mat)) return true; } } } } - GetLogger()->Error("LevelPutDot error\n"); + GetLogger()->Error("AddMaterialPoint error\n"); return false; } -bool Gfx::CTerrain::LevelInit(int id) +bool Gfx::CTerrain::InitMaterials(int id) { - TerrainMaterial* tm = LevelSearchMat(id); + TerrainMaterial* tm = FindMaterial(id); if (tm == nullptr) return false; - for (int i = 0; i < m_levelDotSize*m_levelDotSize; i++) + for (int i = 0; i < m_materialPointCount*m_materialPointCount; i++) { - m_levelDots[i].id = id; + m_materialPoints[i].id = id; for (int j = 0; j < 4; j++) - m_levelDots[i].mat[j] = tm->mat[j]; + m_materialPoints[i].mat[j] = tm->mat[j]; } return true; } -bool Gfx::CTerrain::LevelGenerate(int *id, float min, float max, - float slope, float freq, - Math::Vector center, float radius) +bool Gfx::CTerrain::GenerateMaterials(int *id, float min, float max, + float slope, float freq, + Math::Vector center, float radius) { static char random[100] = { @@ -1130,40 +1059,40 @@ bool Gfx::CTerrain::LevelGenerate(int *id, float min, float max, TerrainMaterial* tm = nullptr; int i = 0; - while ( id[i] != 0 ) + while (id[i] != 0) { - tm = LevelSearchMat(id[i++]); - if (tm == nullptr) return false; + tm = FindMaterial(id[i++]); + if (tm == nullptr) return false; } int numID = i; - int group = m_brick / m_subdivMapping; + int group = m_brickCount / m_textureSubdivCount; if (radius > 0.0f && radius < 5.0f) // just a square? { - float dim = (m_mosaic*m_brick*m_size)/2.0f; + float dim = (m_mosaicCount*m_brickCount*m_brickSize)/2.0f; - int xx = static_cast((center.x+dim)/m_size); - int yy = static_cast((center.z+dim)/m_size); + int xx = static_cast((center.x+dim)/m_brickSize); + int yy = static_cast((center.z+dim)/m_brickSize); int x = xx/group; int y = yy/group; - tm = LevelSearchMat(id[0]); + tm = FindMaterial(id[0]); if (tm != nullptr) - LevelSetDot(x, y, id[0], tm->mat); // puts the point + SetMaterialPoint(x, y, id[0], tm->mat); // puts the point } else { - for (int y = 0; y < m_levelDotSize; y++) + for (int y = 0; y < m_materialPointCount; y++) { - for (int x = 0; x < m_levelDotSize; x++) + for (int x = 0; x < m_materialPointCount; x++) { if (radius != 0.0f) { Math::Vector pos; - pos.x = (static_cast(x)-m_levelDotSize/2.0f)*group*m_size; - pos.z = (static_cast(y)-m_levelDotSize/2.0f)*group*m_size; + pos.x = (static_cast(x)-m_materialPointCount/2.0f)*group*m_brickSize; + pos.z = (static_cast(y)-m_materialPointCount/2.0f)*group*m_brickSize; if (Math::DistanceProjected(pos, center) > radius) continue; } @@ -1176,11 +1105,11 @@ bool Gfx::CTerrain::LevelGenerate(int *id, float min, float max, int xx = x*group + group/2; int yy = y*group + group/2; - if (LevelGetDot(xx, yy, min, max, slope)) + if (CheckMaterialPoint(xx, yy, min, max, slope)) { int rnd = random[(x%10)+(y%10)*10]; int ii = rnd % numID; - LevelPutDot(xx, yy, id[ii]); + ChangeMaterialPoint(xx, yy, id[ii]); } } } @@ -1189,66 +1118,59 @@ bool Gfx::CTerrain::LevelGenerate(int *id, float min, float max, return true; } -void Gfx::CTerrain::LevelOpenTable() +void Gfx::CTerrain::InitMaterialPoints() { - if (! m_levelText) return; - if (! m_levelDots.empty()) return; // already allocated + if (! m_useMaterials) return; + if (! m_materialPoints.empty()) return; // already allocated - m_levelDotSize = (m_mosaic*m_brick)/(m_brick/m_subdivMapping)+1; - std::vector(m_levelDotSize*m_levelDotSize).swap(m_levelDots); + m_materialPointCount = (m_mosaicCount*m_brickCount)/(m_brickCount/m_textureSubdivCount)+1; + std::vector(m_materialPointCount*m_materialPointCount).swap(m_materialPoints); - for (int i = 0; i < m_levelDotSize * m_levelDotSize; i++) + for (int i = 0; i < m_materialPointCount * m_materialPointCount; i++) { for (int j = 0; j < 4; j++) - m_levelDots[i].mat[j] = 0; + m_materialPoints[i].mat[j] = 0; } } -void Gfx::CTerrain::LevelCloseTable() +void Gfx::CTerrain::FlushMaterialPoints() { - m_levelDots.clear(); + m_materialPoints.clear(); } -bool Gfx::CTerrain::CreateSquare(bool multiRes, int x, int y) +bool Gfx::CTerrain::CreateSquare(int x, int y) { Gfx::Material mat; mat.diffuse = Gfx::Color(1.0f, 1.0f, 1.0f); mat.ambient = Gfx::Color(0.0f, 0.0f, 0.0f); int objRank = m_engine->CreateObject(); - m_engine->SetObjectType(objRank, Gfx::ENG_OBJTYPE_TERRAIN); // it is a terrain + m_engine->SetObjectType(objRank, Gfx::ENG_OBJTYPE_TERRAIN); - m_objRank[x+y*m_mosaic] = objRank; + m_objRanks[x+y*m_mosaicCount] = objRank; - if (multiRes) - { - float min = 0.0f; - float max = m_vision; - max *= m_engine->GetClippingDistance(); - for (int step = 0; step < m_depth; step++) - { - CreateMosaic(x, y, 1 << step, objRank, mat, min, max); - min = max; - max *= 2; - if (step == m_depth-1) max = Math::HUGE_NUM; - } - } - else + float min = 0.0f; + float max = m_vision; + max *= m_engine->GetClippingDistance(); + for (int step = 0; step < m_depth; step++) { - CreateMosaic(x, y, 1, objRank, mat, 0.0f, Math::HUGE_NUM); + CreateMosaic(x, y, 1 << step, objRank, mat, min, max); + min = max; + max *= 2; + if (step == m_depth-1) max = Math::HUGE_NUM; } return true; } -bool Gfx::CTerrain::CreateObjects(bool multiRes) +bool Gfx::CTerrain::CreateObjects() { AdjustRelief(); - for (int y = 0; y < m_mosaic; y++) + for (int y = 0; y < m_mosaicCount; y++) { - for (int x = 0; x < m_mosaic; x++) - CreateSquare(multiRes, x, y); + for (int x = 0; x < m_mosaicCount; x++) + CreateSquare(x, y); } return true; @@ -1257,29 +1179,29 @@ bool Gfx::CTerrain::CreateObjects(bool multiRes) /** ATTENTION: ok only with m_depth = 2! */ bool Gfx::CTerrain::Terraform(const Math::Vector &p1, const Math::Vector &p2, float height) { - float dim = (m_mosaic*m_brick*m_size)/2.0f; + float dim = (m_mosaicCount*m_brickCount*m_brickSize)/2.0f; Math::IntPoint tp1, tp2; - tp1.x = static_cast((p1.x+dim+m_size/2.0f)/m_size); - tp1.y = static_cast((p1.z+dim+m_size/2.0f)/m_size); - tp2.x = static_cast((p2.x+dim+m_size/2.0f)/m_size); - tp2.y = static_cast((p2.z+dim+m_size/2.0f)/m_size); + tp1.x = static_cast((p1.x+dim+m_brickSize/2.0f)/m_brickSize); + tp1.y = static_cast((p1.z+dim+m_brickSize/2.0f)/m_brickSize); + tp2.x = static_cast((p2.x+dim+m_brickSize/2.0f)/m_brickSize); + tp2.y = static_cast((p2.z+dim+m_brickSize/2.0f)/m_brickSize); if (tp1.x > tp2.x) { - int x = tp1.x; + int x = tp1.x; tp1.x = tp2.x; tp2.x = x; } if (tp1.y > tp2.y) { - int y = tp1.y; + int y = tp1.y; tp1.y = tp2.y; tp2.y = y; } - int size = (m_mosaic*m_brick)+1; + int size = (m_mosaicCount*m_brickCount)+1; // Calculates the current average height float avg = 0.0f; @@ -1301,13 +1223,13 @@ bool Gfx::CTerrain::Terraform(const Math::Vector &p1, const Math::Vector &p2, fl { m_relief[x+y*size] = avg+height; - if (x % m_brick == 0 && y % m_depth != 0) + if (x % m_brickCount == 0 && y % m_depth != 0) { m_relief[(x+0)+(y-1)*size] = avg+height; m_relief[(x+0)+(y+1)*size] = avg+height; } - if (y % m_brick == 0 && x % m_depth != 0) + if (y % m_brickCount == 0 && x % m_depth != 0) { m_relief[(x-1)+(y+0)*size] = avg+height; m_relief[(x+1)+(y+0)*size] = avg+height; @@ -1317,22 +1239,22 @@ bool Gfx::CTerrain::Terraform(const Math::Vector &p1, const Math::Vector &p2, fl AdjustRelief(); Math::IntPoint pp1, pp2; - pp1.x = (tp1.x-2)/m_brick; - pp1.y = (tp1.y-2)/m_brick; - pp2.x = (tp2.x+1)/m_brick; - pp2.y = (tp2.y+1)/m_brick; + pp1.x = (tp1.x-2)/m_brickCount; + pp1.y = (tp1.y-2)/m_brickCount; + pp2.x = (tp2.x+1)/m_brickCount; + pp2.y = (tp2.y+1)/m_brickCount; - if (pp1.x < 0 ) pp1.x = 0; - if (pp1.x >= m_mosaic) pp1.x = m_mosaic-1; - if (pp1.y < 0 ) pp1.y = 0; - if (pp1.y >= m_mosaic) pp1.y = m_mosaic-1; + if (pp1.x < 0 ) pp1.x = 0; + if (pp1.x >= m_mosaicCount) pp1.x = m_mosaicCount-1; + if (pp1.y < 0 ) pp1.y = 0; + if (pp1.y >= m_mosaicCount) pp1.y = m_mosaicCount-1; for (int y = pp1.y; y <= pp2.y; y++) { for (int x = pp1.x; x <= pp2.x; x++) { - m_engine->DeleteObject(m_objRank[x+y*m_mosaic]); - CreateSquare(m_multiText, x, y); // recreates the square + m_engine->DeleteObject(m_objRanks[x+y*m_mosaicCount]); + CreateSquare(x, y); // recreates the square } } m_engine->Update(); @@ -1361,37 +1283,37 @@ float Gfx::CTerrain::GetCoarseSlope(const Math::Vector &pos) { if (m_relief.empty()) return 0.0f; - float dim = (m_mosaic*m_brick*m_size)/2.0f; + float dim = (m_mosaicCount*m_brickCount*m_brickSize)/2.0f; - int x = static_cast((pos.x+dim)/m_size); - int y = static_cast((pos.z+dim)/m_size); + int x = static_cast((pos.x+dim)/m_brickSize); + int y = static_cast((pos.z+dim)/m_brickSize); - if ( x < 0 || x >= m_mosaic*m_brick || - y < 0 || y >= m_mosaic*m_brick ) return 0.0f; + if ( x < 0 || x >= m_mosaicCount*m_brickCount || + y < 0 || y >= m_mosaicCount*m_brickCount ) return 0.0f; float level[4] = { - m_relief[(x+0)+(y+0)*(m_mosaic*m_brick+1)], - m_relief[(x+1)+(y+0)*(m_mosaic*m_brick+1)], - m_relief[(x+0)+(y+1)*(m_mosaic*m_brick+1)], - m_relief[(x+1)+(y+1)*(m_mosaic*m_brick+1)], + m_relief[(x+0)+(y+0)*(m_mosaicCount*m_brickCount+1)], + m_relief[(x+1)+(y+0)*(m_mosaicCount*m_brickCount+1)], + m_relief[(x+0)+(y+1)*(m_mosaicCount*m_brickCount+1)], + m_relief[(x+1)+(y+1)*(m_mosaicCount*m_brickCount+1)], }; float min = Math::Min(level[0], level[1], level[2], level[3]); float max = Math::Max(level[0], level[1], level[2], level[3]); - return atanf((max-min)/m_size); + return atanf((max-min)/m_brickSize); } bool Gfx::CTerrain::GetNormal(Math::Vector &n, const Math::Vector &p) { - float dim = (m_mosaic*m_brick*m_size)/2.0f; + float dim = (m_mosaicCount*m_brickCount*m_brickSize)/2.0f; - int x = static_cast((p.x+dim)/m_size); - int y = static_cast((p.z+dim)/m_size); + int x = static_cast((p.x+dim)/m_brickSize); + int y = static_cast((p.z+dim)/m_brickSize); - if ( x < 0 || x > m_mosaic*m_brick || - y < 0 || y > m_mosaic*m_brick ) return false; + if ( x < 0 || x > m_mosaicCount*m_brickCount || + y < 0 || y > m_mosaicCount*m_brickCount ) return false; Math::Vector p1 = GetVector(x+0, y+0); Math::Vector p2 = GetVector(x+1, y+0); @@ -1406,23 +1328,23 @@ bool Gfx::CTerrain::GetNormal(Math::Vector &n, const Math::Vector &p) return true; } -float Gfx::CTerrain::GetFloorLevel(const Math::Vector &p, bool brut, bool water) +float Gfx::CTerrain::GetFloorLevel(const Math::Vector &pos, bool brut, bool water) { - float dim = (m_mosaic*m_brick*m_size)/2.0f; + float dim = (m_mosaicCount*m_brickCount*m_brickSize)/2.0f; - int x = static_cast((p.x+dim)/m_size); - int y = static_cast((p.z+dim)/m_size); + int x = static_cast((pos.x+dim)/m_brickSize); + int y = static_cast((pos.z+dim)/m_brickSize); - if ( x < 0 || x > m_mosaic*m_brick || - y < 0 || y > m_mosaic*m_brick ) return false; + if ( x < 0 || x > m_mosaicCount*m_brickCount || + y < 0 || y > m_mosaicCount*m_brickCount ) return false; Math::Vector p1 = GetVector(x+0, y+0); Math::Vector p2 = GetVector(x+1, y+0); Math::Vector p3 = GetVector(x+0, y+1); Math::Vector p4 = GetVector(x+1, y+1); - Math::Vector ps = p; - if ( fabs(p.z-p2.z) < fabs(p.x-p2.x) ) + Math::Vector ps = pos; + if ( fabs(pos.z-p2.z) < fabs(pos.x-p2.x) ) { if ( !IntersectY(p1, p2, p3, ps) ) return 0.0f; } @@ -1442,25 +1364,23 @@ float Gfx::CTerrain::GetFloorLevel(const Math::Vector &p, bool brut, bool water) return ps.y; } - -/** This height is positive when you are above the ground */ -float Gfx::CTerrain::GetFloorHeight(const Math::Vector &p, bool brut, bool water) +float Gfx::CTerrain::GetHeightToFloor(const Math::Vector &pos, bool brut, bool water) { - float dim = (m_mosaic*m_brick*m_size)/2.0f; + float dim = (m_mosaicCount*m_brickCount*m_brickSize)/2.0f; - int x = static_cast((p.x+dim)/m_size); - int y = static_cast((p.z+dim)/m_size); + int x = static_cast((pos.x+dim)/m_brickSize); + int y = static_cast((pos.z+dim)/m_brickSize); - if ( x < 0 || x > m_mosaic*m_brick || - y < 0 || y > m_mosaic*m_brick ) return false; + if ( x < 0 || x > m_mosaicCount*m_brickCount || + y < 0 || y > m_mosaicCount*m_brickCount ) return false; Math::Vector p1 = GetVector(x+0, y+0); Math::Vector p2 = GetVector(x+1, y+0); Math::Vector p3 = GetVector(x+0, y+1); Math::Vector p4 = GetVector(x+1, y+1); - Math::Vector ps = p; - if ( fabs(p.z-p2.z) < fabs(p.x-p2.x) ) + Math::Vector ps = pos; + if ( fabs(pos.z-p2.z) < fabs(pos.x-p2.x) ) { if ( !IntersectY(p1, p2, p3, ps) ) return 0.0f; } @@ -1474,76 +1394,114 @@ float Gfx::CTerrain::GetFloorHeight(const Math::Vector &p, bool brut, bool water if (water) // not going underwater? { float level = m_water->GetLevel(); - if ( ps.y < level ) ps.y = level; // not under water + if (ps.y < level ) ps.y = level; // not under water } - return p.y-ps.y; + return pos.y-ps.y; } -bool Gfx::CTerrain::MoveOnFloor(Math::Vector &p, bool brut, bool water) +bool Gfx::CTerrain::AdjustToFloor(Math::Vector &pos, bool brut, bool water) { - float dim = (m_mosaic*m_brick*m_size)/2.0f; + float dim = (m_mosaicCount*m_brickCount*m_brickSize)/2.0f; - int x = static_cast((p.x + dim) / m_size); - int y = static_cast((p.z + dim) / m_size); + int x = static_cast((pos.x + dim) / m_brickSize); + int y = static_cast((pos.z + dim) / m_brickSize); - if ( x < 0 || x > m_mosaic*m_brick || - y < 0 || y > m_mosaic*m_brick ) return false; + if ( x < 0 || x > m_mosaicCount*m_brickCount || + y < 0 || y > m_mosaicCount*m_brickCount ) return false; Math::Vector p1 = GetVector(x+0, y+0); Math::Vector p2 = GetVector(x+1, y+0); Math::Vector p3 = GetVector(x+0, y+1); Math::Vector p4 = GetVector(x+1, y+1); - if (fabs(p.z - p2.z) < fabs(p.x - p2.x)) + if (fabs(pos.z - p2.z) < fabs(pos.x - p2.x)) { - if (! Math::IntersectY(p1, p2, p3, p)) return false; + if (! Math::IntersectY(p1, p2, p3, pos)) return false; } else { - if (! Math::IntersectY(p2, p4, p3, p)) return false; + if (! Math::IntersectY(p2, p4, p3, pos)) return false; } - if (! brut) AdjustBuildingLevel(p); + if (! brut) AdjustBuildingLevel(pos); if (water) // not going underwater? { float level = m_water->GetLevel(); - if (p.y < level) p.y = level; // not under water + if (pos.y < level) pos.y = level; // not under water } return true; } - -/** Returns false if the initial coordinate was too far */ -bool Gfx::CTerrain::ValidPosition(Math::Vector &p, float marging) +/** + * @returns \c false if the initial coordinate was outside terrain area; \c true otherwise + */ +bool Gfx::CTerrain::AdjustToStandardBounds(Math::Vector& pos) { bool ok = true; - float limit = m_mosaic*m_brick*m_size/2.0f - marging; + // TODO: _TEEN ... * 0.98f; + float limit = (m_mosaicCount*m_brickCount*m_brickSize)/2.0f*0.92f; - if (p.x < -limit) + if (pos.x < -limit) { - p.x = -limit; + pos.x = -limit; ok = false; } - if (p.z < -limit) + if (pos.z < -limit) { - p.z = -limit; + pos.z = -limit; ok = false; } - if (p.x > limit) + if (pos.x > limit) { - p.x = limit; + pos.x = limit; ok = false; } - if (p.z > limit) + if (pos.z > limit) { - p.z = limit; + pos.z = limit; + ok = false; + } + + return ok; +} + +/** + * @param margin margin to the terrain border + * @returns \c false if the initial coordinate was outside terrain area; \c true otherwise + */ +bool Gfx::CTerrain::AdjustToBounds(Math::Vector& pos, float margin) +{ + bool ok = true; + float limit = m_mosaicCount*m_brickCount*m_brickSize/2.0f - margin; + + if (pos.x < -limit) + { + pos.x = -limit; + ok = false; + } + + if (pos.z < -limit) + { + pos.z = -limit; + ok = false; + } + + if (pos.x > limit) + { + pos.x = limit; + ok = false; + } + + if (pos.z > limit) + { + pos.z = limit; ok = false; } @@ -1670,46 +1628,41 @@ void Gfx::CTerrain::AdjustBuildingLevel(Math::Vector &p) } } - -// returns the hardness of the ground in a given place. -// The hardness determines the noise (SOUND_STEP and SOUND_BOUM). - float Gfx::CTerrain::GetHardness(const Math::Vector &p) { float factor = GetBuildingFactor(p); - if (factor != 1.0f) return 1.0f; // on building + if (factor != 1.0f) return 1.0f; // on building level - if (m_levelDots.empty()) return m_defHardness; + if (m_materialPoints.empty()) return m_defaultHardness; - float dim = (m_mosaic*m_brick*m_size)/2.0f; + float dim = (m_mosaicCount*m_brickCount*m_brickSize)/2.0f; int x, y; - x = static_cast((p.x+dim)/m_size); - y = static_cast((p.z+dim)/m_size); + x = static_cast((p.x+dim)/m_brickSize); + y = static_cast((p.z+dim)/m_brickSize); - if ( x < 0 || x > m_mosaic*m_brick || - y < 0 || y > m_mosaic*m_brick ) return m_defHardness; + if ( x < 0 || x > m_mosaicCount*m_brickCount || + y < 0 || y > m_mosaicCount*m_brickCount ) return m_defaultHardness; - x /= m_brick/m_subdivMapping; - y /= m_brick/m_subdivMapping; + x /= m_brickCount/m_textureSubdivCount; + y /= m_brickCount/m_textureSubdivCount; - if ( x < 0 || x >= m_levelDotSize || - y < 0 || y >= m_levelDotSize ) return m_defHardness; + if ( x < 0 || x >= m_materialPointCount || + y < 0 || y >= m_materialPointCount ) return m_defaultHardness; - int id = m_levelDots[x+y*m_levelDotSize].id; - TerrainMaterial* tm = LevelSearchMat(id); - if (tm == nullptr) return m_defHardness; + int id = m_materialPoints[x+y*m_materialPointCount].id; + TerrainMaterial* tm = FindMaterial(id); + if (tm == nullptr) return m_defaultHardness; return tm->hardness; } -void Gfx::CTerrain::GroundFlat(Math::Vector pos) +void Gfx::CTerrain::ShowFlatGround(Math::Vector pos) { - static char table[41*41]; - + static char table[41*41] = { 1 }; - float rapport = 3200.0f/1024.0f; + float radius = 3200.0f/1024.0f; for (int y = 0; y <= 40; y++) { @@ -1719,16 +1672,16 @@ void Gfx::CTerrain::GroundFlat(Math::Vector pos) table[i] = 0; Math::Vector p; - p.x = (x-20)*rapport; - p.z = (y-20)*rapport; + p.x = (x-20)*radius; + p.z = (y-20)*radius; p.y = 0.0f; - if (Math::Point(p.x, p.y).Length() > 20.0f*rapport) + if (Math::Point(p.x, p.y).Length() > 20.0f*radius) continue; float angle = GetFineSlope(pos+p); - if (angle < FLATLIMIT) + if (angle < Gfx::TERRAIN_FLATLIMIT) table[i] = 1; else table[i] = 2; @@ -1741,7 +1694,7 @@ void Gfx::CTerrain::GroundFlat(Math::Vector pos) float Gfx::CTerrain::GetFlatZoneRadius(Math::Vector center, float max) { float angle = GetFineSlope(center); - if (angle >= Gfx::FLATLIMIT) + if (angle >= Gfx::TERRAIN_FLATLIMIT) return 0.0f; float ref = GetFloorLevel(center, true); diff --git a/src/graphics/engine/terrain.h b/src/graphics/engine/terrain.h index 0c3fa63..80eed07 100644 --- a/src/graphics/engine/terrain.h +++ b/src/graphics/engine/terrain.h @@ -35,7 +35,7 @@ class CWater; //! 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 { Math::Vector center; @@ -81,29 +85,43 @@ struct BuildingLevel } }; +/** + * \struct TerrainMaterial + * \brief Material for ground surface + */ struct TerrainMaterial { + //! Unique ID short id; + //! Texture std::string texName; - float u,v; + //! UV texture coordinates + Math::Point uv; + //! Terrain hardness (defines e.g. sound of walking) float hardness; - char mat[4]; // up, right, down, left + //! IDs of neighbor materials: up, right, down, left + char mat[4]; TerrainMaterial() { id = 0; - u = v = 0.0f; hardness = 0.0f; 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; - char mat[4]; // up, right, down, left + //! IDs of neighbor materials: up, right, down, left + char mat[4]; - DotLevel() + TerrainMaterialPoint() { id = 0; mat[0] = mat[1] = mat[2] = mat[3] = 0; @@ -132,17 +150,73 @@ struct FlyingLimit * \class CTerrain * \brief Terrain loader/generator and manager * + * \section Mapping Terrain mapping + * * Terrain is created from relief textures specifying a XY plane with height * values which are then scaled and translated into XZ surface forming the * terrain of game level. * - * The class also facilitates creating and searching for flat space expanses - * for construction of buildings. + * The basic unit of terrain is called "brick", which is two triangles + * 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). + * + * Bricks are grouped into "mosaics". Mosaic is a square containing + * 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. * - * The terrain also specifies underground resources loaded from texture - * and flying limits for the player. + * 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 { @@ -151,25 +225,32 @@ public: ~CTerrain(); //! 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 bool InitTextures(const std::string& baseName, int* table, int dx, int dy); - //! Empties level - void LevelFlush(); - //! Initializes the names of textures to use for the land - void LevelMaterial(int id, const std::string& baseName, float u, float v, int up, int right, int down, int left, float hardness); - //! Initializes all the ground with a material - bool LevelInit(int id); + + //! Clears all terrain materials + void FlushMaterials(); + //! Adds a terrain material the names of textures to use for the land + void AddMaterial(int id, const std::string& baseName, const Math::Point& uv, + 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 - bool LevelGenerate(int *id, float min, float max, float slope, float freq, Math::Vector center, float radius); - //! Initializes a completely flat terrain + bool GenerateMaterials(int *id, float min, float max, float slope, float freq, Math::Vector center, float radius); + + //! Clears the relief data to zero void FlushRelief(); - //! Load relief from a PNG file - bool ReliefFromPNG(const std::string& filename, float scaleRelief, bool adjustBorder); - //! Load resources from a PNG file - bool ResFromPNG(const std::string& filename); + //! Load relief from image + bool LoadRelief(const std::string& fileName, float scaleRelief, bool adjustBorder); + + //! Load resources from image + bool LoadResources(const std::string& fileName); + //! Creates all objects of the terrain within the 3D engine - bool CreateObjects(bool multiRes); + bool CreateObjects(); + //! Modifies the terrain's relief bool Terraform(const Math::Vector& p1, const Math::Vector& p2, float height); @@ -179,24 +260,24 @@ public: 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); - //! 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); - //! 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); - //! returns the height of the ground - float GetFloorLevel(const Math::Vector& p, bool brut=false, bool water=false); - //! Returns the height to the ground - float GetFloorHeight(const Math::Vector& p, bool brut=false, bool water=false); - //! Modifies the coordinate "y" of point "p" to rest on the ground floor - bool MoveOnFloor(Math::Vector& p, bool brut=false, bool water=false); - //! Modifies a coordinate so that it is on the ground - bool ValidPosition(Math::Vector& p, float marging); - //! Returns the resource type available underground - Gfx::TerrainRes GetResource(const Math::Vector& p); - //! Adjusts a position so that it does not exceed the boundaries - void LimitPos(Math::Vector &pos); + //! Returns the height of the ground level at 2D (XZ) position + float GetFloorLevel(const Math::Vector& pos, bool brut=false, bool water=false); + //! Returns the distance to the ground level from 3D position + float GetHeightToFloor(const Math::Vector& pos, bool brut=false, bool water=false); + //! Modifies the Y coordinate of 3D position to rest on the ground floor + bool AdjustToFloor(Math::Vector& pos, bool brut=false, bool water=false); + //! Adjusts 3D position so that it is within standard terrain boundaries + bool AdjustToStandardBounds(Math::Vector &pos); + //! Adjusts 3D position so that it is within terrain boundaries and the given margin + bool AdjustToBounds(Math::Vector& pos, float margin); + //! Returns the resource type available underground at 2D (XZ) position + Gfx::TerrainRes GetResource(const Math::Vector& pos); //! Empty the table of elevations void FlushBuildingLevel(); @@ -207,16 +288,21 @@ public: //! Removes the elevation for a building when it was destroyed bool DeleteBuildingLevel(Math::Vector center); //! Returns the influence factor whether a position is on a possible rise - float GetBuildingFactor(const Math::Vector& p); - float GetHardness(const Math::Vector& p); - - int GetMosaic(); - int GetBrick(); - float GetSize(); - float GetScaleRelief(); + float GetBuildingFactor(const Math::Vector& pos); + //! Returns the hardness of the ground in a given place + float GetHardness(const Math::Vector& pos); + + //! Returns number of mosaics + int GetMosaicCount(); + //! Returns number of bricks in mosaic + int GetBrickCount(); + //! Returns brick size + float GetBrickSize(); + //! Returns the vertical scale of relief + float GetReliefScale(); //! 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 float GetFlatZoneRadius(Math::Vector center, float max); @@ -234,7 +320,7 @@ public: protected: //! 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 void AdjustRelief(); //! Calculates a vector of the terrain @@ -244,28 +330,28 @@ protected: //! Creates all objects of a mosaic 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 - bool CreateSquare(bool multiRes, int x, int y); - - //! Seeks a materials based on theirs identifier - Gfx::TerrainMaterial* LevelSearchMat(int id); - //! Chooses texture to use for a given square - void LevelTextureName(int x, int y, std::string& name, Math::Point &uv); + bool CreateSquare(int x, int y); + + //! Seeks a material based on its ID + Gfx::TerrainMaterial* FindMaterial(int id); + //! Seeks a material based on neighbor values + 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 - float LevelGetHeight(int x, int y); + float GetHeight(int x, int y); //! Decide whether a point is using the materials - bool LevelGetDot(int x, int y, float min, float max, float slope); - //! Seeks if material exists - int LevelTestMat(char *mat); + bool CheckMaterialPoint(int x, int y, float min, float max, float slope); //! Modifies the state of a point and its four neighbors, without testing if possible - void LevelSetDot(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); + void SetMaterialPoint(int x, int y, int id, char *mat); //! Modifies the state of a point - bool LevelPutDot(int x, int y, int id); - //! Initializes a table with empty levels - void LevelOpenTable(); - //! Closes the level table - void LevelCloseTable(); + bool ChangeMaterialPoint(int x, int y, int id); + //! Tests if a material can give a place, according to its four neighbors. If yes, puts the point. + bool CondChangeMaterialPoint(int x, int y, int id, char *mat); + //! Initializes material points array + void InitMaterialPoints(); + //! Clears the material points + void FlushMaterialPoints(); //! Adjusts a position according to a possible rise void AdjustBuildingLevel(Math::Vector &p); @@ -275,39 +361,51 @@ protected: CEngine* m_engine; CWater* m_water; - //! Number of mosaics - 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 + //! Relief data points std::vector m_relief; - //! Table of textures - std::vector m_texture; - //! Table of rows of objects - std::vector m_objRank; - //! Table of resources + //! Resources data std::vector m_resources; - bool m_multiText; - bool m_levelText; - //! Scale of the mapping - float m_scaleMapping; + //! Texture indices + std::vector m_textures; + //! Object ranks for mosaic objects + std::vector 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; - int m_subdivMapping; + //! Subdivision of material points in mosaic + int m_textureSubdivCount; //! Number of different resolutions (1,2,3,4) int m_depth; + //! Scale of texture mapping + float m_textureScale; + //! Vision before a change of resolution + float m_vision; + + //! Base name for single texture std::string m_texBaseName; + //! Extension for single texture std::string m_texBaseExt; - float m_defHardness; - - std::vector m_levelMats; - std::vector m_levelDots; - int m_levelMatMax; - int m_levelID; + //! Default hardness for level material + float m_defaultHardness; + + //! True if using terrain material mapping + bool m_useMaterials; + //! Terrain materials + std::vector m_materials; + //! Material for terrain points + std::vector 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 m_buildingLevels; diff --git a/src/graphics/engine/water.cpp b/src/graphics/engine/water.cpp index bf2f64d..a2ff081 100644 --- a/src/graphics/engine/water.cpp +++ b/src/graphics/engine/water.cpp @@ -50,7 +50,7 @@ Gfx::CWater::CWater(CInstanceManager* iMan, Gfx::CEngine* engine) m_level = 0.0f; m_draw = true; m_lava = false; - m_color = 0xffffffff; + m_color = Gfx::Color(1.0f, 1.0f, 1.0f, 1.0f); m_subdiv = 4; m_lines.reserve(WATERLINE_PREALLOCATE_COUNT); @@ -330,7 +330,7 @@ void Gfx::CWater::DrawSurf() if (m_type[0] == Gfx::WATER_NULL) return; if (m_lines.empty()) return; - std::vector vertices((m_brick+2)*2, Gfx::VertexTex2()); + std::vector vertices((m_brickCount+2)*2, Gfx::VertexTex2()); Math::Vector eye = m_engine->GetEyePt(); @@ -365,7 +365,7 @@ void Gfx::CWater::DrawSurf() device->SetRenderState(Gfx::RENDER_STATE_FOG, true); - float size = m_size/2.0f; + float size = m_brickSize/2.0f; float sizez = 0.0f; if (under) sizez = -size; else sizez = size; @@ -436,8 +436,8 @@ bool Gfx::CWater::GetWater(int x, int y) x *= m_subdiv; y *= m_subdiv; - float size = m_size/m_subdiv; - float offset = m_brick*m_size/2.0f; + float size = m_brickSize/m_subdiv; + float offset = m_brickCount*m_brickSize/2.0f; 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.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.px2 = m_size*(line.x+line.len) - offset; - line.pz = m_size* line.y - offset; + line.px1 = m_brickSize* line.x - offset; + line.px2 = m_brickSize*(line.x+line.len) - offset; + line.pz = m_brickSize* line.y - offset; 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) m_terrain = static_cast(m_iMan->SearchInstance(CLASS_TERRAIN)); - m_brick = m_terrain->GetBrick()*m_terrain->GetMosaic(); - m_size = m_terrain->GetSize(); + m_brickCount = m_terrain->GetBrickCount()*m_terrain->GetMosaicCount(); + m_brickSize = m_terrain->GetBrickSize(); - m_brick /= m_subdiv; - m_size *= m_subdiv; + m_brickCount /= m_subdiv; + m_brickSize *= m_subdiv; if (m_type[0] == WATER_NULL) return; m_lines.clear(); - for (int y = 0; y < m_brick; y++) + for (int y = 0; y < m_brickCount; y++) { 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? { @@ -530,7 +530,7 @@ void Gfx::CWater::Create(Gfx::WaterType type1, Gfx::WaterType type2, const std:: } } if (len != 0) - CreateLine(m_brick - len, y, len); + CreateLine(m_brickCount - len, y, len); } } diff --git a/src/graphics/engine/water.h b/src/graphics/engine/water.h index 371a91f..9b31045 100644 --- a/src/graphics/engine/water.h +++ b/src/graphics/engine/water.h @@ -188,16 +188,16 @@ protected: int m_subdiv; //! Number of brick*mosaics - int m_brick; + int m_brickCount; //! Size of a item in an brick - float m_size; + float m_brickSize; std::vector m_lines; std::vector m_vapors; bool m_draw; bool m_lava; - long m_color; + Gfx::Color m_color; }; }; // namespace Gfx -- cgit v1.2.3-1-g7c22