summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt8
-rw-r--r--src/app/app.cpp29
-rw-r--r--src/common/ioutils.h80
-rw-r--r--src/common/singleton.h10
-rw-r--r--src/graphics/core/color.h2
-rw-r--r--src/graphics/core/vertex.h22
-rw-r--r--src/graphics/engine/camera.cpp28
-rw-r--r--src/graphics/engine/cloud.cpp47
-rw-r--r--src/graphics/engine/cloud.h31
-rw-r--r--src/graphics/engine/engine.cpp49
-rw-r--r--src/graphics/engine/engine.h7
-rw-r--r--src/graphics/engine/lightman.cpp3
-rw-r--r--src/graphics/engine/modelfile.cpp1205
-rw-r--r--src/graphics/engine/modelfile.h62
-rw-r--r--src/graphics/engine/terrain.cpp969
-rw-r--r--src/graphics/engine/terrain.h286
-rw-r--r--src/graphics/engine/test/CMakeLists.txt25
-rw-r--r--src/graphics/engine/test/modelfile_test.cpp305
-rw-r--r--src/graphics/engine/water.cpp32
-rw-r--r--src/graphics/engine/water.h6
-rw-r--r--src/graphics/opengl/gldevice.cpp50
-rw-r--r--src/tools/CMakeLists.txt13
-rw-r--r--src/tools/README.txt4
-rw-r--r--src/tools/convert_model.cpp286
24 files changed, 2391 insertions, 1168 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 11c62f7..dc003b9 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,5 +1,11 @@
# CBot shared library is built separately
-add_subdirectory(CBot)
+add_subdirectory(CBot)
+
+# Tools directory is built separately
+add_subdirectory(tools)
+
+# Tests
+add_subdirectory(graphics/engine/test)
# Configure options
diff --git a/src/app/app.cpp b/src/app/app.cpp
index 182e0fd..00cd13d 100644
--- a/src/app/app.cpp
+++ b/src/app/app.cpp
@@ -113,6 +113,7 @@ CApplication::~CApplication()
bool CApplication::ParseArguments(int argc, char *argv[])
{
bool waitDataDir = false;
+ bool waitLogLevel = false;
for (int i = 1; i < argc; ++i)
{
@@ -125,10 +126,34 @@ bool CApplication::ParseArguments(int argc, char *argv[])
continue;
}
+ if (waitLogLevel)
+ {
+ waitLogLevel = false;
+ if (arg == "trace")
+ GetLogger()->SetLogLevel(LOG_TRACE);
+ else if (arg == "debug")
+ GetLogger()->SetLogLevel(LOG_DEBUG);
+ else if (arg == "info")
+ GetLogger()->SetLogLevel(LOG_INFO);
+ else if (arg == "warn")
+ GetLogger()->SetLogLevel(LOG_WARN);
+ else if (arg == "error")
+ GetLogger()->SetLogLevel(LOG_ERROR);
+ else if (arg == "none")
+ GetLogger()->SetLogLevel(LOG_NONE);
+ else
+ return false;
+ continue;
+ }
+
if (arg == "-debug")
{
SetDebugMode(true);
}
+ else if (arg == "-loglevel")
+ {
+ waitLogLevel = true;
+ }
else if (arg == "-datadir")
{
waitDataDir = true;
@@ -140,8 +165,8 @@ bool CApplication::ParseArguments(int argc, char *argv[])
}
}
- // Data dir not given?
- if (waitDataDir)
+ // Args not given?
+ if (waitDataDir || waitLogLevel)
return false;
return true;
diff --git a/src/common/ioutils.h b/src/common/ioutils.h
index a7bd044..2a542c6 100644
--- a/src/common/ioutils.h
+++ b/src/common/ioutils.h
@@ -27,9 +27,10 @@ namespace IOUtils {
//! Writes a binary number to output stream
/**
- \c T is a numeric type (int, unsigned int, etc.)
- \c N is number of bytes
- Write order is little-endian */
+ * \c T is a numeric type (int, unsigned int, etc.)
+ * \c N is number of bytes
+ * Write order is little-endian
+ */
template<int N, typename T>
void WriteBinary(T value, std::ostream &ostr)
{
@@ -42,9 +43,10 @@ void WriteBinary(T value, std::ostream &ostr)
//! Reads a binary number from input stream
/**
- \c T is a numeric type (int, unsigned int, etc.)
- \c N is number of bytes
- Read order is little-endian */
+ * \c T is a numeric type (int, unsigned int, etc.)
+ * \c N is number of bytes
+ * Read order is little-endian
+ */
template<int N, typename T>
T ReadBinary(std::istream &istr)
{
@@ -58,10 +60,31 @@ T ReadBinary(std::istream &istr)
return value;
}
+//! Writes a binary 1-byte boolean
+/**
+ * false is 0; true is 1.
+ */
+void WriteBinaryBool(float value, std::ostream &ostr)
+{
+ unsigned char v = value ? 1 : 0;
+ IOUtils::WriteBinary<1, unsigned char>(v, ostr);
+}
+
+//! Reads a binary 1-byte boolean
+/**
+ * 0 is false; other values are true.
+ */
+bool ReadBinaryBool(std::istream &istr)
+{
+ int v = IOUtils::ReadBinary<1, unsigned char>(istr);
+ return v != 0;
+}
+
//! Writes a binary 32-bit float to output stream
/**
- Write order is little-endian
- NOTE: code is probably not portable as there are platforms with other float representations. */
+ * Write order is little-endian
+ * NOTE: code is probably not portable as there are platforms with other float representations.
+ */
void WriteBinaryFloat(float value, std::ostream &ostr)
{
union { float fValue; unsigned int iValue; } u;
@@ -72,8 +95,9 @@ void WriteBinaryFloat(float value, std::ostream &ostr)
//! Reads a binary 32-bit float from input stream
/**
- Read order is little-endian
- NOTE: code is probably not portable as there are platforms with other float representations. */
+ * Read order is little-endian
+ * NOTE: code is probably not portable as there are platforms with other float representations.
+ */
float ReadBinaryFloat(std::istream &istr)
{
union { float fValue; unsigned int iValue; } u;
@@ -82,4 +106,40 @@ float ReadBinaryFloat(std::istream &istr)
return u.fValue;
}
+//! Writes a variable binary string to output stream
+/**
+ * The string is written by first writing string length
+ * in \c N byte binary number and then the string bytes.
+ */
+template<int N>
+void WriteBinaryString(const std::string &value, std::ostream &ostr)
+{
+ int length = value.size();
+ WriteBinary<N, int>(length, ostr);
+
+ for (int i = 0; i < length; ++i)
+ ostr.put(value[i]);
+}
+
+//! Reads a variable binary string from output stream
+/**
+ * The string is read by first reading string length
+ * in \c N byte binary number and then the string bytes.
+ */
+template<int N>
+std::string ReadBinaryString(std::istream &istr)
+{
+ int length = ReadBinary<N, int>(istr);
+
+ std::string str;
+ char c = 0;
+ for (int i = 0; i < length; ++i)
+ {
+ istr.read(&c, 1);
+ str += c;
+ }
+
+ return str;
+}
+
}; // namespace IOUtils
diff --git a/src/common/singleton.h b/src/common/singleton.h
index 4df7878..f631ed4 100644
--- a/src/common/singleton.h
+++ b/src/common/singleton.h
@@ -29,26 +29,26 @@ template<typename T> class CSingleton
public:
static T& GetInstance() {
- assert(mInstance != NULL);
+ assert(mInstance != nullptr);
return *mInstance;
}
static T* GetInstancePointer() {
- assert(mInstance != NULL);
+ assert(mInstance != nullptr);
return mInstance;
}
static bool IsCreated() {
- return mInstance != NULL;
+ return mInstance != nullptr;
}
CSingleton() {
- assert(mInstance == NULL);
+ assert(mInstance == nullptr);
mInstance = static_cast<T *>(this);
}
virtual ~CSingleton() {
- mInstance = NULL;
+ mInstance = nullptr;
}
private:
diff --git a/src/graphics/core/color.h b/src/graphics/core/color.h
index ff8a2eb..bcd0af1 100644
--- a/src/graphics/core/color.h
+++ b/src/graphics/core/color.h
@@ -35,7 +35,7 @@ struct Color
float r, g, b, a;
//! 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) {}
inline Gfx::Color Inverse() const
diff --git a/src/graphics/core/vertex.h b/src/graphics/core/vertex.h
index 53dd642..a99d618 100644
--- a/src/graphics/core/vertex.h
+++ b/src/graphics/core/vertex.h
@@ -47,9 +47,9 @@ struct Vertex
Math::Vector normal;
Math::Point texCoord;
- Vertex(Math::Vector aCoord = Math::Vector(),
- Math::Vector aNormal = Math::Vector(),
- Math::Point aTexCoord = Math::Point())
+ explicit Vertex(Math::Vector aCoord = Math::Vector(),
+ Math::Vector aNormal = Math::Vector(),
+ Math::Point aTexCoord = Math::Point())
: coord(aCoord), normal(aNormal), texCoord(aTexCoord) {}
@@ -83,10 +83,10 @@ struct VertexCol
Gfx::Color specular;
Math::Point texCoord;
- VertexCol(Math::Vector aCoord = Math::Vector(),
- Gfx::Color aColor = Gfx::Color(),
- Gfx::Color aSpecular = Gfx::Color(),
- Math::Point aTexCoord = Math::Point())
+ explicit VertexCol(Math::Vector aCoord = Math::Vector(),
+ Gfx::Color aColor = Gfx::Color(),
+ Gfx::Color aSpecular = Gfx::Color(),
+ Math::Point aTexCoord = Math::Point())
: coord(aCoord), color(aColor), specular(aSpecular), texCoord(aTexCoord) {}
//! Returns a string "(c: [...], col: [...], sp: [...], tc: [...])"
@@ -115,10 +115,10 @@ struct VertexTex2
Math::Point texCoord;
Math::Point texCoord2;
- VertexTex2(Math::Vector aCoord = Math::Vector(),
- Math::Vector aNormal = Math::Vector(),
- Math::Point aTexCoord = Math::Point(),
- Math::Point aTexCoord2 = Math::Point())
+ explicit VertexTex2(Math::Vector aCoord = Math::Vector(),
+ Math::Vector aNormal = Math::Vector(),
+ Math::Point aTexCoord = Math::Point(),
+ Math::Point aTexCoord2 = Math::Point())
: coord(aCoord), normal(aNormal), texCoord(aTexCoord), texCoord2(aTexCoord2) {}
//! Sets the fields from Gfx::Vertex with texCoord2 = (0,0)
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..26a75ab 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)
@@ -42,7 +43,7 @@ Gfx::CCloud::CCloud(CInstanceManager* iMan, Gfx::CEngine* engine)
m_level = 0.0f;
m_wind = Math::Vector(0.0f, 0.0f, 0.0f);
m_subdiv = 8;
- m_enable = true;
+ m_enabled = true;
m_lines.reserve(CLOUD_LINE_PREALLOCATE_COUNT);
}
@@ -77,8 +78,8 @@ bool Gfx::CCloud::EventFrame(const Event &event)
return true;
}
-void Gfx::CCloud::AdjustLevel(Math::Vector &pos, Math::Vector &eye, float deep,
- Math::Point &uv1, Math::Point &uv2)
+void Gfx::CCloud::AdjustLevel(Math::Vector& pos, Math::Vector& eye, float deep,
+ Math::Point& uv1, Math::Point& uv2)
{
uv1.x = (pos.x+20000.0f)/1280.0f;
uv1.y = (pos.z+20000.0f)/1280.0f;
@@ -95,14 +96,14 @@ void Gfx::CCloud::AdjustLevel(Math::Vector &pos, Math::Vector &eye, float deep,
void Gfx::CCloud::Draw()
{
- if (! m_enable) return;
+ if (! m_enabled) return;
if (m_level == 0.0f) 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 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,17 +196,17 @@ 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);
}
void Gfx::CCloud::Create(const std::string& fileName,
- Gfx::Color diffuse, Gfx::Color ambient,
+ const Gfx::Color& diffuse, const Gfx::Color& ambient,
float level)
{
m_diffuse = diffuse;
@@ -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;
}
@@ -257,12 +258,12 @@ float Gfx::CCloud::GetLevel()
return m_level;
}
-void Gfx::CCloud::SetEnable(bool enable)
+void Gfx::CCloud::SetEnabled(bool enabled)
{
- m_enable = enable;
+ m_enabled = enabled;
}
-bool Gfx::CCloud::GetEnable()
+bool Gfx::CCloud::GetEnabled()
{
- return m_enable;
+ return m_enabled;
}
diff --git a/src/graphics/engine/cloud.h b/src/graphics/engine/cloud.h
index abfaf26..a9109fa 100644
--- a/src/graphics/engine/cloud.h
+++ b/src/graphics/engine/cloud.h
@@ -79,29 +79,32 @@ public:
CCloud(CInstanceManager* iMan, CEngine* engine);
~CCloud();
- bool EventProcess(const Event &event);
+ bool EventProcess(const Event& event);
//! Removes all the clouds
void Flush();
//! Creates all areas of cloud
- void Create(const std::string& fileName, Gfx::Color diffuse, Gfx::Color ambient, float level);
+ void Create(const std::string& fileName, const Gfx::Color& diffuse, const Gfx::Color& ambient, float level);
//! Draw the clouds
void Draw();
- //! Modifies the cloud level
+ //! Management of cloud level
+ //@{
void SetLevel(float level);
- //! Returns the current level of clouds
float GetLevel();
+ //@}
- //! Activate management of clouds
- void SetEnable(bool enable);
- bool GetEnable();
+ //! Management of clouds
+ //@{
+ void SetEnabled(bool enable);
+ bool GetEnabled();
+ //@}
protected:
//! Makes the clouds evolve
bool EventFrame(const Event &event);
//! Adjusts the position to normal, to imitate the clouds at movement
- void AdjustLevel(Math::Vector &pos, Math::Vector &eye, float deep,
- Math::Point &uv1, Math::Point &uv2);
+ void AdjustLevel(Math::Vector& pos, Math::Vector& eye, float deep,
+ Math::Point& uv1, Math::Point& uv2);
//! Updates the positions, relative to the ground
void CreateLine(int x, int y, int len);
@@ -110,9 +113,11 @@ protected:
Gfx::CEngine* m_engine;
Gfx::CTerrain* m_terrain;
- std::string m_fileName;
+ bool m_enabled;
//! Overall level
float m_level;
+ //! Texture
+ std::string m_fileName;
//! Feedrate (wind)
Math::Point m_speed;
//! Diffuse color
@@ -126,13 +131,11 @@ 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<Gfx::CloudLine> m_lines;
-
- bool m_enable;
};
diff --git a/src/graphics/engine/engine.cpp b/src/graphics/engine/engine.cpp
index 3187dde..068687a 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;
@@ -208,7 +208,7 @@ Gfx::CEngine::CEngine(CInstanceManager *iMan, CApplication *app)
m_mouseVisible = false;
m_texPath = "textures/";
- m_defaultTexParams.format = Gfx::TEX_IMG_RGB;
+ m_defaultTexParams.format = Gfx::TEX_IMG_AUTO;
m_defaultTexParams.mipmap = true;
m_defaultTexParams.minFilter = Gfx::TEX_MIN_FILTER_LINEAR_MIPMAP_LINEAR;
m_defaultTexParams.magFilter = Gfx::TEX_MAG_FILTER_LINEAR;
@@ -260,6 +260,8 @@ bool Gfx::CEngine::Create()
m_lightning = new Gfx::CLightning(m_iMan, this);
m_planet = new Gfx::CPlanet(m_iMan, this);
+ m_lightMan->SetDevice(m_device);
+
m_text->SetDevice(m_device);
if (! m_text->Create())
{
@@ -979,7 +981,7 @@ Gfx::EngineObjLevel4* Gfx::CEngine::FindTriangles(int objRank, const Gfx::Materi
for (int l3 = 0; l3 < static_cast<int>( p2.next.size() ); l3++)
{
- Gfx::EngineObjLevel3& p3 = p2.next[l1];
+ Gfx::EngineObjLevel3& p3 = p2.next[l3];
if (! p3.used) continue;
if (p3.min != min || p3.max != max) continue;
@@ -1031,7 +1033,7 @@ int Gfx::CEngine::GetPartialTriangles(int objRank, float min, float max, float p
for (int l3 = 0; l3 < static_cast<int>( p2.next.size() ); l3++)
{
- Gfx::EngineObjLevel3& p3 = p2.next[l1];
+ Gfx::EngineObjLevel3& p3 = p2.next[l3];
if (! p3.used) continue;
if (p3.min != min || p3.max != max) continue;
@@ -1126,7 +1128,7 @@ void Gfx::CEngine::ChangeLOD()
for (int l3 = 0; l3 < static_cast<int>( p2.next.size() ); l3++)
{
- Gfx::EngineObjLevel3& p3 = p2.next[l1];
+ Gfx::EngineObjLevel3& p3 = p2.next[l3];
if (! p3.used) continue;
if ( Math::IsEqual(p3.min, 0.0f ) &&
@@ -1620,7 +1622,7 @@ void Gfx::CEngine::UpdateGeometry()
for (int l3 = 0; l3 < static_cast<int>( p2.next.size() ); l3++)
{
- Gfx::EngineObjLevel3& p3 = p2.next[l1];
+ Gfx::EngineObjLevel3& p3 = p2.next[l3];
if (! p3.used) continue;
for (int l4 = 0; l4 < static_cast<int>( p3.next.size() ); l4++)
@@ -1712,7 +1714,7 @@ int Gfx::CEngine::DetectObject(Math::Point mouse)
for (int l3 = 0; l3 < static_cast<int>( p2.next.size() ); l3++)
{
- Gfx::EngineObjLevel3& p3 = p2.next[l1];
+ Gfx::EngineObjLevel3& p3 = p2.next[l3];
if (! p3.used) continue;
if (p3.min != 0.0f) continue; // LOD B or C?
@@ -2099,7 +2101,8 @@ void Gfx::CEngine::SetViewParams(const Math::Vector& eyePt, const Math::Vector&
if (m_sound == nullptr)
m_sound = static_cast<CSoundInterface*>( m_iMan->SearchInstance(CLASS_SOUND) );
- m_sound->SetListener(eyePt, lookatPt);
+ if (m_sound != nullptr)
+ m_sound->SetListener(eyePt, lookatPt);
}
Gfx::Texture Gfx::CEngine::CreateTexture(const std::string& texName, const Gfx::TextureCreateParams& params)
@@ -2315,7 +2318,7 @@ void Gfx::CEngine::SetFocus(float focus)
m_focus = focus;
m_size = m_app->GetVideoConfig().size;
- float aspect = (static_cast<float>(m_size.y)) / m_size.x;
+ float aspect = (static_cast<float>(m_size.x)) / m_size.y;
Math::LoadProjectionMatrix(m_matProj, m_focus, aspect, 0.5f, m_deepView[0]);
}
@@ -2837,7 +2840,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();
@@ -2889,6 +2892,8 @@ void Gfx::CEngine::Draw3DScene()
if (m_shadowVisible)
{
+ m_lightMan->UpdateLightsEnableState(Gfx::ENG_OBJTYPE_TERRAIN);
+
// Draw the terrain
for (int l1 = 0; l1 < static_cast<int>( m_objectTree.size() ); l1++)
@@ -2911,13 +2916,19 @@ void Gfx::CEngine::Draw3DScene()
if (! m_objects[objRank].drawWorld)
continue;
+ m_device->SetTransform(Gfx::TRANSFORM_WORLD, m_objects[objRank].transform);
+
+ if (! IsVisible(objRank))
+ continue;
+
for (int l3 = 0; l3 < static_cast<int>( p2.next.size() ); l3++)
{
- Gfx::EngineObjLevel3& p3 = p2.next[l1];
+ Gfx::EngineObjLevel3& p3 = p2.next[l3];
if (! p3.used) continue;
if ( m_objects[objRank].distance < p3.min ||
- m_objects[objRank].distance >= p3.max ) continue;
+ m_objects[objRank].distance >= p3.max )
+ continue;
for (int l4 = 0; l4 < static_cast<int>( p3.next.size() ); l4++)
{
@@ -2985,7 +2996,7 @@ void Gfx::CEngine::Draw3DScene()
for (int l3 = 0; l3 < static_cast<int>( p2.next.size() ); l3++)
{
- Gfx::EngineObjLevel3& p3 = p2.next[l1];
+ Gfx::EngineObjLevel3& p3 = p2.next[l3];
if (! p3.used) continue;
if ( m_objects[objRank].distance < p3.min ||
@@ -3074,7 +3085,7 @@ void Gfx::CEngine::Draw3DScene()
for (int l3 = 0; l3 < static_cast<int>( p2.next.size() ); l3++)
{
- Gfx::EngineObjLevel3& p3 = p2.next[l1];
+ Gfx::EngineObjLevel3& p3 = p2.next[l3];
if (! p3.used) continue;
if ( m_objects[objRank].distance < p3.min ||
@@ -3189,7 +3200,7 @@ void Gfx::CEngine::DrawInterface()
for (int l3 = 0; l3 < static_cast<int>( p2.next.size() ); l3++)
{
- Gfx::EngineObjLevel3& p3 = p2.next[l1];
+ Gfx::EngineObjLevel3& p3 = p2.next[l3];
if (! p3.used) continue;
if ( m_objects[objRank].distance < p3.min ||
diff --git a/src/graphics/engine/engine.h b/src/graphics/engine/engine.h
index b3a576a..705c83a 100644
--- a/src/graphics/engine/engine.h
+++ b/src/graphics/engine/engine.h
@@ -807,6 +807,9 @@ public:
float min, float max, Gfx::EngineTextureMapping mode,
float pos, float factor, float tl, float ts, float tt);
+ //! Detects the target object that is selected with the mouse
+ /** Returns the rank of the object or -1. */
+ int DetectObject(Math::Point mouse);
//! Creates a shadow for the given object
bool CreateShadow(int objRank);
@@ -1197,10 +1200,6 @@ protected:
//! Compute and return the 2D box on screen of any object
bool GetBBox2D(int objRank, Math::Point& min, Math::Point& max);
- //! Detects the target object that is selected with the mouse
- /** Returns the rank of the object or -1. */
- int DetectObject(Math::Point mouse);
-
//! Detects whether the mouse is in a triangle.
bool DetectTriangle(Math::Point mouse, Gfx::VertexTex2* triangle, int objRank, float& dist);
diff --git a/src/graphics/engine/lightman.cpp b/src/graphics/engine/lightman.cpp
index 9e15b5a..46000d7 100644
--- a/src/graphics/engine/lightman.cpp
+++ b/src/graphics/engine/lightman.cpp
@@ -65,6 +65,7 @@ void Gfx::LightProgression::SetTarget(float value)
Gfx::DynamicLight::DynamicLight()
{
used = enabled = false;
+ includeType = excludeType = Gfx::ENG_OBJTYPE_NULL;
}
@@ -147,8 +148,6 @@ bool Gfx::CLightManager::DeleteLight(int lightRank)
return true;
}
-// Specifies a light.
-
bool Gfx::CLightManager::SetLight(int lightRank, const Gfx::Light &light)
{
if ( (lightRank < 0) || (lightRank >= static_cast<int>( m_dynLights.size() )) )
diff --git a/src/graphics/engine/modelfile.cpp b/src/graphics/engine/modelfile.cpp
index 9d7a389..2049749 100644
--- a/src/graphics/engine/modelfile.cpp
+++ b/src/graphics/engine/modelfile.cpp
@@ -23,120 +23,42 @@
#include "common/ioutils.h"
#include "common/logger.h"
#include "common/stringutils.h"
+#include "graphics/engine/engine.h"
#include "math/geometry.h"
#include <string.h>
#include <fstream>
+#include <sstream>
-//! How big the triangle vector is by default
-const int TRIANGLE_PREALLOCATE_COUNT = 2000;
-
-/**
- \struct ModelHeader
- \brief Header info for model file
+/*
+ * NOTE: #ifndef checking for MODELFILE_NO_ENGINE
+ * is provided in this module to conditionally
+ * disable dependence on CEngine.
*/
-struct ModelHeader
-{
- //! Revision number
- int revision;
- //! Version number
- int version;
- //! Total number of vertices
- int totalVertices;
- //! Reserved area
- int reserved[10];
-
- ModelHeader()
- {
- memset(this, 0, sizeof(*this));
- }
-};
-struct OldModelTriangle1
-{
- char used;
- char selected;
- Gfx::Vertex p1;
- Gfx::Vertex p2;
- Gfx::Vertex p3;
- Gfx::Material material;
- char texName[20];
- float min;
- float max;
-
- OldModelTriangle1()
- {
- memset(this, 0, sizeof(*this));
- }
-};
-
-struct OldModelTriangle2
-{
- char used;
- char selected;
- Gfx::Vertex p1;
- Gfx::Vertex p2;
- Gfx::Vertex p3;
- Gfx::Material material;
- char texName[20];
- float min;
- float max;
- long state;
- short reserved1;
- short reserved2;
- short reserved3;
- short reserved4;
- OldModelTriangle2()
- {
- memset(this, 0, sizeof(*this));
- }
-};
-
-
-struct NewModelTriangle
-{
- char used;
- char selected;
- Gfx::VertexTex2 p1;
- Gfx::VertexTex2 p2;
- Gfx::VertexTex2 p3;
- Gfx::Material material;
- char texName[20];
- float min;
- float max;
- long state;
- short texNum2;
- short reserved2;
- short reserved3;
- short reserved4;
+//! How big the triangle vector is by default
+const int TRIANGLE_PREALLOCATE_COUNT = 2000;
- NewModelTriangle()
- {
- memset(this, 0, sizeof(*this));
- }
-};
-Gfx::Vertex ReadBinaryVertex(std::istream &stream)
+bool ReadBinaryVertex(std::istream& stream, Gfx::Vertex& vertex)
{
- Gfx::Vertex result;
-
- result.coord.x = IOUtils::ReadBinaryFloat(stream);
- result.coord.y = IOUtils::ReadBinaryFloat(stream);
- result.coord.z = IOUtils::ReadBinaryFloat(stream);
- result.normal.x = IOUtils::ReadBinaryFloat(stream);
- result.normal.y = IOUtils::ReadBinaryFloat(stream);
- result.normal.z = IOUtils::ReadBinaryFloat(stream);
- result.texCoord.x = IOUtils::ReadBinaryFloat(stream);
- result.texCoord.y = IOUtils::ReadBinaryFloat(stream);
-
- return result;
+ vertex.coord.x = IOUtils::ReadBinaryFloat(stream);
+ vertex.coord.y = IOUtils::ReadBinaryFloat(stream);
+ vertex.coord.z = IOUtils::ReadBinaryFloat(stream);
+ vertex.normal.x = IOUtils::ReadBinaryFloat(stream);
+ vertex.normal.y = IOUtils::ReadBinaryFloat(stream);
+ vertex.normal.z = IOUtils::ReadBinaryFloat(stream);
+ vertex.texCoord.x = IOUtils::ReadBinaryFloat(stream);
+ vertex.texCoord.y = IOUtils::ReadBinaryFloat(stream);
+
+ return !stream.fail();
}
-void WriteBinaryVertex(Gfx::Vertex vertex, std::ostream &stream)
+bool WriteBinaryVertex(Gfx::Vertex vertex, std::ostream& stream)
{
IOUtils::WriteBinaryFloat(vertex.coord.x, stream);
IOUtils::WriteBinaryFloat(vertex.coord.y, stream);
@@ -146,27 +68,27 @@ void WriteBinaryVertex(Gfx::Vertex vertex, std::ostream &stream)
IOUtils::WriteBinaryFloat(vertex.normal.z, stream);
IOUtils::WriteBinaryFloat(vertex.texCoord.x, stream);
IOUtils::WriteBinaryFloat(vertex.texCoord.y, stream);
+
+ return !stream.fail();
}
-Gfx::VertexTex2 ReadBinaryVertexTex2(std::istream &stream)
+bool ReadBinaryVertexTex2(std::istream& stream, Gfx::VertexTex2& vertex)
{
- Gfx::VertexTex2 result;
-
- result.coord.x = IOUtils::ReadBinaryFloat(stream);
- result.coord.y = IOUtils::ReadBinaryFloat(stream);
- result.coord.z = IOUtils::ReadBinaryFloat(stream);
- result.normal.x = IOUtils::ReadBinaryFloat(stream);
- result.normal.y = IOUtils::ReadBinaryFloat(stream);
- result.normal.z = IOUtils::ReadBinaryFloat(stream);
- result.texCoord.x = IOUtils::ReadBinaryFloat(stream);
- result.texCoord.y = IOUtils::ReadBinaryFloat(stream);
- result.texCoord2.x = IOUtils::ReadBinaryFloat(stream);
- result.texCoord2.y = IOUtils::ReadBinaryFloat(stream);
-
- return result;
+ vertex.coord.x = IOUtils::ReadBinaryFloat(stream);
+ vertex.coord.y = IOUtils::ReadBinaryFloat(stream);
+ vertex.coord.z = IOUtils::ReadBinaryFloat(stream);
+ vertex.normal.x = IOUtils::ReadBinaryFloat(stream);
+ vertex.normal.y = IOUtils::ReadBinaryFloat(stream);
+ vertex.normal.z = IOUtils::ReadBinaryFloat(stream);
+ vertex.texCoord.x = IOUtils::ReadBinaryFloat(stream);
+ vertex.texCoord.y = IOUtils::ReadBinaryFloat(stream);
+ vertex.texCoord2.x = IOUtils::ReadBinaryFloat(stream);
+ vertex.texCoord2.y = IOUtils::ReadBinaryFloat(stream);
+
+ return !stream.fail();
}
-void WriteBinaryVertexTex2(Gfx::VertexTex2 vertex, std::ostream &stream)
+bool WriteBinaryVertexTex2(Gfx::VertexTex2 vertex, std::ostream& stream)
{
IOUtils::WriteBinaryFloat(vertex.coord.x, stream);
IOUtils::WriteBinaryFloat(vertex.coord.y, stream);
@@ -178,38 +100,83 @@ void WriteBinaryVertexTex2(Gfx::VertexTex2 vertex, std::ostream &stream)
IOUtils::WriteBinaryFloat(vertex.texCoord.y, stream);
IOUtils::WriteBinaryFloat(vertex.texCoord2.x, stream);
IOUtils::WriteBinaryFloat(vertex.texCoord2.y, stream);
+
+ return !stream.fail();
}
-Gfx::Material ReadBinaryMaterial(std::istream &stream)
+bool ReadTextVertexTex2(const std::string& text, Gfx::VertexTex2& vertex)
{
- Gfx::Material result;
+ std::stringstream stream;
+ stream.str(text);
- result.diffuse.r = IOUtils::ReadBinaryFloat(stream);
- result.diffuse.g = IOUtils::ReadBinaryFloat(stream);
- result.diffuse.b = IOUtils::ReadBinaryFloat(stream);
- result.diffuse.a = IOUtils::ReadBinaryFloat(stream);
+ std::string what;
- result.ambient.r = IOUtils::ReadBinaryFloat(stream);
- result.ambient.g = IOUtils::ReadBinaryFloat(stream);
- result.ambient.b = IOUtils::ReadBinaryFloat(stream);
- result.ambient.a = IOUtils::ReadBinaryFloat(stream);
+ stream >> what;
+ if (what != "c")
+ return false;
- result.specular.r = IOUtils::ReadBinaryFloat(stream);
- result.specular.g = IOUtils::ReadBinaryFloat(stream);
- result.specular.b = IOUtils::ReadBinaryFloat(stream);
- result.specular.a = IOUtils::ReadBinaryFloat(stream);
+ stream >> vertex.coord.x >> vertex.coord.y >> vertex.coord.z;
- /* emissive.r = */ IOUtils::ReadBinaryFloat(stream);
- /* emissive.g = */ IOUtils::ReadBinaryFloat(stream);
- /* emissive.b = */ IOUtils::ReadBinaryFloat(stream);
- /* emissive.a = */ IOUtils::ReadBinaryFloat(stream);
+ stream >> what;
+ if (what != "n")
+ return false;
+
+ stream >> vertex.normal.x >> vertex.normal.y >> vertex.normal.z;
+
+ stream >> what;
+ if (what != "t1")
+ return false;
- /* power = */ IOUtils::ReadBinaryFloat(stream);
+ stream >> vertex.texCoord.x >> vertex.texCoord.y;
- return result;
+ stream >> what;
+ if (what != "t2")
+ return false;
+
+ stream >> vertex.texCoord2.x >> vertex.texCoord2.y;
+
+ return !stream.fail();
+}
+
+bool WriteTextVertexTex2(const Gfx::VertexTex2& vertex, std::ostream& stream)
+{
+ stream << "c " << vertex.coord.x << " " << vertex.coord.y << " " << vertex.coord.z;
+ stream << " n " << vertex.normal.x << " " << vertex.normal.y << " " << vertex.normal.z;
+ stream << " t1 " << vertex.texCoord.x << " " << vertex.texCoord.y;
+ stream << " t2 " << vertex.texCoord2.x << " " << vertex.texCoord2.y;
+ stream << std::endl;
+
+ return !stream.fail();
+}
+
+bool ReadBinaryMaterial(std::istream& stream, Gfx::Material& material)
+{
+ material.diffuse.r = IOUtils::ReadBinaryFloat(stream);
+ material.diffuse.g = IOUtils::ReadBinaryFloat(stream);
+ material.diffuse.b = IOUtils::ReadBinaryFloat(stream);
+ material.diffuse.a = IOUtils::ReadBinaryFloat(stream);
+
+ material.ambient.r = IOUtils::ReadBinaryFloat(stream);
+ material.ambient.g = IOUtils::ReadBinaryFloat(stream);
+ material.ambient.b = IOUtils::ReadBinaryFloat(stream);
+ material.ambient.a = IOUtils::ReadBinaryFloat(stream);
+
+ material.specular.r = IOUtils::ReadBinaryFloat(stream);
+ material.specular.g = IOUtils::ReadBinaryFloat(stream);
+ material.specular.b = IOUtils::ReadBinaryFloat(stream);
+ material.specular.a = IOUtils::ReadBinaryFloat(stream);
+
+ /* emissive.r = */ IOUtils::ReadBinaryFloat(stream);
+ /* emissive.g = */ IOUtils::ReadBinaryFloat(stream);
+ /* emissive.b = */ IOUtils::ReadBinaryFloat(stream);
+ /* emissive.a = */ IOUtils::ReadBinaryFloat(stream);
+
+ /* power = */ IOUtils::ReadBinaryFloat(stream);
+
+ return !stream.fail();
}
-void WriteBinaryMaterial(Gfx::Material material, std::ostream &stream)
+bool WriteBinaryMaterial(const Gfx::Material& material, std::ostream& stream)
{
IOUtils::WriteBinaryFloat(material.diffuse.r, stream);
IOUtils::WriteBinaryFloat(material.diffuse.g, stream);
@@ -232,13 +199,120 @@ void WriteBinaryMaterial(Gfx::Material material, std::ostream &stream)
/* emissive.a */ IOUtils::WriteBinaryFloat(0.0f, stream);
/* power */ IOUtils::WriteBinaryFloat(0.0f, stream);
+
+ return !stream.fail();
+}
+
+bool ReadTextMaterial(const std::string& text, Gfx::Material& material)
+{
+ std::stringstream stream;
+ stream.str(text);
+
+ std::string what;
+
+ stream >> what;
+ if (what != "dif")
+ return false;
+
+ stream >> material.diffuse.r
+ >> material.diffuse.g
+ >> material.diffuse.b
+ >> material.diffuse.a;
+
+ stream >> what;
+ if (what != "amb")
+ return false;
+
+ stream >> material.ambient.r
+ >> material.ambient.g
+ >> material.ambient.b
+ >> material.ambient.a;
+
+ stream >> what;
+ if (what != "spc")
+ return false;
+
+ stream >> material.specular.r
+ >> material.specular.g
+ >> material.specular.b
+ >> material.specular.a;
+
+ return !stream.fail();
+}
+
+bool WriteTextMaterial(const Gfx::Material& material, std::ostream& stream)
+{
+ stream << "dif " << material.diffuse.r
+ << " " << material.diffuse.g
+ << " " << material.diffuse.b
+ << " " << material.diffuse.a;
+
+ stream << " amb " << material.ambient.r
+ << " " << material.ambient.g
+ << " " << material.ambient.b
+ << " " << material.ambient.a;
+
+ stream << " spc " << material.specular.r
+ << " " << material.specular.g << " "
+ << material.specular.b << " "
+ << material.specular.a;
+
+ stream << std::endl;
+
+ return !stream.fail();
}
-Gfx::ModelTriangle::ModelTriangle()
+template<typename T>
+bool ReadLineValue(std::istream& stream, const std::string& prefix, T& value)
{
- min = 0.0f;
- max = 0.0f;
- state = 0L;
+ std::string line;
+ while (true)
+ {
+ if (stream.eof() || stream.fail())
+ return false;
+
+ std::getline(stream, line);
+ if (!line.empty() && line[0] != '#')
+ break;
+ }
+
+ std::stringstream s;
+ s.str(line);
+
+ std::string what;
+ s >> what;
+ if (what != prefix)
+ return false;
+
+ s >> value;
+
+ return true;
+}
+
+bool ReadLineString(std::istream& stream, const std::string& prefix, std::string& value)
+{
+ std::string line;
+ while (true)
+ {
+ if (stream.eof() || stream.fail())
+ return false;
+
+ std::getline(stream, line);
+ if (!line.empty() && line[0] != '#')
+ break;
+ }
+
+ std::stringstream s;
+ s.str(line);
+
+ std::string what;
+ s >> what;
+ if (what != prefix)
+ return false;
+
+ std::getline(s, value);
+
+ return true;
}
@@ -246,7 +320,9 @@ Gfx::CModelFile::CModelFile(CInstanceManager* iMan)
{
m_iMan = iMan;
+#ifndef MODELFILE_NO_ENGINE
m_engine = static_cast<CEngine*>(m_iMan->SearchInstance(CLASS_ENGINE));
+#endif
m_triangles.reserve(TRIANGLE_PREALLOCATE_COUNT);
}
@@ -255,71 +331,171 @@ Gfx::CModelFile::~CModelFile()
{
}
-std::string Gfx::CModelFile::GetError()
+
+/*******************************************************
+ Deprecated formats
+ *******************************************************/
+
+/**
+ * \struct OldModelHeader
+ * \brief Colobot binary model header info
+ *
+ * @deprecated
+ */
+struct OldModelHeader
{
- return m_error;
-}
+ //! Revision number
+ int revision;
+ //! Version number
+ int version;
+ //! Total number of triangles
+ int totalTriangles;
+ //! Reserved area
+ int reserved[10];
+
+ OldModelHeader()
+ {
+ memset(this, 0, sizeof(*this));
+ }
+};
+
+
+/**
+ * \struct OldModelTriangle1
+ * \brief Colobot binary model file version 1
+ *
+ * @deprecated
+ */
+struct OldModelTriangle1
+{
+ char used;
+ char selected;
+ Gfx::Vertex p1;
+ Gfx::Vertex p2;
+ Gfx::Vertex p3;
+ Gfx::Material material;
+ char texName[20];
+ float min;
+ float max;
+ OldModelTriangle1()
+ {
+ memset(this, 0, sizeof(*this));
+ }
+};
+
+/**
+ * \struct OldModelTriangle2
+ * \brief Colobot binary model file version 2
+ *
+ * @deprecated
+ */
+struct OldModelTriangle2
+{
+ char used;
+ char selected;
+ Gfx::Vertex p1;
+ Gfx::Vertex p2;
+ Gfx::Vertex p3;
+ Gfx::Material material;
+ char texName[20];
+ float min;
+ float max;
+ long state;
+ short reserved1;
+ short reserved2;
+ short reserved3;
+ short reserved4;
+ OldModelTriangle2()
+ {
+ memset(this, 0, sizeof(*this));
+ }
+};
+
+/**
+ * \struct OldModelTriangle3
+ * \brief Colobot binary model file version 3
+ *
+ * @deprecated
+ */
+struct OldModelTriangle3
+{
+ char used;
+ char selected;
+ Gfx::VertexTex2 p1;
+ Gfx::VertexTex2 p2;
+ Gfx::VertexTex2 p3;
+ Gfx::Material material;
+ char texName[20];
+ float min;
+ float max;
+ long state;
+ short texNum2;
+ short reserved2;
+ short reserved3;
+ short reserved4;
+
+ OldModelTriangle3()
+ {
+ memset(this, 0, sizeof(*this));
+ }
+};
-bool Gfx::CModelFile::ReadModel(const std::string &filename, bool edit, bool meta)
+bool Gfx::CModelFile::ReadModel(const std::string& fileName)
{
m_triangles.clear();
- m_error = "";
std::ifstream stream;
- stream.open(filename.c_str(), std::ios_base::in | std::ios_base::binary);
- if (! stream.good())
+ stream.open(fileName.c_str(), std::ios_base::in | std::ios_base::binary);
+ if (!stream.good())
{
- m_error = std::string("Could not open file '") + filename + std::string("'");
+ GetLogger()->Error("Could not open file '%s'\n", fileName.c_str());
return false;
}
- return ReadModel(stream, edit, meta);
+ return ReadModel(stream);
}
-bool Gfx::CModelFile::ReadModel(std::istream &stream, bool edit, bool meta)
+bool Gfx::CModelFile::ReadModel(std::istream& stream)
{
m_triangles.clear();
- m_error = "";
- // FIXME: for now, reading models only from files, not metafile
-
- ModelHeader header;
+ OldModelHeader header;
header.revision = IOUtils::ReadBinary<4, int>(stream);
header.version = IOUtils::ReadBinary<4, int>(stream);
- header.totalVertices = IOUtils::ReadBinary<4, int>(stream);
+ header.totalTriangles = IOUtils::ReadBinary<4, int>(stream);
for (int i = 0; i < 10; ++i)
header.reserved[i] = IOUtils::ReadBinary<4, int>(stream);
- if (! stream.good())
+ if (!stream.good())
{
- m_error = "Error reading model file header";
+ GetLogger()->Error("Error reading model file header\n");
return false;
}
// Old model version #1
if ( (header.revision == 1) && (header.version == 0) )
{
- for (int i = 0; i < header.totalVertices; ++i)
+ for (int i = 0; i < header.totalTriangles; ++i)
{
OldModelTriangle1 t;
t.used = IOUtils::ReadBinary<1, char>(stream);
t.selected = IOUtils::ReadBinary<1, char>(stream);
- t.p1 = ReadBinaryVertex(stream);
- t.p2 = ReadBinaryVertex(stream);
- t.p3 = ReadBinaryVertex(stream);
+ ReadBinaryVertex(stream, t.p1);
+ ReadBinaryVertex(stream, t.p2);
+ ReadBinaryVertex(stream, t.p3);
- t.material = ReadBinaryMaterial(stream);
+ ReadBinaryMaterial(stream, t.material);
stream.read(t.texName, 20);
t.min = IOUtils::ReadBinaryFloat(stream);
t.max = IOUtils::ReadBinaryFloat(stream);
- if (! stream.good())
+ if (stream.fail())
{
- m_error = "Error reading model data";
+ GetLogger()->Error("Error reading model data\n");
return false;
}
@@ -338,17 +514,17 @@ bool Gfx::CModelFile::ReadModel(std::istream &stream, bool edit, bool meta)
}
else if ( header.revision == 1 && header.version == 1 )
{
- for (int i = 0; i < header.totalVertices; ++i)
+ for (int i = 0; i < header.totalTriangles; ++i)
{
OldModelTriangle2 t;
t.used = IOUtils::ReadBinary<1, char>(stream);
t.selected = IOUtils::ReadBinary<1, char>(stream);
- t.p1 = ReadBinaryVertex(stream);
- t.p2 = ReadBinaryVertex(stream);
- t.p3 = ReadBinaryVertex(stream);
+ ReadBinaryVertex(stream, t.p1);
+ ReadBinaryVertex(stream, t.p2);
+ ReadBinaryVertex(stream, t.p3);
- t.material = ReadBinaryMaterial(stream);
+ ReadBinaryMaterial(stream, t.material);
stream.read(t.texName, 20);
t.min = IOUtils::ReadBinaryFloat(stream);
t.max = IOUtils::ReadBinaryFloat(stream);
@@ -359,9 +535,9 @@ bool Gfx::CModelFile::ReadModel(std::istream &stream, bool edit, bool meta)
t.reserved3 = IOUtils::ReadBinary<2, short>(stream);
t.reserved4 = IOUtils::ReadBinary<2, short>(stream);
- if (! stream.good())
+ if (stream.fail())
{
- m_error = "Error reading model data";
+ GetLogger()->Error("Error reading model data\n");
return false;
}
@@ -381,19 +557,19 @@ bool Gfx::CModelFile::ReadModel(std::istream &stream, bool edit, bool meta)
}
else
{
- for (int i = 0; i < header.totalVertices; ++i)
+ for (int i = 0; i < header.totalTriangles; ++i)
{
- NewModelTriangle t;
+ OldModelTriangle3 t;
t.used = IOUtils::ReadBinary<1, char>(stream);
t.selected = IOUtils::ReadBinary<1, char>(stream);
/* padding */ IOUtils::ReadBinary<2, unsigned int>(stream);
- t.p1 = ReadBinaryVertexTex2(stream);
- t.p2 = ReadBinaryVertexTex2(stream);
- t.p3 = ReadBinaryVertexTex2(stream);
+ ReadBinaryVertexTex2(stream, t.p1);
+ ReadBinaryVertexTex2(stream, t.p2);
+ ReadBinaryVertexTex2(stream, t.p3);
- t.material = ReadBinaryMaterial(stream);
+ ReadBinaryMaterial(stream, t.material);
stream.read(t.texName, 20);
t.min = IOUtils::ReadBinaryFloat(stream);
t.max = IOUtils::ReadBinaryFloat(stream);
@@ -404,9 +580,9 @@ bool Gfx::CModelFile::ReadModel(std::istream &stream, bool edit, bool meta)
t.reserved3 = IOUtils::ReadBinary<2, short>(stream);
t.reserved4 = IOUtils::ReadBinary<2, short>(stream);
- if (! stream.good())
+ if (stream.fail())
{
- m_error = "Error reading model data";
+ GetLogger()->Error("Error reading model data\n");
return false;
}
@@ -417,15 +593,26 @@ bool Gfx::CModelFile::ReadModel(std::istream &stream, bool edit, bool meta)
triangle.material = t.material;
triangle.tex1Name = std::string(t.texName);
- char tex2Name[20] = { 0 };
triangle.min = t.min;
triangle.max = t.max;
triangle.state = t.state;
+ triangle.variableTex2 = t.texNum2 == 1;
+
+ if (triangle.tex1Name == "plant.png")
+ triangle.state |= Gfx::ENG_RSTATE_ALPHA;
+
+ if (!triangle.variableTex2 && t.texNum2 != 0)
+ {
+ if (t.texNum2 >= 1 && t.texNum2 <= 10)
+ triangle.state |= Gfx::ENG_RSTATE_DUAL_BLACK;
- if (t.texNum2 != 0)
- sprintf(tex2Name, "dirty%.2d.tga", t.texNum2); // hardcoded as in the original code
+ if (t.texNum2 >= 11 && t.texNum2 <= 20)
+ triangle.state |= Gfx::ENG_RSTATE_DUAL_WHITE;
- triangle.tex2Name = std::string(tex2Name);
+ char tex2Name[20] = { 0 };
+ sprintf(tex2Name, "dirty%.2d.png", t.texNum2); // hardcoded as in original code
+ triangle.tex2Name = tex2Name;
+ }
m_triangles.push_back(triangle);
}
@@ -433,97 +620,70 @@ bool Gfx::CModelFile::ReadModel(std::istream &stream, bool edit, bool meta)
for (int i = 0; i < static_cast<int>( m_triangles.size() ); ++i)
{
- m_triangles[i].tex1Name = StrUtils::Replace(m_triangles[i].tex1Name, "bmp", "tga");
+ // All extensions are now png
+ m_triangles[i].tex1Name = StrUtils::Replace(m_triangles[i].tex1Name, "bmp", "png");
+ m_triangles[i].tex1Name = StrUtils::Replace(m_triangles[i].tex1Name, "tga", "png");
+
+ m_triangles[i].tex2Name = StrUtils::Replace(m_triangles[i].tex2Name, "bmp", "png");
+ m_triangles[i].tex2Name = StrUtils::Replace(m_triangles[i].tex2Name, "tga", "png");
- GetLogger()->Info("ModelTriangle %d\n", i+1);
+ GetLogger()->Trace("ModelTriangle %d\n", i+1);
std::string s1 = m_triangles[i].p1.ToString();
- GetLogger()->Info(" p1: %s\n", s1.c_str());
+ GetLogger()->Trace(" p1: %s\n", s1.c_str());
std::string s2 = m_triangles[i].p2.ToString();
- GetLogger()->Info(" p2: %s\n", s2.c_str());
+ GetLogger()->Trace(" p2: %s\n", s2.c_str());
std::string s3 = m_triangles[i].p3.ToString();
- GetLogger()->Info(" p3: %s\n", s3.c_str());
+ GetLogger()->Trace(" p3: %s\n", s3.c_str());
std::string d = m_triangles[i].material.diffuse.ToString();
std::string a = m_triangles[i].material.ambient.ToString();
std::string s = m_triangles[i].material.specular.ToString();
- GetLogger()->Info(" mat: d: %s a: %s s: %s\n", d.c_str(), a.c_str(), s.c_str());
+ GetLogger()->Trace(" mat: d: %s a: %s s: %s\n", d.c_str(), a.c_str(), s.c_str());
- GetLogger()->Info(" tex1: %s tex2: %s\n", m_triangles[i].tex1Name.c_str(), m_triangles[i].tex2Name.c_str());
- GetLogger()->Info(" min: %.2f max: %.2f\n", m_triangles[i].min, m_triangles[i].max);
- GetLogger()->Info(" state: %ld\n", m_triangles[i].state);
+ GetLogger()->Trace(" tex1: %s tex2: %s\n", m_triangles[i].tex1Name.c_str(),
+ m_triangles[i].variableTex2 ? "(variable)" : m_triangles[i].tex2Name.c_str());
+ GetLogger()->Trace(" min: %.2f max: %.2f\n", m_triangles[i].min, m_triangles[i].max);
+ GetLogger()->Trace(" state: %ld\n", m_triangles[i].state);
}
- /*
- if (! edit)
- {
- float limit[2];
- limit[0] = m_engine->RetLimitLOD(0); // frontier AB as config
- limit[1] = m_engine->RetLimitLOD(1); // frontier BC as config
-
- // Standard frontiers -> config.
- for (int i = 0; i < m_triangles.size(); ++i)
- {
- if ( m_triangles[i].min == 0.0f &&
- m_triangles[i].max == 100.0f ) // resolution A ?
- {
- m_triangles[i].max = limit[0];
- }
- else if ( m_triangles[i].min == 100.0f &&
- m_triangles[i].max == 200.0f ) // resolution B ?
- {
- m_triangles[i].min = limit[0];
- m_triangles[i].max = limit[1];
- }
- else if ( m_triangles[i].min == 200.0f &&
- m_triangles[i].max == 1000000.0f ) // resolution C ?
- {
- m_triangles[i].min = limit[1];
- }
- }
- }*/
-
return true;
}
-bool Gfx::CModelFile::WriteModel(const std::string &filename)
+bool Gfx::CModelFile::WriteModel(const std::string& fileName)
{
- m_error = "";
-
std::ofstream stream;
- stream.open(filename.c_str(), std::ios_base::out | std::ios_base::binary);
- if (! stream.good())
+ stream.open(fileName.c_str(), std::ios_base::out | std::ios_base::binary);
+ if (!stream.good())
{
- m_error = std::string("Could not open file '") + filename + std::string("'");
+ GetLogger()->Error("Could not open file '%s'\n", fileName.c_str());
return false;
}
return WriteModel(stream);
}
-bool Gfx::CModelFile::WriteModel(std::ostream &stream)
+bool Gfx::CModelFile::WriteModel(std::ostream& stream)
{
- m_error = "";
-
if (m_triangles.size() == 0)
{
- m_error = "Empty model";
+ GetLogger()->Error("Empty model\n");
return false;
}
- ModelHeader header;
+ OldModelHeader header;
header.revision = 1;
header.version = 2;
- header.totalVertices = m_triangles.size();
+ header.totalTriangles = m_triangles.size();
IOUtils::WriteBinary<4, int>(header.revision, stream);
IOUtils::WriteBinary<4, int>(header.version, stream);
- IOUtils::WriteBinary<4, int>(header.totalVertices, stream);
+ IOUtils::WriteBinary<4, int>(header.totalTriangles, stream);
for (int i = 0; i < 10; ++i)
IOUtils::WriteBinary<4, int>(header.reserved[i], stream);
for (int i = 0; i < static_cast<int>( m_triangles.size() ); ++i)
{
- NewModelTriangle t;
+ OldModelTriangle3 t;
t.used = true;
@@ -536,14 +696,21 @@ bool Gfx::CModelFile::WriteModel(std::ostream &stream)
t.min = m_triangles[i].min;
t.max = m_triangles[i].max;
t.state = m_triangles[i].state;
+
int no = 0;
- sscanf(m_triangles[i].tex2Name.c_str(), "dirty%d.tga", &no); // hardcoded as in the original code
+ if (m_triangles[i].variableTex2)
+ no = 1;
+ else
+ sscanf(m_triangles[i].tex2Name.c_str(), "dirty%d.png", &no); // hardcoded as in the original code
+
t.texNum2 = no;
IOUtils::WriteBinary<1, char>(t.used, stream);
IOUtils::WriteBinary<1, char>(t.selected, stream);
+ /* padding */ IOUtils::WriteBinary<2, unsigned int>(0, stream);
+
WriteBinaryVertexTex2(t.p1, stream);
WriteBinaryVertexTex2(t.p2, stream);
WriteBinaryVertexTex2(t.p3, stream);
@@ -563,215 +730,489 @@ bool Gfx::CModelFile::WriteModel(std::ostream &stream)
return true;
}
-bool Gfx::CModelFile::ReadDXF(const std::string &filename, float min, float max)
+
+/*******************************************************
+ New formats
+ *******************************************************/
+
+/**
+ * \struct NewModelHeader
+ * \brief Header for new binary model file
+ */
+struct NewModelHeader
{
- m_triangles.clear();
- m_error = "";
+ //! File version (1, 2, ...)
+ int version;
+ //! Total number of triangles
+ int totalTriangles;
+ NewModelHeader()
+ {
+ version = 0;
+ totalTriangles = 0;
+ }
+};
+
+/**
+ * \struct NewModelTriangle1
+ * \brief Triangle of new binary model file
+ *
+ * NOTE: at this time, it is identical to ModelTriangle struct, but it may change
+ * independently in the future.
+ */
+struct NewModelTriangle1
+{
+ //! 1st vertex
+ Gfx::VertexTex2 p1;
+ //! 2nd vertex
+ Gfx::VertexTex2 p2;
+ //! 3rd vertex
+ Gfx::VertexTex2 p3;
+ //! Material
+ Gfx::Material material;
+ //! Name of 1st texture
+ std::string tex1Name;
+ //! Name of 2nd texture
+ std::string tex2Name;
+ //! If true, 2nd texture will be taken from current engine setting
+ bool variableTex2;
+ //! Min LOD threshold
+ float min;
+ //! Max LOD threshold
+ float max;
+ //! Rendering state to be set
+ int state;
+
+ NewModelTriangle1()
+ {
+ variableTex2 = true;
+ min = max = 0.0f;
+ state = 0;
+ }
+};
+
+
+bool Gfx::CModelFile::ReadTextModel(const std::string& fileName)
+{
std::ifstream stream;
- stream.open(filename.c_str(), std::ios_base::in);
- if (! stream.good())
+ stream.open(fileName.c_str(), std::ios_base::in);
+ if (!stream.good())
{
- m_error = std::string("Couldn't open file '") + filename + std::string("'");
+ GetLogger()->Error("Could not open file '%s'\n", fileName.c_str());
return false;
}
- return ReadDXF(stream, min, max);
+ return ReadTextModel(stream);
}
-bool Gfx::CModelFile::ReadDXF(std::istream &stream, float min, float max)
+bool Gfx::CModelFile::ReadTextModel(std::istream& stream)
{
m_triangles.clear();
- m_error = "";
- if (! stream.good())
+ NewModelHeader header;
+
+ bool headOk = ReadLineValue<int>(stream, "version", header.version) &&
+ ReadLineValue<int>(stream, "total_triangles", header.totalTriangles);
+
+ if (!headOk || !stream.good())
{
- m_error = "Invalid stream";
+ GetLogger()->Error("Error reading model file header\n");
return false;
}
- // Input state
- bool waitNumVertex = false;
- bool waitNumFace = false;
- bool waitVertexX = false;
- bool waitVertexY = false;
- bool waitVertexZ = false;
- bool waitFaceX = false;
- bool waitFaceY = false;
- bool waitFaceZ = false;
-
- // Vertex array
- std::vector<Math::Vector> vertices;
- vertices.reserve(TRIANGLE_PREALLOCATE_COUNT);
-
- // Number of vertices & faces of the primitive to be read
- int vertexNum = 0, faceNum = 0;
- // Vertex coords
- Math::Vector coords;
- // Indexes of face (triangle) points
- int p1 = 0, p2 = 0, p3 = 0;
-
- // Input line
- std::string line;
- while (! stream.eof() )
+ // New model version 1
+ if (header.version == 1)
{
- // Read line with command
- std::getline(stream, line);
- int command = StrUtils::FromString<int>(line);
+ for (int i = 0; i < header.totalTriangles; ++i)
+ {
+ NewModelTriangle1 t;
+
+ std::string p1Text, p2Text, p3Text;
+ std::string matText;
+ char varTex2Ch = 0;
+
+ bool triOk = ReadLineString(stream, "p1", p1Text) &&
+ ReadTextVertexTex2(p1Text, t.p1) &&
+ ReadLineString(stream, "p2", p2Text) &&
+ ReadTextVertexTex2(p2Text, t.p2) &&
+ ReadLineString(stream, "p3", p3Text) &&
+ ReadTextVertexTex2(p3Text, t.p3) &&
+ ReadLineString(stream, "mat", matText) &&
+ ReadTextMaterial(matText, t.material) &&
+ ReadLineValue<std::string>(stream, "tex1", t.tex1Name) &&
+ ReadLineValue<std::string>(stream, "tex2", t.tex2Name) &&
+ ReadLineValue<char>(stream, "var_tex2", varTex2Ch) &&
+ ReadLineValue<float>(stream, "min", t.min) &&
+ ReadLineValue<float>(stream, "max", t.max) &&
+ ReadLineValue<int>(stream, "state", t.state);
+
+ if (!triOk || stream.fail())
+ {
+ GetLogger()->Error("Error reading model file header\n");
+ return false;
+ }
- // Read line with param
- std::getline(stream, line);
+ t.variableTex2 = varTex2Ch == 'Y';
- bool ok = true;
+ Gfx::ModelTriangle triangle;
+ triangle.p1 = t.p1;
+ triangle.p2 = t.p2;
+ triangle.p3 = t.p3;
+ triangle.material = t.material;
+ triangle.tex1Name = t.tex1Name;
+ triangle.tex2Name = t.tex2Name;
+ triangle.variableTex2 = t.variableTex2;
+ triangle.min = t.min;
+ triangle.max = t.max;
+ triangle.state = t.state;
- if (command == 66)
- {
- waitNumVertex = true;
- }
+ m_triangles.push_back(triangle);
- if ( command == 71 && waitNumVertex )
- {
- waitNumVertex = false;
- vertexNum = StrUtils::FromString<int>(line, &ok);
- waitNumFace = true;
+ continue;
}
+ }
+ else
+ {
+ GetLogger()->Error("Unknown model file version\n");
+ return false;
+ }
- if ( command == 72 && waitNumFace )
- {
- waitNumFace = false;
- faceNum = StrUtils::FromString<int>(line, &ok);
- waitVertexX = true;
- }
+ for (int i = 0; i < static_cast<int>( m_triangles.size() ); ++i)
+ {
+ GetLogger()->Trace("ModelTriangle %d\n", i+1);
+ std::string s1 = m_triangles[i].p1.ToString();
+ GetLogger()->Trace(" p1: %s\n", s1.c_str());
+ std::string s2 = m_triangles[i].p2.ToString();
+ GetLogger()->Trace(" p2: %s\n", s2.c_str());
+ std::string s3 = m_triangles[i].p3.ToString();
+ GetLogger()->Trace(" p3: %s\n", s3.c_str());
- if ( command == 10 && waitVertexX )
- {
- waitVertexX = false;
- coords.x = StrUtils::FromString<float>(line, &ok);
- waitVertexY = true;
- }
+ std::string d = m_triangles[i].material.diffuse.ToString();
+ std::string a = m_triangles[i].material.ambient.ToString();
+ std::string s = m_triangles[i].material.specular.ToString();
+ GetLogger()->Trace(" mat: d: %s a: %s s: %s\n", d.c_str(), a.c_str(), s.c_str());
+
+ GetLogger()->Trace(" tex1: %s tex2: %s\n", m_triangles[i].tex1Name.c_str(), m_triangles[i].tex2Name.c_str());
+ GetLogger()->Trace(" min: %.2f max: %.2f\n", m_triangles[i].min, m_triangles[i].max);
+ GetLogger()->Trace(" state: %ld\n", m_triangles[i].state);
+ }
+
+ return true;
+}
+
+bool Gfx::CModelFile::WriteTextModel(const std::string &fileName)
+{
+ std::ofstream stream;
+ stream.open(fileName.c_str(), std::ios_base::out);
+ if (!stream.good())
+ {
+ GetLogger()->Error("Could not open file '%s'\n", fileName.c_str());
+ return false;
+ }
- if ( command == 20 && waitVertexY )
+ return WriteTextModel(stream);
+}
+
+bool Gfx::CModelFile::WriteTextModel(std::ostream& stream)
+{
+ if (m_triangles.size() == 0)
+ {
+ GetLogger()->Error("Empty model\n");
+ return false;
+ }
+
+ NewModelHeader header;
+
+ header.version = 1;
+ header.totalTriangles = m_triangles.size();
+
+ stream << "# Colobot text model" << std::endl;
+ stream << std::endl;
+ stream << "### HEAD" << std::endl;
+ stream << "version " << header.version << std::endl;
+ stream << "total_triangles " << header.totalTriangles << std::endl;
+ stream << std::endl;
+ stream << "### TRIANGLES" << std::endl;
+
+ for (int i = 0; i < static_cast<int>( m_triangles.size() ); ++i)
+ {
+ NewModelTriangle1 t;
+
+ t.p1 = m_triangles[i].p1;
+ t.p2 = m_triangles[i].p2;
+ t.p3 = m_triangles[i].p3;
+ t.material = m_triangles[i].material;
+ t.tex1Name = m_triangles[i].tex1Name;
+ t.tex2Name = m_triangles[i].tex2Name;
+ t.variableTex2 = m_triangles[i].variableTex2;
+ t.min = m_triangles[i].min;
+ t.max = m_triangles[i].max;
+ t.state = m_triangles[i].state;
+
+ stream << "p1 ";
+ WriteTextVertexTex2(t.p1, stream);
+ stream << "p2 ";
+ WriteTextVertexTex2(t.p2, stream);
+ stream << "p3 ";
+ WriteTextVertexTex2(t.p3, stream);
+ stream << "mat ";
+ WriteTextMaterial(t.material, stream);
+
+ stream << "tex1 " << t.tex1Name << std::endl;
+ stream << "tex2 " << t.tex2Name << std::endl;
+ stream << "var_tex2 " << (t.variableTex2 ? 'Y' : 'N') << std::endl;
+ stream << "min " << t.min << std::endl;
+ stream << "max " << t.max << std::endl;
+ stream << "state " << t.state << std::endl;
+
+ stream << std::endl;
+
+ if (stream.fail())
{
- waitVertexY = false;
- coords.y = StrUtils::FromString<float>(line, &ok);
- waitVertexZ = true;
+ GetLogger()->Error("Error writing model file\n");
+ return false;
}
+ }
- if ( command == 30 && waitVertexZ )
+ return true;
+}
+
+bool Gfx::CModelFile::ReadBinaryModel(const std::string& fileName)
+{
+ std::ifstream stream;
+ stream.open(fileName.c_str(), std::ios_base::in | std::ios_base::binary);
+ if (!stream.good())
+ {
+ GetLogger()->Error("Could not open file '%s'\n", fileName.c_str());
+ return false;
+ }
+
+ return ReadBinaryModel(stream);
+}
+
+bool Gfx::CModelFile::ReadBinaryModel(std::istream& stream)
+{
+ m_triangles.clear();
+
+ NewModelHeader header;
+
+ header.version = IOUtils::ReadBinary<4, int>(stream);
+ header.totalTriangles = IOUtils::ReadBinary<4, int>(stream);
+
+ if (!stream.good())
+ {
+ GetLogger()->Error("Error reading model file header\n");
+ return false;
+ }
+
+ // New model version 1
+ if (header.version == 1)
+ {
+ for (int i = 0; i < header.totalTriangles; ++i)
{
- waitVertexZ = false;
- coords.z = StrUtils::FromString<float>(line, &ok);
+ NewModelTriangle1 t;
+
+ ReadBinaryVertexTex2(stream, t.p1);
+ ReadBinaryVertexTex2(stream, t.p2);
+ ReadBinaryVertexTex2(stream, t.p3);
+ ReadBinaryMaterial(stream, t.material);
+ t.tex1Name = IOUtils::ReadBinaryString<1>(stream);
+ t.tex2Name = IOUtils::ReadBinaryString<1>(stream);
+ t.variableTex2 = IOUtils::ReadBinaryBool(stream);
+ t.min = IOUtils::ReadBinaryFloat(stream);
+ t.max = IOUtils::ReadBinaryFloat(stream);
+ t.state = IOUtils::ReadBinary<4, unsigned int>(stream);
- vertexNum --;
- if ( vertexNum >= 0 )
- {
- Math::Vector p(coords.x, coords.z, coords.y); // permutation of Y and Z!
- vertices.push_back(p);
- waitVertexX = true;
- }
- else
+ if (stream.fail())
{
- waitFaceX = true;
+ GetLogger()->Error("Error reading model data\n");
+ return false;
}
- }
- if ( command == 71 && waitFaceX )
- {
- waitFaceX = false;
- p1 = StrUtils::FromString<int>(line, &ok);
- if ( p1 < 0 ) p1 = -p1;
- waitFaceY = true;
- }
+ Gfx::ModelTriangle triangle;
+ triangle.p1 = t.p1;
+ triangle.p2 = t.p2;
+ triangle.p3 = t.p3;
+ triangle.material = t.material;
+ triangle.tex1Name = t.tex1Name;
+ triangle.tex2Name = t.tex2Name;
+ triangle.variableTex2 = t.variableTex2;
+ triangle.min = t.min;
+ triangle.max = t.max;
+ triangle.state = t.state;
- if ( command == 72 && waitFaceY )
- {
- waitFaceY = false;
- p2 = StrUtils::FromString<int>(line, &ok);
- if ( p2 < 0 ) p2 = -p2;
- waitFaceZ = true;
+ m_triangles.push_back(triangle);
}
+ }
+ else
+ {
+ GetLogger()->Error("Unknown model file version\n");
+ return false;
+ }
- if ( command == 73 && waitFaceZ )
- {
- waitFaceZ = false;
- p3 = StrUtils::FromString<int>(line, &ok);
- if ( p3 < 0 ) p3 = -p3;
+ for (int i = 0; i < static_cast<int>( m_triangles.size() ); ++i)
+ {
+ GetLogger()->Trace("ModelTriangle %d\n", i+1);
+ std::string s1 = m_triangles[i].p1.ToString();
+ GetLogger()->Trace(" p1: %s\n", s1.c_str());
+ std::string s2 = m_triangles[i].p2.ToString();
+ GetLogger()->Trace(" p2: %s\n", s2.c_str());
+ std::string s3 = m_triangles[i].p3.ToString();
+ GetLogger()->Trace(" p3: %s\n", s3.c_str());
- faceNum --;
- if ( faceNum >= 0 )
- {
- assert( (p1-1 >= 0) && (p1-1 < static_cast<int>(vertices.size())) );
- assert( (p2-1 >= 0) && (p2-1 < static_cast<int>(vertices.size())) );
- assert( (p3-1 >= 0) && (p3-1 < static_cast<int>(vertices.size())) );
+ std::string d = m_triangles[i].material.diffuse.ToString();
+ std::string a = m_triangles[i].material.ambient.ToString();
+ std::string s = m_triangles[i].material.specular.ToString();
+ GetLogger()->Trace(" mat: d: %s a: %s s: %s\n", d.c_str(), a.c_str(), s.c_str());
- CreateTriangle(vertices[p3-1], vertices[p2-1], vertices[p1-1], min, max);
- waitFaceX = true;
- }
- }
+ GetLogger()->Trace(" tex1: %s tex2: %s\n", m_triangles[i].tex1Name.c_str(), m_triangles[i].tex2Name.c_str());
+ GetLogger()->Trace(" min: %.2f max: %.2f\n", m_triangles[i].min, m_triangles[i].max);
+ GetLogger()->Trace(" state: %ld\n", m_triangles[i].state);
+ }
- if (! ok)
+ return true;
+}
+
+bool Gfx::CModelFile::WriteBinaryModel(const std::string& fileName)
+{
+ std::ofstream stream;
+ stream.open(fileName.c_str(), std::ios_base::out | std::ios_base::binary);
+ if (!stream.good())
+ {
+ GetLogger()->Error("Could not open file '%s'\n", fileName.c_str());
+ return false;
+ }
+
+ return WriteBinaryModel(stream);
+}
+
+bool Gfx::CModelFile::WriteBinaryModel(std::ostream& stream)
+{
+ if (m_triangles.size() == 0)
+ {
+ GetLogger()->Error("Empty model\n");
+ return false;
+ }
+
+ NewModelHeader header;
+
+ header.version = 1;
+ header.totalTriangles = m_triangles.size();
+
+ IOUtils::WriteBinary<4, int>(header.version, stream);
+ IOUtils::WriteBinary<4, int>(header.totalTriangles, stream);
+
+ for (int i = 0; i < static_cast<int>( m_triangles.size() ); ++i)
+ {
+ NewModelTriangle1 t;
+
+ t.p1 = m_triangles[i].p1;
+ t.p2 = m_triangles[i].p2;
+ t.p3 = m_triangles[i].p3;
+ t.material = m_triangles[i].material;
+ t.tex1Name = m_triangles[i].tex1Name;
+ t.tex2Name = m_triangles[i].tex2Name;
+ t.variableTex2 = m_triangles[i].variableTex2;
+ t.min = m_triangles[i].min;
+ t.max = m_triangles[i].max;
+ t.state = m_triangles[i].state;
+
+ WriteBinaryVertexTex2(t.p1, stream);
+ WriteBinaryVertexTex2(t.p2, stream);
+ WriteBinaryVertexTex2(t.p3, stream);
+ WriteBinaryMaterial(t.material, stream);
+ IOUtils::WriteBinaryString<1>(t.tex1Name, stream);
+ IOUtils::WriteBinaryString<1>(t.tex2Name, stream);
+ IOUtils::WriteBinaryBool(t.variableTex2, stream);
+ IOUtils::WriteBinaryFloat(t.min, stream);
+ IOUtils::WriteBinaryFloat(t.max, stream);
+ IOUtils::WriteBinary<4, unsigned int>(t.state, stream);
+
+ if (stream.fail())
{
- m_error = "Error reading data";
+ GetLogger()->Error("Error writing model file\n");
return false;
}
-
}
return true;
}
-bool Gfx::CModelFile::CreateEngineObject(int objRank, int addState)
+
+/*******************************************************
+ Other stuff
+ *******************************************************/
+
+#ifndef MODELFILE_NO_ENGINE
+
+bool Gfx::CModelFile::CreateEngineObject(int objRank)
{
+ std::vector<Gfx::VertexTex2> vs(3, Gfx::VertexTex2());
+
+ float limit[2];
+ limit[0] = m_engine->GetLimitLOD(0); // frontier AB as config
+ limit[1] = m_engine->GetLimitLOD(1); // frontier BC as config
+
for (int i = 0; i < static_cast<int>( m_triangles.size() ); i++)
{
- int state = m_triangles[i].state;
+ // TODO move this to CEngine
- /* TODO ???
- if (texName1 == "plant.png")
- state |= Gfx::ENG_RSTATE_ALPHA;
+ float min = m_triangles[i].min;
+ float max = m_triangles[i].max;
- if (m_triangles[i].tex2Name.empty())
+ // Standard frontiers -> config
+ if (min == 0.0f && max == 100.0f) // resolution A ?
+ {
+ max = limit[0];
+ }
+ else if (min == 100.0f && max == 200.0f) // resolution B ?
{
- int texNum = 0;
+ min = limit[0];
+ max = limit[1];
+ }
+ else if (min == 200.0f && max == 1000000.0f) // resolution C ?
+ {
+ min = limit[1];
+ }
- if ( m_triangles[i].texNum2 == 1 )
- {
- texNum = m_engine->RetSecondTexture();
- }
- else
- {
- texNum = m_triangles[i].texNum2;
- }
+ int state = m_triangles[i].state;
+ std::string tex2Name = m_triangles[i].tex2Name;
- if ( texNum >= 1 && texNum <= 10 )
- {
- state |= D3DSTATEDUALb;
- }
- if ( texNum >= 11 && texNum <= 20 )
- {
- state |= D3DSTATEDUALw;
- }
- sprintf(texName2, "dirty%.2d.tga", texNum); // ???
- }*/
+ if (m_triangles[i].variableTex2)
+ {
+ int texNum = m_engine->GetSecondTexture();
- std::vector<Gfx::VertexTex2> vs;
- vs.push_back(m_triangles[i].p1);
- vs.push_back(m_triangles[i].p2);
- vs.push_back(m_triangles[i].p3);
+ if (texNum >= 1 && texNum <= 10)
+ state |= Gfx::ENG_RSTATE_DUAL_BLACK;
- m_engine->AddTriangles(objRank, vs,
- m_triangles[i].material,
- state + addState,
- m_triangles[i].tex1Name,
- m_triangles[i].tex2Name,
- m_triangles[i].min,
- m_triangles[i].max, false);
+ if (texNum >= 11 && texNum <= 20)
+ state |= Gfx::ENG_RSTATE_DUAL_WHITE;
+
+ char name[20] = { 0 };
+ sprintf(name, "dirty%.2d.png", texNum);
+ tex2Name = name;
+ }
+
+ vs[0] = m_triangles[i].p1;
+ vs[1] = m_triangles[i].p2;
+ vs[2] = m_triangles[i].p3;
+
+ bool ok = m_engine->AddTriangles(objRank, vs,
+ m_triangles[i].material,
+ state,
+ m_triangles[i].tex1Name,
+ tex2Name,
+ min, max, false);
+ if (!ok)
+ return false;
}
return true;
}
+#endif
+
void Gfx::CModelFile::Mirror()
{
for (int i = 0; i < static_cast<int>( m_triangles.size() ); i++)
@@ -790,7 +1231,7 @@ void Gfx::CModelFile::Mirror()
}
}
-std::vector<Gfx::ModelTriangle>& Gfx::CModelFile::GetTriangles()
+const std::vector<Gfx::ModelTriangle>& Gfx::CModelFile::GetTriangles()
{
return m_triangles;
}
diff --git a/src/graphics/engine/modelfile.h b/src/graphics/engine/modelfile.h
index fab190f..833cdf6 100644
--- a/src/graphics/engine/modelfile.h
+++ b/src/graphics/engine/modelfile.h
@@ -20,7 +20,6 @@
* \brief Model loading - Gfx::CModelFile class (aka modfile)
*/
-#include "graphics/engine/engine.h"
#include "graphics/core/vertex.h"
#include "graphics/core/material.h"
#include "math/vector.h"
@@ -35,6 +34,9 @@ class CInstanceManager;
namespace Gfx {
+class CEngine;
+
+
/**
\struct ModelTriangle
\brief Triangle of a 3D model
@@ -53,14 +55,21 @@ struct ModelTriangle
std::string tex1Name;
//! Name of 2nd texture
std::string tex2Name;
+ //! If true, 2nd texture will be taken from current engine setting
+ bool variableTex2;
//! Min LOD threshold
float min;
//! Max LOD threshold
float max;
//! Rendering state to be set
- long state;
-
- ModelTriangle();
+ int state;
+
+ ModelTriangle()
+ {
+ variableTex2 = true;
+ min = max = 0.0f;
+ state = 0;
+ }
};
@@ -75,27 +84,45 @@ public:
CModelFile(CInstanceManager* iMan);
~CModelFile();
- //! Returns the last error encountered
- std::string GetError();
+ //! Reads a model in text format from file
+ bool ReadTextModel(const std::string &fileName);
+ //! Reads a model in text format from stream
+ bool ReadTextModel(std::istream &stream);
+
+ //! Writes the model in text format to a file
+ bool WriteTextModel(const std::string &fileName);
+ //! Writes the model in text format to a stream
+ bool WriteTextModel(std::ostream &stream);
+
+ //! Reads a model in new binary format from file
+ bool ReadBinaryModel(const std::string &fileName);
+ //! Reads a model in new binary format from stream
+ bool ReadBinaryModel(std::istream &stream);
+
+ //! Writes the model in binary format to a file
+ bool WriteBinaryModel(const std::string &fileName);
+ //! Writes the model in binary format to a stream
+ bool WriteBinaryModel(std::ostream &stream);
//! Reads a binary Colobot model from file
- bool ReadModel(const std::string &filename, bool edit = false, bool meta = true);
+ //! @deprecated
+ bool ReadModel(const std::string &fileName);
//! Reads a binary Colobot model from stream
- bool ReadModel(std::istream &stream, bool edit = false, bool meta = true);
+ //! @deprecated
+ bool ReadModel(std::istream &stream);
//! Writes the model to Colobot binary model file
- bool WriteModel(const std::string &filename);
+ //! @deprecated
+ bool WriteModel(const std::string &fileName);
//! Writes the model to Colobot binary model file
+ //! @deprecated
bool WriteModel(std::ostream &stream);
- //! Reads a DXF model from file
- bool ReadDXF(const std::string &filename, float min, float max);
- //! Reads a DXF model from stream
- bool ReadDXF(std::istream &stream, float min, float max);
-
//! Returns the number of triangles in model
int GetTriangleCount();
+
//! Returns the triangle vector
- std::vector<Gfx::ModelTriangle>& GetTriangles();
+ const std::vector<Gfx::ModelTriangle>& GetTriangles();
+
//! Returns the height of model -- closest point to X and Z coords of \a pos
float GetHeight(Math::Vector pos);
@@ -103,7 +130,7 @@ public:
void Mirror();
//! Creates an object in the graphics engine from the model
- bool CreateEngineObject(int objRank, int addState = 0);
+ bool CreateEngineObject(int objRank);
protected:
//! Adds a triangle to the list
@@ -113,9 +140,6 @@ protected:
CInstanceManager* m_iMan;
Gfx::CEngine* m_engine;
- //! Last error
- std::string m_error;
-
//! Model triangles
std::vector<Gfx::ModelTriangle> m_triangles;
};
diff --git a/src/graphics/engine/terrain.cpp b/src/graphics/engine/terrain.cpp
index 6b26281..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<Gfx::CEngine*>( m_iMan->SearchInstance(CLASS_ENGINE) );
m_water = static_cast<Gfx::CWater*>( 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<float>(dim).swap(m_relief);
- dim = m_mosaic*m_subdivMapping*m_mosaic*m_subdivMapping;
- std::vector<int>(dim).swap(m_texture);
+ dim = m_mosaicCount*m_textureSubdivCount*m_mosaicCount*m_textureSubdivCount;
+ std::vector<int>(dim).swap(m_textures);
- dim = m_mosaic*m_mosaic;
- std::vector<int>(dim).swap(m_objRank);
+ dim = m_mosaicCount*m_mosaicCount;
+ std::vector<int>(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, 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();
@@ -241,8 +209,13 @@ bool Gfx::CTerrain::ResFromPNG(const std::string& fileName)
(data->surface->format->BytesPerPixel != 3) )
return false;
- // Assuming the data format is compatible
- memcpy(&m_resources[0], data->surface->pixels, 3*size*size);
+ unsigned char* pixels = static_cast<unsigned char*>(data->surface->pixels);
+ int pitch = data->surface->pitch;
+
+ for (int y = 0; y < size; y++)
+ {
+ memcpy(&m_resources[3*size*y], &pixels[pitch*y], 3*size);
+ }
return true;
}
@@ -252,14 +225,14 @@ Gfx::TerrainRes Gfx::CTerrain::GetResource(const Math::Vector &p)
if (m_resources.empty())
return Gfx::TR_NULL;
- int x = static_cast<int>((p.x + (m_mosaic*m_brick*m_size)/2.0f)/m_size);
- int y = static_cast<int>((p.z + (m_mosaic*m_brick*m_size)/2.0f)/m_size);
+ int x = static_cast<int>((p.x + (m_mosaicCount*m_brickCount*m_brickSize)/2.0f)/m_brickSize);
+ int y = static_cast<int>((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];
@@ -284,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;
@@ -307,20 +270,21 @@ 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) )
return false;
unsigned char* pixels = static_cast<unsigned char*>(data->surface->pixels);
+ int pitch = data->surface->pitch;
float limit = 0.9f;
for (int y = 0; y < size; y++)
{
for (int x = 0; x < size; x++)
{
- float level = (255 - pixels[3*x+3*size*(size-y-1)]) * scaleRelief;
+ float level = (255 - pixels[3*x+pitch*(size-y-1)]) * scaleRelief;
float dist = Math::Max(fabs(static_cast<float>(x-size/2)),
fabs(static_cast<float>(y-size/2)));
@@ -340,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<int>(pos.x);
int y = static_cast<int>(pos.z);
@@ -360,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];
@@ -397,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];
@@ -408,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];
@@ -419,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];
@@ -435,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
{
@@ -452,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
@@ -481,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);
@@ -502,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;
}
@@ -539,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);
@@ -549,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 (*)
@@ -559,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();
}
@@ -597,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)
{
@@ -635,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;
@@ -650,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<float>(ox%5)*m_brick+xx+0.0f)/(m_brick*5);
- p1.texCoord2.y = (static_cast<float>(oy%5)*m_brick+yy+0.0f)/(m_brick*5);
- p2.texCoord2.x = (static_cast<float>(ox%5)*m_brick+xx+0.0f)/(m_brick*5);
- p2.texCoord2.y = (static_cast<float>(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<float>(ox%5)*m_brickCount+xx+0.0f)/(m_brickCount*5);
+ p1.texCoord2.y = (static_cast<float>(oy%5)*m_brickCount+yy+0.0f)/(m_brickCount*5);
+ p2.texCoord2.x = (static_cast<float>(ox%5)*m_brickCount+xx+0.0f)/(m_brickCount*5);
+ p2.texCoord2.y = (static_cast<float>(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:
@@ -693,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<int>( m_levelMats.size() ); i++)
+ for (int i = 0; i < static_cast<int>( 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;
@@ -736,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)
@@ -776,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<int>( m_levelMats.size() ); i++)
+ for (int i = 0; i < static_cast<int>( 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] ||
@@ -802,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] =
{
@@ -1124,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<int>((center.x+dim)/m_size);
- int yy = static_cast<int>((center.z+dim)/m_size);
+ int xx = static_cast<int>((center.x+dim)/m_brickSize);
+ int yy = static_cast<int>((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<float>(x)-m_levelDotSize/2.0f)*group*m_size;
- pos.z = (static_cast<float>(y)-m_levelDotSize/2.0f)*group*m_size;
+ pos.x = (static_cast<float>(x)-m_materialPointCount/2.0f)*group*m_brickSize;
+ pos.z = (static_cast<float>(y)-m_materialPointCount/2.0f)*group*m_brickSize;
if (Math::DistanceProjected(pos, center) > radius) continue;
}
@@ -1170,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]);
}
}
}
@@ -1183,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<Gfx::DotLevel>(m_levelDotSize*m_levelDotSize).swap(m_levelDots);
+ m_materialPointCount = (m_mosaicCount*m_brickCount)/(m_brickCount/m_textureSubdivCount)+1;
+ std::vector<Gfx::TerrainMaterialPoint>(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++)
{
- 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
- {
- 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;
@@ -1251,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<int>((p1.x+dim+m_size/2.0f)/m_size);
- tp1.y = static_cast<int>((p1.z+dim+m_size/2.0f)/m_size);
- tp2.x = static_cast<int>((p2.x+dim+m_size/2.0f)/m_size);
- tp2.y = static_cast<int>((p2.z+dim+m_size/2.0f)/m_size);
+ tp1.x = static_cast<int>((p1.x+dim+m_brickSize/2.0f)/m_brickSize);
+ tp1.y = static_cast<int>((p1.z+dim+m_brickSize/2.0f)/m_brickSize);
+ tp2.x = static_cast<int>((p2.x+dim+m_brickSize/2.0f)/m_brickSize);
+ tp2.y = static_cast<int>((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;
@@ -1295,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;
@@ -1311,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();
@@ -1355,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<int>((pos.x+dim)/m_size);
- int y = static_cast<int>((pos.z+dim)/m_size);
+ int x = static_cast<int>((pos.x+dim)/m_brickSize);
+ int y = static_cast<int>((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<int>((p.x+dim)/m_size);
- int y = static_cast<int>((p.z+dim)/m_size);
+ int x = static_cast<int>((p.x+dim)/m_brickSize);
+ int y = static_cast<int>((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);
@@ -1400,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<int>((p.x+dim)/m_size);
- int y = static_cast<int>((p.z+dim)/m_size);
+ int x = static_cast<int>((pos.x+dim)/m_brickSize);
+ int y = static_cast<int>((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;
}
@@ -1436,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<int>((p.x+dim)/m_size);
- int y = static_cast<int>((p.z+dim)/m_size);
+ int x = static_cast<int>((pos.x+dim)/m_brickSize);
+ int y = static_cast<int>((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;
}
@@ -1468,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<int>((p.x + dim) / m_size);
- int y = static_cast<int>((p.z + dim) / m_size);
+ int x = static_cast<int>((pos.x + dim) / m_brickSize);
+ int y = static_cast<int>((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;
}
@@ -1664,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<int>((p.x+dim)/m_size);
- y = static_cast<int>((p.z+dim)/m_size);
+ x = static_cast<int>((p.x+dim)/m_brickSize);
+ y = static_cast<int>((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++)
{
@@ -1713,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;
@@ -1735,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 24bd1f9..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, 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<float> m_relief;
- //! Table of textures
- std::vector<int> m_texture;
- //! Table of rows of objects
- std::vector<int> m_objRank;
- //! Table of resources
+ //! Resources data
std::vector<unsigned char> m_resources;
- bool m_multiText;
- bool m_levelText;
- //! Scale of the mapping
- float m_scaleMapping;
+ //! Texture indices
+ std::vector<int> m_textures;
+ //! Object ranks for mosaic objects
+ 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;
- 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<TerrainMaterial> m_levelMats;
- std::vector<Gfx::DotLevel> 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<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;
diff --git a/src/graphics/engine/test/CMakeLists.txt b/src/graphics/engine/test/CMakeLists.txt
index bd83773..4e3263b 100644
--- a/src/graphics/engine/test/CMakeLists.txt
+++ b/src/graphics/engine/test/CMakeLists.txt
@@ -1,7 +1,26 @@
cmake_minimum_required(VERSION 2.8)
set(CMAKE_BUILD_TYPE debug)
-set(CMAKE_CXX_FLAGS_DEBUG "-Wall -g -O0")
+set(CMAKE_CXX_FLAGS_DEBUG "-g -O0 -Wall -Wold-style-cast -std=gnu++0x")
-include_directories(. ../../..)
-add_executable(modelfile_test modelfile_test.cpp ../modelfile.cpp ../../../common/logger.cpp ../../../common/stringutils.cpp ../../../common/iman.cpp)
+set(MODELFILE_TEST_SOURCES
+modelfile_test.cpp
+../modelfile.cpp
+../../../common/logger.cpp
+../../../common/stringutils.cpp
+../../../common/iman.cpp
+)
+
+add_definitions(-DMODELFILE_NO_ENGINE)
+
+include_directories(
+.
+../../..
+${GTEST_DIR}/include
+)
+
+add_executable(modelfile_test ${MODELFILE_TEST_SOURCES})
+
+target_link_libraries(modelfile_test gtest)
+
+add_test(modelfile_test modelfile_test)
diff --git a/src/graphics/engine/test/modelfile_test.cpp b/src/graphics/engine/test/modelfile_test.cpp
index f7ed87f..6879a1b 100644
--- a/src/graphics/engine/test/modelfile_test.cpp
+++ b/src/graphics/engine/test/modelfile_test.cpp
@@ -1,48 +1,273 @@
-#include "graphics/engine/modelfile.h"
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2012, Polish Portal of Colobot (PPC)
+// *
+// * This program is free software: you can redistribute it and/or modify
+// * it under the terms of the GNU General Public License as published by
+// * the Free Software Foundation, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * This program is distributed in the hope that it will be useful,
+// * but WITHOUT ANY WARRANTY; without even the implied warranty of
+// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// * GNU General Public License for more details.
+// *
+// * You should have received a copy of the GNU General Public License
+// * along with this program. If not, see http://www.gnu.org/licenses/.
+
+
#include "common/iman.h"
+#include "common/logger.h"
+#include "graphics/engine/modelfile.h"
+#include "math/func.h"
+
+#include "gtest/gtest.h"
+
+#include <cassert>
+#include <sstream>
+
+/* Test model file (new text format) */
+const char* const TEXT_MODEL =
+"# Colobot text model\n"
+"\n"
+"### HEAD\n"
+"version 1\n"
+"total_triangles 2\n"
+"\n"
+"### TRIANGLES\n"
+"p1 c -12.4099 10.0016 -2.54558 n 1 -0 1.87319e-07 t1 0.970703 0.751953 t2 0 0\n"
+"p2 c -12.4099 10.0016 2.54558 n 1 -0 1.87319e-07 t1 0.998047 0.751953 t2 0 0\n"
+"p3 c -12.4099 4.00165 -2.54558 n 1 -0 1.87319e-07 t1 0.970703 0.998047 t2 0 0\n"
+"mat dif 1 1 1 0 amb 0.5 0.5 0.5 0 spc 0 0 0 0\n"
+"tex1 lemt.png\n"
+"tex2\n"
+"var_tex2 N\n"
+"min 200\n"
+"max 1e+06\n"
+"state 1024\n"
+"\n"
+"p1 c -19 -1 4 n -1 0 0 t1 0.248047 0.123047 t2 0.905224 0.52067\n"
+"p2 c -19 4 4 n -1 0 0 t1 0.248047 0.00195312 t2 0.905224 0.614223\n"
+"p3 c -19 4 -4 n -1 0 0 t1 0.00195312 0.00195312 t2 0.0947756 0.614223\n"
+"mat dif 1 1 1 0 amb 0.5 0.5 0.5 0 spc 0 0 0 0\n"
+"tex1 derrick.png\n"
+"tex2\n"
+"var_tex2 Y\n"
+"min 200\n"
+"max 1e+06\n"
+"state 0\n"
+"";
+
+// Triangles as defined in model file
+Gfx::ModelTriangle TRIANGLE_1;
+Gfx::ModelTriangle TRIANGLE_2;
+
+// Sets triangle data
+void Init()
+{
+
+ TRIANGLE_1.p1 = Gfx::VertexTex2(Math::Vector(-12.4099, 10.0016, -2.54558),
+ Math::Vector(1, 0, 1.87319e-07),
+ Math::Point(0.970703, 0.751953),
+ Math::Point(0, 0));
+ TRIANGLE_1.p2 = Gfx::VertexTex2(Math::Vector(-12.4099, 10.0016, 2.54558),
+ Math::Vector(1, 0, 1.87319e-07),
+ Math::Point(0.998047, 0.751953),
+ Math::Point(0, 0));
+ TRIANGLE_1.p3 = Gfx::VertexTex2(Math::Vector(-12.4099, 4.00165, -2.54558),
+ Math::Vector(1, 0, 1.87319e-07),
+ Math::Point(0.970703, 0.998047),
+ Math::Point(0, 0));
+ TRIANGLE_1.material.diffuse = Gfx::Color(1, 1, 1, 0);
+ TRIANGLE_1.material.ambient = Gfx::Color(0.5, 0.5, 0.5, 0);
+ TRIANGLE_1.material.specular = Gfx::Color(0, 0, 0, 0);
+ TRIANGLE_1.tex1Name = "lemt.png";
+ TRIANGLE_1.variableTex2 = false;
+ TRIANGLE_1.min = 200.0f;
+ TRIANGLE_1.max = 1e+06f;
+ TRIANGLE_1.state = 1024;
+
+ TRIANGLE_2.p1 = Gfx::VertexTex2(Math::Vector(-19, -1, 4),
+ Math::Vector(-1, 0, 0),
+ Math::Point(0.248047, 0.123047),
+ Math::Point(0.905224, 0.52067));
+ TRIANGLE_2.p2 = Gfx::VertexTex2(Math::Vector(-19, 4, 4),
+ Math::Vector(-1, 0, 0),
+ Math::Point(0.248047, 0.00195312),
+ Math::Point(0.905224, 0.614223));
+ TRIANGLE_2.p3 = Gfx::VertexTex2(Math::Vector(-19, 4, -4),
+ Math::Vector(-1, 0, 0),
+ Math::Point(0.00195312, 0.00195312),
+ Math::Point(0.0947756, 0.614223));
+ TRIANGLE_2.material.diffuse = Gfx::Color(1, 1, 1, 0);
+ TRIANGLE_2.material.ambient = Gfx::Color(0.5, 0.5, 0.5, 0);
+ TRIANGLE_2.material.specular = Gfx::Color(0, 0, 0, 0);
+ TRIANGLE_2.tex1Name = "derrick.png";
+ TRIANGLE_2.variableTex2 = true;
+ TRIANGLE_2.min = 200.0f;
+ TRIANGLE_2.max = 1e+06f;
+ TRIANGLE_2.state = 0;
+}
+
+
+// Compares vertices (within Math::TOLERANCE)
+bool CompareVertices(const Gfx::VertexTex2& v1, const Gfx::VertexTex2& v2)
+{
+ if ( !( Math::IsEqual(v1.coord.x, v2.coord.x) &&
+ Math::IsEqual(v1.coord.y, v2.coord.y) &&
+ Math::IsEqual(v1.coord.z, v2.coord.z) ) )
+ return false;
+
+ if ( !( Math::IsEqual(v1.normal.x, v2.normal.x) &&
+ Math::IsEqual(v1.normal.y, v2.normal.y) &&
+ Math::IsEqual(v1.normal.z, v2.normal.z) ) )
+ return false;
-#include <iostream>
+ if ( !( Math::IsEqual(v1.texCoord.x, v2.texCoord.x) &&
+ Math::IsEqual(v1.texCoord.y, v2.texCoord.y) ) )
+ return false;
+ if ( !( Math::IsEqual(v1.texCoord2.x, v2.texCoord2.x) &&
+ Math::IsEqual(v1.texCoord2.y, v2.texCoord2.y) ) )
+ return false;
-int main(int argc, char *argv[])
+ return true;
+}
+
+// Compares colors (within Math::TOLERANCE)
+bool CompareColors(const Gfx::Color& c1, const Gfx::Color& c2)
+{
+ return Math::IsEqual(c1.r, c2.r) &&
+ Math::IsEqual(c1.g, c2.g) &&
+ Math::IsEqual(c1.b, c2.b) &&
+ Math::IsEqual(c1.a, c2.a);
+}
+
+// Compares model triangles (within Math::TOLERANCE)
+bool CompareTriangles(const Gfx::ModelTriangle& t1, const Gfx::ModelTriangle& t2)
{
- if (argc != 4)
- {
- std::cerr << "Usage: " << argv[0] << " {mod|dxf} in_file out_file" << std::endl;
- return 1;
- }
+ if (! CompareVertices(t1.p1, t2.p1))
+ return false;
+
+ if (! CompareVertices(t1.p2, t2.p2))
+ return false;
+
+ if (! CompareVertices(t1.p3, t2.p3))
+ return false;
+
+ if (! CompareColors(t1.material.diffuse, t2.material.diffuse))
+ return false;
+
+ if (! CompareColors(t1.material.ambient, t2.material.ambient))
+ return false;
+
+ if (! CompareColors(t1.material.specular, t2.material.specular))
+ return false;
+
+ if (t1.tex1Name != t2.tex1Name)
+ return false;
+
+ if (t1.tex2Name != t2.tex2Name)
+ return false;
+
+ if (t1.variableTex2 != t2.variableTex2)
+ return false;
+
+ if (!Math::IsEqual(t1.min, t2.min))
+ return false;
+
+ if (!Math::IsEqual(t1.max, t2.max))
+ return false;
+
+ if (t1.state != t2.state)
+ return false;
+
+ return true;
+}
+
+// Tests reading/writing new text model file
+TEST(ModelFileTest, RWTxtModel)
+{
+ std::stringstream str;
+ str.str(TEXT_MODEL);
CInstanceManager iMan;
- Gfx::CModelFile modfile(&iMan);
-
- std::string mode(argv[1]);
- if (mode == "mod")
- {
- if (! modfile.ReadModel(argv[2], false, false) )
- {
- std::cerr << "Read error: " << modfile.GetError() << std::endl;
- return 2;
- }
- }
- else if (mode == "dxf")
- {
- if (! modfile.ReadDXF(argv[2], false, false) )
- {
- std::cerr << "Read error: " << modfile.GetError() << std::endl;
- return 2;
- }
- }
- else
- {
- std::cerr << "Usage: " << argv[0] << " {mod|dxf} in_file out_file" << std::endl;
- return 1;
- }
-
- if (! modfile.WriteModel(argv[3]) )
- {
- std::cerr << "Write error: " << modfile.GetError() << std::endl;
- return 3;
- }
-
- return 0;
+ Gfx::CModelFile modelFile(&iMan);
+
+ EXPECT_TRUE(modelFile.ReadTextModel(str));
+
+ EXPECT_EQ(modelFile.GetTriangleCount(), 2);
+ EXPECT_TRUE(CompareTriangles(modelFile.GetTriangles()[0], TRIANGLE_1));
+ EXPECT_TRUE(CompareTriangles(modelFile.GetTriangles()[1], TRIANGLE_2));
+
+ str.str("");
+
+ EXPECT_TRUE(modelFile.WriteTextModel(str));
+ str.seekg(0);
+ EXPECT_TRUE(modelFile.ReadTextModel(str));
+
+ EXPECT_EQ(modelFile.GetTriangleCount(), 2);
+ EXPECT_TRUE(CompareTriangles(modelFile.GetTriangles()[0], TRIANGLE_1));
+ EXPECT_TRUE(CompareTriangles(modelFile.GetTriangles()[1], TRIANGLE_2));
+}
+
+// Tests reading/writing new binary model
+TEST(ModelFileTest, RWBinModel)
+{
+ std::stringstream str;
+ str.str(TEXT_MODEL);
+
+ CInstanceManager iMan;
+ Gfx::CModelFile modelFile(&iMan);
+
+ EXPECT_TRUE(modelFile.ReadTextModel(str));
+
+ EXPECT_EQ(modelFile.GetTriangleCount(), 2);
+ EXPECT_TRUE(CompareTriangles(modelFile.GetTriangles()[0], TRIANGLE_1));
+ EXPECT_TRUE(CompareTriangles(modelFile.GetTriangles()[1], TRIANGLE_2));
+
+ str.str("");
+
+ EXPECT_TRUE(modelFile.WriteBinaryModel(str));
+ str.seekg(0);
+ EXPECT_TRUE(modelFile.ReadBinaryModel(str));
+
+ EXPECT_EQ(modelFile.GetTriangleCount(), 2);
+ EXPECT_TRUE(CompareTriangles(modelFile.GetTriangles()[0], TRIANGLE_1));
+ EXPECT_TRUE(CompareTriangles(modelFile.GetTriangles()[1], TRIANGLE_2));
+}
+
+// Tests reading/writing old model file
+TEST(ModelFileTest, RWOldModel)
+{
+ std::stringstream str;
+ str.str(TEXT_MODEL);
+
+ CInstanceManager iMan;
+ Gfx::CModelFile modelFile(&iMan);
+
+ EXPECT_TRUE(modelFile.ReadTextModel(str));
+
+ EXPECT_EQ(modelFile.GetTriangleCount(), 2);
+ EXPECT_TRUE(CompareTriangles(modelFile.GetTriangles()[0], TRIANGLE_1));
+ EXPECT_TRUE(CompareTriangles(modelFile.GetTriangles()[1], TRIANGLE_2));
+
+ str.str("");
+
+ EXPECT_TRUE(modelFile.WriteModel(str));
+ str.seekg(0);
+ EXPECT_TRUE(modelFile.ReadModel(str));
+
+ EXPECT_EQ(modelFile.GetTriangleCount(), 2);
+ EXPECT_TRUE(CompareTriangles(modelFile.GetTriangles()[0], TRIANGLE_1));
+ EXPECT_TRUE(CompareTriangles(modelFile.GetTriangles()[1], TRIANGLE_2));
+}
+
+int main(int argc, char **argv)
+{
+ CLogger logger;
+
+ Init();
+
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
}
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<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();
@@ -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<CTerrain*>(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<WaterLine> m_lines;
std::vector<WaterVapor> m_vapors;
bool m_draw;
bool m_lava;
- long m_color;
+ Gfx::Color m_color;
};
}; // namespace Gfx
diff --git a/src/graphics/opengl/gldevice.cpp b/src/graphics/opengl/gldevice.cpp
index 7221421..a779a5f 100644
--- a/src/graphics/opengl/gldevice.cpp
+++ b/src/graphics/opengl/gldevice.cpp
@@ -187,6 +187,7 @@ void Gfx::CGLDevice::EndScene()
void Gfx::CGLDevice::Clear()
{
+ glDepthMask(GL_TRUE);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
@@ -454,6 +455,55 @@ Gfx::Texture Gfx::CGLDevice::CreateTexture(ImageData *data, const Gfx::TextureCr
sourceFormat = GL_BGRA;
result.alpha = true;
}
+ else if (params.format == Gfx::TEX_IMG_AUTO)
+ {
+ if (data->surface->format->Amask != 0)
+ {
+ if ((data->surface->format->Rmask == 0xFF000000) &&
+ (data->surface->format->Gmask == 0x00FF0000) &&
+ (data->surface->format->Bmask == 0x0000FF00) &&
+ (data->surface->format->Amask == 0x000000FF))
+ {
+ sourceFormat = GL_BGRA;
+ result.alpha = true;
+ }
+ else if ((data->surface->format->Bmask == 0xFF000000) &&
+ (data->surface->format->Gmask == 0x00FF0000) &&
+ (data->surface->format->Rmask == 0x0000FF00) &&
+ (data->surface->format->Amask == 0x000000FF))
+ {
+ sourceFormat = GL_RGBA;
+ result.alpha = true;
+ }
+ else
+ {
+ GetLogger()->Error("Auto texture format failed\n");
+ return Gfx::Texture(); // other format?
+ }
+ }
+ else
+ {
+ if ((data->surface->format->Rmask == 0xFF0000) &&
+ (data->surface->format->Gmask == 0x00FF00) &&
+ (data->surface->format->Bmask == 0x0000FF))
+ {
+ sourceFormat = GL_BGR;
+ result.alpha = false;
+ }
+ else if ((data->surface->format->Bmask == 0xFF0000) &&
+ (data->surface->format->Gmask == 0x00FF00) &&
+ (data->surface->format->Rmask == 0x0000FF))
+ {
+ sourceFormat = GL_RGB;
+ result.alpha = false;
+ }
+ else
+ {
+ GetLogger()->Error("Auto texture format failed\n");
+ return Gfx::Texture(); // other format?
+ }
+ }
+ }
else
assert(false);
diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt
new file mode 100644
index 0000000..f6c6112
--- /dev/null
+++ b/src/tools/CMakeLists.txt
@@ -0,0 +1,13 @@
+set(CONVERT_MODEL_SOURCES
+../common/iman.cpp
+../common/logger.cpp
+../common/stringutils.cpp
+../graphics/engine/modelfile.cpp
+convert_model.cpp
+)
+
+include_directories(. ..)
+
+add_definitions(-DMODELFILE_NO_ENGINE)
+
+add_executable(convert_model ${CONVERT_MODEL_SOURCES})
diff --git a/src/tools/README.txt b/src/tools/README.txt
new file mode 100644
index 0000000..de2f087
--- /dev/null
+++ b/src/tools/README.txt
@@ -0,0 +1,4 @@
+/**
+ * \dir tools
+ * \brief Various tools (separate programs)
+ */
diff --git a/src/tools/convert_model.cpp b/src/tools/convert_model.cpp
new file mode 100644
index 0000000..a2f2b7a
--- /dev/null
+++ b/src/tools/convert_model.cpp
@@ -0,0 +1,286 @@
+#include "common/iman.h"
+#include "common/logger.h"
+#include "graphics/engine/modelfile.h"
+
+#include <iostream>
+#include <map>
+
+
+bool EndsWith(std::string const &fullString, std::string const &ending)
+{
+ if (fullString.length() >= ending.length()) {
+ return (0 == fullString.compare (fullString.length() - ending.length(), ending.length(), ending));
+ } else {
+ return false;
+ }
+}
+
+
+struct Args
+{
+ bool usage;
+ bool dumpInfo;
+ bool mirror;
+ std::string inputFile;
+ std::string outputFile;
+ std::string inputFormat;
+ std::string outputFormat;
+
+ Args()
+ {
+ usage = false;
+ dumpInfo = false;
+ mirror = false;
+ }
+};
+
+Args ARGS;
+
+void PrintUsage(const std::string& program)
+{
+ std::cerr << "Colobot model converter" << std::endl;
+ std::cerr << std::endl;
+ std::cerr << "Usage:" << std::endl;
+ std::cerr << std::endl;
+ std::cerr << " Convert files:" << std::endl;
+ std::cerr << " " << program << " -i input_file -if input_format -o output_file -of output_format [-m]" << std::endl;
+ std::cerr << " -m => mirror" << std::endl;
+ std::cerr << std::endl;
+ std::cerr << " Dump info:" << std::endl;
+ std::cerr << " " << program << " -d -i input_file -if input_format" << std::endl;
+ std::cerr << std::endl;
+ std::cerr << " Help:" << std::endl;
+ std::cerr << " " << program << " -h" << std::endl;
+ std::cerr << std::endl;
+
+ std::cerr << "Model formats:" << std::endl;
+ std::cerr << " old => old binary format" << std::endl;
+ std::cerr << " new_bin => new binary format" << std::endl;
+ std::cerr << " new_txt => new text format" << std::endl;
+}
+
+bool ParseArgs(int argc, char *argv[])
+{
+ bool waitI = false, waitO = false;
+ bool waitIf = false, waitOf = false;
+ for (int i = 1; i < argc; ++i)
+ {
+ std::string arg = std::string(argv[i]);
+
+ if (arg == "-i")
+ {
+ waitI = true;
+ continue;
+ }
+ if (arg == "-o")
+ {
+ waitO = true;
+ continue;
+ }
+ if (arg == "-if")
+ {
+ waitIf = true;
+ continue;
+ }
+ if (arg == "-of")
+ {
+ waitOf = true;
+ continue;
+ }
+
+ if (waitI)
+ {
+ waitI = false;
+ ARGS.inputFile = arg;
+ }
+ else if (waitO)
+ {
+ waitO = false;
+ ARGS.outputFile = arg;
+ }
+ else if (waitIf)
+ {
+ waitIf = false;
+ ARGS.inputFormat = arg;
+ }
+ else if (waitOf)
+ {
+ waitOf = false;
+ ARGS.outputFormat = arg;
+ }
+ else if (arg == "-h")
+ {
+ PrintUsage(argv[0]);
+ ARGS.usage = true;
+ }
+ else if (arg == "-d")
+ {
+ ARGS.dumpInfo = true;
+ }
+ else if (arg == "-m")
+ {
+ ARGS.mirror = true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ if (waitI || waitO || waitIf || waitOf)
+ return false;
+
+ if (ARGS.usage)
+ return true;
+
+ if (ARGS.inputFile.empty() || (!ARGS.dumpInfo && ARGS.outputFile.empty() ))
+ return false;
+
+ if (ARGS.inputFormat.empty() || (!ARGS.dumpInfo && ARGS.outputFormat.empty() ))
+ return false;
+
+ return true;
+}
+
+template<typename T>
+void PrintStats(const std::map<T, int>& stats, int total)
+{
+ for (auto it = stats.begin(); it != stats.end(); ++it)
+ {
+ std::cerr << " " << (*it).first << " : " << (*it).second << " / " << total << std::endl;
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ CLogger logger;
+ logger.SetLogLevel(LOG_ERROR);
+
+ if (!ParseArgs(argc, argv))
+ {
+ std::cerr << "Invalid arguments! Run with -h for usage info." << std::endl;
+ return 1;
+ }
+
+ if (ARGS.usage)
+ return 0;
+
+ CInstanceManager iMan;
+ Gfx::CModelFile model(&iMan);
+
+ bool ok = true;
+
+ if (ARGS.inputFormat == "old")
+ {
+ ok = model.ReadModel(ARGS.inputFile);
+ }
+ else if (ARGS.inputFormat == "new_bin")
+ {
+ ok = model.ReadBinaryModel(ARGS.inputFile);
+ }
+ else if (ARGS.inputFormat == "new_txt")
+ {
+ ok = model.ReadTextModel(ARGS.inputFile);
+ }
+ else
+ {
+ std::cerr << "Invalid input format" << std::endl;
+ return 1;
+ }
+
+ if (!ok)
+ {
+ std::cerr << "Reading input model failed" << std::endl;
+ return 1;
+ }
+
+ if (ARGS.dumpInfo)
+ {
+ const std::vector<Gfx::ModelTriangle>& triangles = model.GetTriangles();
+
+ Math::Vector min( Math::HUGE_NUM, Math::HUGE_NUM, Math::HUGE_NUM);
+ Math::Vector max(-Math::HUGE_NUM, -Math::HUGE_NUM, -Math::HUGE_NUM);
+
+ std::map<std::string, int> texs1, texs2;
+ std::map<int, int> states;
+ std::map<float, int> mins, maxs;
+ int variableTexs2 = 0;
+
+ for (int i = 0; i < static_cast<int>( triangles.size() ); ++i)
+ {
+ const Gfx::ModelTriangle& t = triangles[i];
+
+ min.x = Math::Min(t.p1.coord.x, t.p2.coord.x, t.p3.coord.x, min.x);
+ min.y = Math::Min(t.p1.coord.y, t.p2.coord.y, t.p3.coord.y, min.y);
+ min.z = Math::Min(t.p1.coord.z, t.p2.coord.z, t.p3.coord.z, min.z);
+
+ max.x = Math::Max(t.p1.coord.x, t.p2.coord.x, t.p3.coord.x, max.x);
+ max.y = Math::Max(t.p1.coord.y, t.p2.coord.y, t.p3.coord.y, max.y);
+ max.z = Math::Max(t.p1.coord.z, t.p2.coord.z, t.p3.coord.z, max.z);
+
+ texs1[t.tex1Name] += 1;
+ if (! t.tex2Name.empty())
+ texs2[t.tex2Name] += 1;
+ if (t.variableTex2)
+ variableTexs2 += 1;
+ states[t.state] += 1;
+
+ mins[t.min] += 1;
+ maxs[t.max] += 1;
+ }
+
+ std::cerr << "---- Info ----" << std::endl;
+ std::cerr << "Total triangles: " << triangles.size();
+ std::cerr << std::endl;
+ std::cerr << "Bounding box:" << std::endl;
+ std::cerr << " min: [" << min.x << ", " << min.y << ", " << min.z << "]" << std::endl;
+ std::cerr << " max: [" << max.x << ", " << max.y << ", " << max.z << "]" << std::endl;
+ std::cerr << std::endl;
+ std::cerr << "Textures:" << std::endl;
+ std::cerr << " tex1:" << std::endl;
+ PrintStats(texs1, triangles.size());
+ std::cerr << " tex2:" << std::endl;
+ PrintStats(texs2, triangles.size());
+ std::cerr << " variable tex2: " << variableTexs2 << " / " << triangles.size() << std::endl;
+ std::cerr << std::endl;
+ std::cerr << "States:" << std::endl;
+ PrintStats(states, triangles.size());
+ std::cerr << std::endl;
+ std::cerr << "LOD:" << std::endl;
+ std::cerr << " min:" << std::endl;
+ PrintStats(mins, triangles.size());
+ std::cerr << " max:" << std::endl;
+ PrintStats(maxs, triangles.size());
+
+ return 0;
+ }
+
+ if (ARGS.mirror)
+ model.Mirror();
+
+ if (ARGS.outputFormat == "old")
+ {
+ ok = model.WriteModel(ARGS.outputFile);
+ }
+ else if (ARGS.outputFormat == "new_bin")
+ {
+ ok = model.WriteBinaryModel(ARGS.outputFile);
+ }
+ else if (ARGS.outputFormat == "new_txt")
+ {
+ ok = model.WriteTextModel(ARGS.outputFile);
+ }
+ else
+ {
+ std::cerr << "Invalid output format" << std::endl;
+ return 1;
+ }
+
+ if (!ok)
+ {
+ std::cerr << "Writing output model failed" << std::endl;
+ return 1;
+ }
+
+ return 0;
+}