summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/CMakeLists.txt4
-rw-r--r--src/common/ioutils.h81
-rw-r--r--src/common/stringutils.cpp149
-rw-r--r--src/common/stringutils.h77
-rw-r--r--src/graphics/common/model.cpp23
-rw-r--r--src/graphics/common/model.h141
-rw-r--r--src/graphics/common/modelfile.cpp815
-rw-r--r--src/graphics/common/modelfile.h118
-rw-r--r--src/graphics/common/modfile.cpp23
-rw-r--r--src/graphics/common/modfile.h114
-rw-r--r--src/graphics/common/test/CMakeLists.txt7
-rw-r--r--src/graphics/common/test/modelfile_test.cpp48
-rw-r--r--src/graphics/common/vertex.h8
13 files changed, 1305 insertions, 303 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index fada14c..7f52e8d 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -38,6 +38,7 @@ common/iman.cpp
# common/modfile.cpp
# common/profile.cpp
# common/restext.cpp
+common/stringutils.cpp
graphics/common/camera.cpp
graphics/common/cloud.cpp
graphics/common/color.cpp
@@ -45,8 +46,7 @@ graphics/common/device.cpp
graphics/common/engine.cpp
graphics/common/light.cpp
graphics/common/lightning.cpp
-graphics/common/model.cpp
-graphics/common/modfile.cpp
+graphics/common/modelfile.cpp
graphics/common/particle.cpp
graphics/common/planet.cpp
graphics/common/pyro.cpp
diff --git a/src/common/ioutils.h b/src/common/ioutils.h
new file mode 100644
index 0000000..f17c961
--- /dev/null
+++ b/src/common/ioutils.h
@@ -0,0 +1,81 @@
+// * 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/.
+
+// ioutils.h
+
+#pragma once
+
+
+#include <iostream>
+
+
+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 */
+template<int N, typename T>
+void WriteBinary(T value, std::ostream &ostr)
+{
+ for (int i = 0; i < N; ++i)
+ {
+ unsigned char byte = (value >> (i*8)) & 0xFF;
+ ostr.write((char*)&byte, 1);
+ }
+}
+
+//! 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 */
+template<int N, typename T>
+T ReadBinary(std::istream &istr)
+{
+ T value = 0;
+ for (int i = 0; i < N; ++i)
+ {
+ unsigned char byte = 0;
+ istr.read((char*)&byte, 1);
+ value |= byte << (i*8);
+ }
+ return value;
+}
+
+//! 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. */
+void WriteBinaryFloat(float value, std::ostream &ostr)
+{
+ unsigned int iValue = *( (unsigned int*)( (void*)(&value) ) );
+ IOUtils::WriteBinary<4, unsigned int>(iValue, 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. */
+float ReadBinaryFloat(std::istream &istr)
+{
+ unsigned int iValue = IOUtils::ReadBinary<4, unsigned int>(istr);
+ float result = *( (float*)( (void*)(&iValue) ) );
+ return result;
+}
+
+}; // namespace IOUtils
diff --git a/src/common/stringutils.cpp b/src/common/stringutils.cpp
new file mode 100644
index 0000000..9a7aa61
--- /dev/null
+++ b/src/common/stringutils.cpp
@@ -0,0 +1,149 @@
+// * 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/.
+
+// stringutils.cpp
+
+#include "stringutils.h"
+
+
+std::string StrUtils::Replace(const std::string &str, const std::string &oldStr, const std::string &newStr)
+{
+ std::string result = str;
+ size_t pos = 0;
+ while ((pos = str.find(oldStr, pos)) != std::string::npos)
+ {
+ result.replace(pos, oldStr.length(), newStr);
+ pos += newStr.length();
+ }
+ return result;
+}
+
+std::string StrUtils::UnicodeCharToUtf8(unsigned int ch)
+{
+ std::string result;
+ if (ch < 0x0080)
+ {
+ result += (char)(ch);
+ }
+ else if (ch < 0x0800)
+ {
+ char ch1 = 0xC0 | ((ch & 0x07C0) >> 6);
+ char ch2 = 0x80 | (ch & 0x3F);
+ result += ch1;
+ result += ch2;
+ }
+ else
+ {
+ char ch1 = 0xE0 | ((ch & 0xF000) >> 12);
+ char ch2 = 0x80 | ((ch & 0x07C0) >> 6);
+ char ch3 = 0x80 | (ch & 0x3F);
+ result += ch1;
+ result += ch2;
+ result += ch3;
+ }
+ return result;
+}
+
+std::string StrUtils::UnicodeStringToUtf8(const std::wstring &str)
+{
+ std::string result;
+ for (unsigned int i = 0; i < str.size(); ++i)
+ result += StrUtils::UnicodeCharToUtf8((unsigned int)str[i]);
+
+ return result;
+}
+
+unsigned int StrUtils::Utf8CharToUnicode(const std::string &ch)
+{
+ if (ch.empty())
+ return 0;
+
+ unsigned int result = 0;
+ if ((ch[0] & 0x80) == 0)
+ {
+ if (ch.size() == 1)
+ result = (unsigned int)ch[0];
+ }
+ else if ((ch[0] & 0xC0) == 0xC0)
+ {
+ if (ch.size() == 2)
+ {
+ unsigned int ch1 = (ch[0] & 0x1F) << 6;
+ unsigned int ch2 = (ch[1] & 0x3F);
+ result = ch1 | ch2;
+ }
+ }
+ else
+ {
+ if (ch.size() == 3)
+ {
+ unsigned int ch1 = (ch[0] & 0xF0) << 12;
+ unsigned int ch2 = (ch[1] & 0xC0) << 6;
+ unsigned int ch3 = (ch[2] & 0xC0);
+ result = ch1 | ch2 | ch3;
+ }
+ }
+
+ return result;
+}
+
+std::wstring StrUtils::Utf8StringToUnicode(const std::string &str)
+{
+ std::wstring result;
+ unsigned int pos = 0;
+ while (pos < str.size())
+ {
+ int len = StrUtils::Utf8CharSizeAt(str, pos);
+ if (len == 0)
+ break;
+
+ std::string ch = str.substr(pos, len);
+ result += (wchar_t)(StrUtils::Utf8CharToUnicode(ch));
+ pos += len;
+ }
+ return result;
+}
+
+int StrUtils::Utf8CharSizeAt(const std::string &str, unsigned int pos)
+{
+ if (pos >= str.size())
+ return 0;
+
+ if ((str[pos] & 0x80) == 0)
+ return 1;
+ else if ((str[pos] & 0xC0) == 0xC0)
+ return 2;
+ else
+ return 3;
+
+ return 0;
+}
+
+size_t StrUtils::Utf8StringLength(const std::string &str)
+{
+ size_t result = 0;
+ for (unsigned int i = 0; i < str.size(); ++i)
+ {
+ char ch = str[i];
+ if ((ch & 0x80) == 0)
+ ++result;
+ else if ((ch & 0xC0) == 0xC0)
+ result += 2;
+ else
+ result += 3;
+ }
+ return result;
+}
diff --git a/src/common/stringutils.h b/src/common/stringutils.h
new file mode 100644
index 0000000..a0cae70
--- /dev/null
+++ b/src/common/stringutils.h
@@ -0,0 +1,77 @@
+// * 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/.
+
+// stringutils.h
+
+#pragma once
+
+
+#include <string>
+#include <sstream>
+
+namespace StrUtils {
+
+//! Converts a value to string
+/** If given, \a ok is set to true/false on success/failure.
+ Warning: To avoid unnecessary problems, *always* give full template qualifier e.g. ToString\<int\> */
+template<class T>
+std::string ToString(T value, bool *ok = NULL)
+{
+ std::ostringstream s;
+ s << value;
+ if (ok != NULL)
+ *ok = !s.fail();
+ return s.str();
+}
+
+//! Converts a value to string
+/** If given, \a ok is set to true/false on success/failure.
+ Warning: To avoid unnecessary problems, *always* give full template qualifier e.g. FromString\<int\> */
+template<class T>
+T FromString(const std::string &str, bool *ok = NULL)
+{
+ std::istringstream s;
+ s.str(str);
+ T value;
+ s >> value;
+ if (ok != NULL)
+ *ok = !s.fail();
+ return value;
+}
+
+//! Returns a string with every occurence of \a oldStr in \a str replaced to \a newStr
+std::string Replace(const std::string &str, const std::string &oldStr, const std::string &newStr);
+
+
+//! Converts a wide Unicode char to a single UTF-8 encoded char
+std::string UnicodeCharToUtf8(unsigned int ch);
+
+//! Converts a wide Unicode string to a UTF-8 encoded string
+std::string UnicodeStringToUtf8(const std::wstring &str);
+
+//! Converts a UTF-8 encoded single character to wide Unicode char
+unsigned int Utf8CharToUnicode(const std::string &ch);
+
+//! Converts a UTF-8 encoded string to wide Unicode string
+std::wstring Utf8StringToUnicode(const std::string &str);
+
+//! Returns the size in bytes of UTF-8 character at given \a pos in a UTF-8 \a str
+int Utf8CharSizeAt(const std::string &str, unsigned int pos);
+
+//! Returns the length in characters of UTF-8 string \a str
+size_t Utf8StringLength(const std::string &str);
+
+}; // namespace StrUtil
diff --git a/src/graphics/common/model.cpp b/src/graphics/common/model.cpp
deleted file mode 100644
index c415fb8..0000000
--- a/src/graphics/common/model.cpp
+++ /dev/null
@@ -1,23 +0,0 @@
-// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
-// * 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/.
-
-// model.cpp
-
-#include "graphics/common/model.h"
-
-
-// TODO implementation
diff --git a/src/graphics/common/model.h b/src/graphics/common/model.h
deleted file mode 100644
index e8a5f19..0000000
--- a/src/graphics/common/model.h
+++ /dev/null
@@ -1,141 +0,0 @@
-// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
-// * 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/.
-
-// model.h
-
-#pragma once
-
-#include "engine.h"
-#include "common/event.h"
-#include "modfile.h"
-#include "vertex.h"
-#include "math/point.h"
-
-
-class CInstanceManager;
-class CModFile;
-class CInterface;
-
-
-namespace Gfx {
-
-class CEngine;
-
-
-class CModel {
- public:
- CModel(CInstanceManager* iMan);
- ~CModel();
-
- void StartUserAction();
- void StopUserAction();
-
- bool EventProcess(const Event &event);
-
- void InitView();
- void InitViewFromSelect();
- void UpdateView();
- void ViewMove(const Event &event, float speed);
-
- protected:
- bool EventFrame(const Event &event);
- bool GetVertex(int rank, Gfx::VertexTex2 &vertex);
- bool SetVertex(int rank, Gfx::VertexTex2 &vertex);
- Math::Vector RetSelectCDG();
- Math::Vector RetSelectNormal();
- void SmoothSelect();
- void PlaneSelect();
- void ColorSelect();
- void StateSelect();
- void MoveSelect(Math::Vector move);
- void OperSelect(Math::Vector move, char oper);
- void ReadScript(char *filename);
- void BBoxCompute(Math::Vector &min, Math::Vector &max);
- bool IsMappingSelectPlausible(Gfx::Mapping D3Dmode);
- void MappingSelect(int mode, int rotate, bool bMirrorX, bool bMirrorY, Math::Point ti, Math::Point ts, char *texName);
- void MappingSelectSpherical(int mode, int rotate, bool bMirrorX, bool bMirrorY, Math::Point ti, Math::Point ts, char *texName);
- Math::Vector RetMappingCenter(Math::Vector pos, Math::Vector min);
- void MappingSelectCylindrical(int mode, int rotate, bool bMirrorX, bool bMirrorY, Math::Point ti, Math::Point ts, char *texName);
- void MappingSelectFace(int mode, int rotate, bool bMirrorX, bool bMirrorY, Math::Point ti, Math::Point ts, char *texName);
- void MappingSelect2(int texNum2, int subdiv, int offsetU, int offsetV, bool bMirrorX, bool bMirrorY);
- void MappingSelectPlane2(int mode, bool bMirrorX, bool bMirrorY);
- void MappingSelectSpherical2(bool bMirrorX, bool bMirrorY);
- void MappingSelectMagic2(bool bMirrorX, bool bMirrorY);
- int SearchNext(int rank, int step);
- int SearchSamePlane(int first, int step);
- void CurrentSearchNext(int step, bool bControl);
- void CurrentInit();
- void CurrentSelect(bool bSelect);
- void DeselectAll();
- void SelectAll();
- void SelectZone(int first, int last);
- void SelectTerm();
- void DefaultSelect();
- void SelectDelete();
- void Compress();
- void MinMaxSelect();
- void MinMaxChange();
- void UpdateInfoText();
- int* RetTextureTable();
- void TexturePartUpdate();
- void TextureRankChange(int step);
- void TexturePartChange(int step);
- void PutTextureValues();
- void GetTextureValues();
- void GetModelName(char *buffer);
- void GetDXFName(char *buffer);
- void GetScriptName(char *buffer);
- bool IsEditFocus();
-
- protected:
- CInstanceManager* m_iMan;
- Gfx::CEngine* m_engine;
- CModFile* m_modFile;
- CInterface* m_interface;
-
- float m_time;
- ModelTriangle* m_triangleTable;
- int m_triangleSel1;
- int m_triangleSel2;
- int m_mode;
- int m_textureMode;
- int m_textureRotate;
- bool m_bTextureMirrorX;
- bool m_bTextureMirrorY;
- Math::Point m_textureInf;
- Math::Point m_textureSup;
- int m_texturePart;
- int m_textureRank;
- char m_textureName[20];
- bool m_bDisplayTransparent;
- bool m_bDisplayOnlySelection;
- float m_viewHeight;
- float m_viewDist;
- float m_viewAngleH;
- float m_viewAngleV;
- int m_color;
- int m_state;
- int m_secondTexNum;
- int m_secondSubdiv;
- int m_secondOffsetU;
- int m_secondOffsetV;
- char m_oper;
- float m_min;
- float m_max;
-};
-
-}; // namespace Gfx
diff --git a/src/graphics/common/modelfile.cpp b/src/graphics/common/modelfile.cpp
new file mode 100644
index 0000000..8e509fe
--- /dev/null
+++ b/src/graphics/common/modelfile.cpp
@@ -0,0 +1,815 @@
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// * 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/.
+
+// modelfile.cpp (aka modfile.cpp)
+
+#include "graphics/common/modelfile.h"
+
+#include "common/iman.h"
+#include "common/ioutils.h"
+#include "common/stringutils.h"
+#include "math/geometry.h"
+
+#include <string.h>
+
+#include <fstream>
+
+
+//! How big the triangle vector is by default
+const int TRIANGLE_PREALLOCATE_COUNT = 2000;
+
+/**
+ \struct ModelHeader
+ \brief Header info for model file
+ */
+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;
+
+ NewModelTriangle()
+ {
+ memset(this, 0, sizeof(*this));
+ }
+};
+
+
+Gfx::Vertex ReadBinaryVertex(std::istream &stream)
+{
+ 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;
+}
+
+void WriteBinaryVertex(Gfx::Vertex vertex, std::ostream &stream)
+{
+ IOUtils::WriteBinaryFloat(vertex.coord.x, stream);
+ IOUtils::WriteBinaryFloat(vertex.coord.y, stream);
+ IOUtils::WriteBinaryFloat(vertex.coord.z, stream);
+ IOUtils::WriteBinaryFloat(vertex.normal.x, stream);
+ IOUtils::WriteBinaryFloat(vertex.normal.y, stream);
+ IOUtils::WriteBinaryFloat(vertex.normal.z, stream);
+ IOUtils::WriteBinaryFloat(vertex.texCoord.x, stream);
+ IOUtils::WriteBinaryFloat(vertex.texCoord.y, stream);
+}
+
+Gfx::VertexTex2 ReadBinaryVertexTex2(std::istream &stream)
+{
+ 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;
+}
+
+void WriteBinaryVertexTex2(Gfx::VertexTex2 vertex, std::ostream &stream)
+{
+ IOUtils::WriteBinaryFloat(vertex.coord.x, stream);
+ IOUtils::WriteBinaryFloat(vertex.coord.y, stream);
+ IOUtils::WriteBinaryFloat(vertex.coord.z, stream);
+ IOUtils::WriteBinaryFloat(vertex.normal.x, stream);
+ IOUtils::WriteBinaryFloat(vertex.normal.y, stream);
+ IOUtils::WriteBinaryFloat(vertex.normal.z, stream);
+ IOUtils::WriteBinaryFloat(vertex.texCoord.x, stream);
+ IOUtils::WriteBinaryFloat(vertex.texCoord.y, stream);
+ IOUtils::WriteBinaryFloat(vertex.texCoord2.x, stream);
+ IOUtils::WriteBinaryFloat(vertex.texCoord2.y, stream);
+}
+
+Gfx::Material ReadBinaryMaterial(std::istream &stream)
+{
+ Gfx::Material result;
+
+ result.diffuse.r = IOUtils::ReadBinaryFloat(stream);
+ result.diffuse.g = IOUtils::ReadBinaryFloat(stream);
+ result.diffuse.b = IOUtils::ReadBinaryFloat(stream);
+ result.diffuse.a = IOUtils::ReadBinaryFloat(stream);
+
+ result.ambient.r = IOUtils::ReadBinaryFloat(stream);
+ result.ambient.g = IOUtils::ReadBinaryFloat(stream);
+ result.ambient.b = IOUtils::ReadBinaryFloat(stream);
+ result.ambient.a = IOUtils::ReadBinaryFloat(stream);
+
+ result.specular.r = IOUtils::ReadBinaryFloat(stream);
+ result.specular.g = IOUtils::ReadBinaryFloat(stream);
+ result.specular.b = IOUtils::ReadBinaryFloat(stream);
+ result.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);
+
+ /* padding? */ IOUtils::ReadBinary<2, unsigned int>(stream);
+
+ return result;
+}
+
+void WriteBinaryMaterial(Gfx::Material material, std::ostream &stream)
+{
+ IOUtils::WriteBinaryFloat(material.diffuse.r, stream);
+ IOUtils::WriteBinaryFloat(material.diffuse.g, stream);
+ IOUtils::WriteBinaryFloat(material.diffuse.b, stream);
+ IOUtils::WriteBinaryFloat(material.diffuse.a, stream);
+
+ IOUtils::WriteBinaryFloat(material.ambient.r, stream);
+ IOUtils::WriteBinaryFloat(material.ambient.g, stream);
+ IOUtils::WriteBinaryFloat(material.ambient.b, stream);
+ IOUtils::WriteBinaryFloat(material.ambient.a, stream);
+
+ IOUtils::WriteBinaryFloat(material.specular.r, stream);
+ IOUtils::WriteBinaryFloat(material.specular.g, stream);
+ IOUtils::WriteBinaryFloat(material.specular.b, stream);
+ IOUtils::WriteBinaryFloat(material.specular.a, stream);
+
+ /* emissive.r */ IOUtils::WriteBinaryFloat(0.0f, stream);
+ /* emissive.g */ IOUtils::WriteBinaryFloat(0.0f, stream);
+ /* emissive.b */ IOUtils::WriteBinaryFloat(0.0f, stream);
+ /* emissive.a */ IOUtils::WriteBinaryFloat(0.0f, stream);
+
+ /* power */ IOUtils::WriteBinaryFloat(0.0f, stream);
+
+ /* padding? */ IOUtils::WriteBinary<2, unsigned int>(0, stream);
+}
+
+Gfx::ModelTriangle::ModelTriangle()
+{
+ min = 0.0f;
+ max = 0.0f;
+ state = 0L;
+}
+
+
+Gfx::CModelFile::CModelFile(CInstanceManager* iMan)
+{
+ m_iMan = iMan;
+
+ m_engine = (CEngine*)m_iMan->SearchInstance(CLASS_ENGINE);
+
+ m_triangles.reserve(TRIANGLE_PREALLOCATE_COUNT);
+}
+
+Gfx::CModelFile::~CModelFile()
+{
+}
+
+std::string Gfx::CModelFile::GetError()
+{
+ return m_error;
+}
+
+
+bool Gfx::CModelFile::ReadModel(const std::string &filename, bool edit, bool meta)
+{
+ m_triangles.clear();
+ m_error = "";
+
+ std::ifstream stream;
+ 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("'");
+ return false;
+ }
+
+ return ReadModel(stream, edit, meta);
+}
+
+bool Gfx::CModelFile::ReadModel(std::istream &stream, bool edit, bool meta)
+{
+ m_triangles.clear();
+ m_error = "";
+
+ // FIXME: for now, reading models only from files, not metafile
+
+ ModelHeader header;
+
+ header.revision = IOUtils::ReadBinary<4, int>(stream);
+ header.version = IOUtils::ReadBinary<4, int>(stream);
+ header.totalVertices = IOUtils::ReadBinary<4, int>(stream);
+ for (int i = 0; i < 10; ++i)
+ header.reserved[i] = IOUtils::ReadBinary<4, int>(stream);
+
+
+ if (! stream.good())
+ {
+ m_error = "Error reading model file header";
+ return false;
+ }
+
+ // Old model version #1
+ if ( (header.revision == 1) && (header.version == 0) )
+ {
+ for (int i = 0; i < header.totalVertices; ++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);
+
+ t.material = ReadBinaryMaterial(stream);
+ stream.read(t.texName, 20);
+ t.min = IOUtils::ReadBinaryFloat(stream);
+ t.max = IOUtils::ReadBinaryFloat(stream);
+
+ if (! stream.good())
+ {
+ m_error = "Error reading model data";
+ return false;
+ }
+
+ Gfx::ModelTriangle triangle;
+ triangle.p1.FromVertex(t.p1);
+ triangle.p2.FromVertex(t.p2);
+ triangle.p3.FromVertex(t.p3);
+
+ triangle.material = t.material;
+ triangle.tex1Name = std::string(t.texName);
+ triangle.min = t.min;
+ triangle.max = t.max;
+
+ m_triangles.push_back(triangle);
+ }
+ }
+ else if ( header.revision == 1 && header.version == 1 )
+ {
+ for (int i = 0; i < header.totalVertices; ++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);
+
+ t.material = ReadBinaryMaterial(stream);
+ stream.read(t.texName, 20);
+ t.min = IOUtils::ReadBinaryFloat(stream);
+ t.max = IOUtils::ReadBinaryFloat(stream);
+ t.state = IOUtils::ReadBinary<4, long>(stream);
+
+ t.reserved1 = IOUtils::ReadBinary<2, short>(stream);
+ t.reserved2 = IOUtils::ReadBinary<2, short>(stream);
+ t.reserved3 = IOUtils::ReadBinary<2, short>(stream);
+ t.reserved4 = IOUtils::ReadBinary<2, short>(stream);
+
+ if (! stream.good())
+ {
+ m_error = "Error reading model data";
+ return false;
+ }
+
+ Gfx::ModelTriangle triangle;
+ triangle.p1.FromVertex(t.p1);
+ triangle.p2.FromVertex(t.p2);
+ triangle.p3.FromVertex(t.p3);
+
+ triangle.material = t.material;
+ triangle.tex1Name = std::string(t.texName);
+ triangle.min = t.min;
+ triangle.max = t.max;
+ triangle.state = t.state;
+
+ m_triangles.push_back(triangle);
+ }
+ }
+ else
+ {
+ for (int i = 0; i < header.totalVertices; ++i)
+ {
+ NewModelTriangle t;
+ t.used = IOUtils::ReadBinary<1, char>(stream);
+ t.selected = IOUtils::ReadBinary<1, char>(stream);
+
+ t.p1 = ReadBinaryVertexTex2(stream);
+ t.p2 = ReadBinaryVertexTex2(stream);
+ t.p3 = ReadBinaryVertexTex2(stream);
+
+ t.material = ReadBinaryMaterial(stream);
+ stream.read(t.texName, 20);
+ t.min = IOUtils::ReadBinaryFloat(stream);
+ t.max = IOUtils::ReadBinaryFloat(stream);
+ t.state = IOUtils::ReadBinary<4, long>(stream);
+ t.texNum2 = IOUtils::ReadBinary<2, short>(stream);
+
+ t.reserved2 = IOUtils::ReadBinary<2, short>(stream);
+ t.reserved3 = IOUtils::ReadBinary<2, short>(stream);
+ t.reserved4 = IOUtils::ReadBinary<2, short>(stream);
+
+ if (! stream.good())
+ {
+ m_error = "Error reading model data";
+ return false;
+ }
+
+ Gfx::ModelTriangle triangle;
+ triangle.p1 = t.p1;
+ triangle.p2 = t.p2;
+ triangle.p3 = t.p3;
+
+ 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;
+ sprintf(tex2Name, "dirty%.2d.tga", t.texNum2); // hardcoded as in the original code
+ triangle.tex2Name = std::string(tex2Name);
+
+ m_triangles.push_back(triangle);
+ }
+ }
+
+ for (int i = 0; i < (int) m_triangles.size(); ++i)
+ m_triangles[i].tex1Name = StrUtils::Replace(m_triangles[i].tex1Name, "bmp", "tga");
+
+ /*
+ 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)
+{
+ m_error = "";
+
+ std::ofstream stream;
+ 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("'");
+ return false;
+ }
+
+ return WriteModel(stream);
+}
+
+bool Gfx::CModelFile::WriteModel(std::ostream &stream)
+{
+ m_error = "";
+
+ if (m_triangles.size() == 0)
+ {
+ m_error = "Empty model";
+ return false;
+ }
+
+ ModelHeader header;
+ header.revision = 1;
+ header.version = 2;
+ header.totalVertices = m_triangles.size();
+
+ IOUtils::WriteBinary<4, int>(header.revision, stream);
+ IOUtils::WriteBinary<4, int>(header.version, stream);
+ IOUtils::WriteBinary<4, int>(header.totalVertices, stream);
+ for (int i = 0; i < 10; ++i)
+ IOUtils::WriteBinary<4, int>(header.reserved[i], stream);
+
+ for (int i = 0; i < (int)m_triangles.size(); ++i)
+ {
+ NewModelTriangle t;
+
+ t.used = true;
+
+ t.p1 = m_triangles[i].p1;
+ t.p2 = m_triangles[i].p2;
+ t.p3 = m_triangles[i].p3;
+
+ t.material = m_triangles[i].material;
+ strncpy(t.texName, m_triangles[i].tex1Name.c_str(), 20);
+ 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
+ t.texNum2 = no;
+
+
+ IOUtils::WriteBinary<1, char>(t.used, stream);
+ IOUtils::WriteBinary<1, char>(t.selected, stream);
+
+ WriteBinaryVertexTex2(t.p1, stream);
+ WriteBinaryVertexTex2(t.p2, stream);
+ WriteBinaryVertexTex2(t.p3, stream);
+
+ WriteBinaryMaterial(t.material, stream);
+ stream.write(t.texName, 20);
+ IOUtils::WriteBinaryFloat(t.min, stream);
+ IOUtils::WriteBinaryFloat(t.max, stream);
+ IOUtils::WriteBinary<4, long>(t.state, stream);
+ IOUtils::WriteBinary<2, short>(t.texNum2, stream);
+
+ IOUtils::WriteBinary<2, short>(t.reserved2, stream);
+ IOUtils::WriteBinary<2, short>(t.reserved3, stream);
+ IOUtils::WriteBinary<2, short>(t.reserved4, stream);
+ }
+
+ return true;
+}
+
+bool Gfx::CModelFile::ReadDXF(const std::string &filename, float min, float max)
+{
+ m_triangles.clear();
+ m_error = "";
+
+ std::ifstream stream;
+ stream.open(filename.c_str(), std::ios_base::in);
+ if (! stream.good())
+ {
+ m_error = std::string("Couldn't open file '") + filename + std::string("'");
+ return false;
+ }
+
+ return ReadDXF(stream, min, max);
+}
+
+bool Gfx::CModelFile::ReadDXF(std::istream &stream, float min, float max)
+{
+ m_triangles.clear();
+ m_error = "";
+
+ if (! stream.good())
+ {
+ m_error = "Invalid stream";
+ 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() )
+ {
+ // Read line with command
+ std::getline(stream, line);
+ int command = StrUtils::FromString<int>(line);
+
+ // Read line with param
+ std::getline(stream, line);
+
+ bool ok = true;
+
+
+ if (command == 66)
+ {
+ waitNumVertex = true;
+ }
+
+ if ( command == 71 && waitNumVertex )
+ {
+ waitNumVertex = false;
+ vertexNum = StrUtils::FromString<int>(line, &ok);
+ waitNumFace = true;
+ }
+
+ if ( command == 72 && waitNumFace )
+ {
+ waitNumFace = false;
+ faceNum = StrUtils::FromString<int>(line, &ok);
+ waitVertexX = true;
+ }
+
+ if ( command == 10 && waitVertexX )
+ {
+ waitVertexX = false;
+ coords.x = StrUtils::FromString<float>(line, &ok);
+ waitVertexY = true;
+ }
+
+ if ( command == 20 && waitVertexY )
+ {
+ waitVertexY = false;
+ coords.y = StrUtils::FromString<float>(line, &ok);
+ waitVertexZ = true;
+ }
+
+ if ( command == 30 && waitVertexZ )
+ {
+ waitVertexZ = false;
+ coords.z = StrUtils::FromString<float>(line, &ok);
+
+ 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
+ {
+ waitFaceX = true;
+ }
+ }
+
+ if ( command == 71 && waitFaceX )
+ {
+ waitFaceX = false;
+ p1 = StrUtils::FromString<int>(line, &ok);
+ if ( p1 < 0 ) p1 = -p1;
+ waitFaceY = true;
+ }
+
+ if ( command == 72 && waitFaceY )
+ {
+ waitFaceY = false;
+ p2 = StrUtils::FromString<int>(line, &ok);
+ if ( p2 < 0 ) p2 = -p2;
+ waitFaceZ = true;
+ }
+
+ if ( command == 73 && waitFaceZ )
+ {
+ waitFaceZ = false;
+ p3 = StrUtils::FromString<int>(line, &ok);
+ if ( p3 < 0 ) p3 = -p3;
+
+ faceNum --;
+ if ( faceNum >= 0 )
+ {
+ assert( (p1-1 >= 0) && (p1-1 < (int)vertices.size() ) );
+ assert( (p2-1 >= 0) && (p2-1 < (int)vertices.size() ) );
+ assert( (p3-1 >= 0) && (p3-1 < (int)vertices.size() ) );
+
+ CreateTriangle(vertices[p3-1], vertices[p2-1], vertices[p1-1], min, max);
+ waitFaceX = true;
+ }
+ }
+
+ if (! ok)
+ {
+ m_error = "Error reading data";
+ return false;
+ }
+
+ }
+
+ return true;
+}
+
+bool Gfx::CModelFile::CreateEngineObject(int objRank, int addState)
+{
+ /*char texName1[20];
+ char texName2[20];
+ int texNum, i, state;
+
+ for (int i = 0; i < m_trianglesUsed; i++)
+ {
+ if (! m_triangles[i].used) continue;
+
+ state = m_triangles[i].state;
+ strcpy(texName1, m_triangles[i].texName);
+ texName2[0] = 0;
+
+ if ( strcmp(texName1, "plant.tga") == 0 ) // ???
+ {
+ state |= D3DSTATEALPHA;
+ }
+
+ if ( m_triangles[i].texNum2 != 0 )
+ {
+ if ( m_triangles[i].texNum2 == 1 )
+ {
+ texNum = m_engine->RetSecondTexture();
+ }
+ else
+ {
+ texNum = m_triangles[i].texNum2;
+ }
+
+ if ( texNum >= 1 && texNum <= 10 )
+ {
+ state |= D3DSTATEDUALb;
+ }
+ if ( texNum >= 11 && texNum <= 20 )
+ {
+ state |= D3DSTATEDUALw;
+ }
+ sprintf(texName2, "dirty%.2d.tga", texNum); // ???
+ }
+
+ m_engine->AddTriangle(objRank, &m_triangles[i].p1, 3,
+ m_triangles[i].material,
+ state + addState,
+ texName1, texName2,
+ m_triangles[i].min,
+ m_triangles[i].max, false);
+ }*/
+ return true;
+}
+
+void Gfx::CModelFile::Mirror()
+{
+ for (int i = 0; i < (int)m_triangles.size(); i++)
+ {
+ Gfx::VertexTex2 t = m_triangles[i].p1;
+ m_triangles[i].p1 = m_triangles[i].p2;
+ m_triangles[i].p2 = t;
+
+ m_triangles[i].p1.coord.z = -m_triangles[i].p1.coord.z;
+ m_triangles[i].p2.coord.z = -m_triangles[i].p2.coord.z;
+ m_triangles[i].p3.coord.z = -m_triangles[i].p3.coord.z;
+
+ m_triangles[i].p1.normal.z = -m_triangles[i].p1.normal.z;
+ m_triangles[i].p2.normal.z = -m_triangles[i].p2.normal.z;
+ m_triangles[i].p3.normal.z = -m_triangles[i].p3.normal.z;
+ }
+}
+
+int Gfx::CModelFile::GetTriangleCount()
+{
+ return m_triangles.size();
+}
+
+float Gfx::CModelFile::GetHeight(Math::Vector pos)
+{
+ float limit = 5.0f;
+
+ for (int i = 0; i < (int)m_triangles.size(); i++)
+ {
+ if ( fabs(pos.x - m_triangles[i].p1.coord.x) < limit &&
+ fabs(pos.z - m_triangles[i].p1.coord.z) < limit )
+ return m_triangles[i].p1.coord.y;
+
+ if ( fabs(pos.x - m_triangles[i].p2.coord.x) < limit &&
+ fabs(pos.z - m_triangles[i].p2.coord.z) < limit )
+ return m_triangles[i].p2.coord.y;
+
+ if ( fabs(pos.x - m_triangles[i].p3.coord.x) < limit &&
+ fabs(pos.z - m_triangles[i].p3.coord.z) < limit )
+ return m_triangles[i].p3.coord.y;
+ }
+
+ return 0.0f;
+}
+
+void Gfx::CModelFile::CreateTriangle(Math::Vector p1, Math::Vector p2, Math::Vector p3, float min, float max)
+{
+ Gfx::ModelTriangle triangle;
+
+ Math::Vector n = Math::NormalToPlane(p3, p2, p1);
+ triangle.p1 = Gfx::VertexTex2(p1, n);
+ triangle.p2 = Gfx::VertexTex2(p2, n);
+ triangle.p3 = Gfx::VertexTex2(p3, n);
+
+ triangle.material.diffuse = Gfx::Color(1.0f, 1.0f, 1.0f, 0.0f);
+ triangle.material.ambient = Gfx::Color(0.5f, 0.5f, 0.5f, 0.0f);
+
+ triangle.min = min;
+ triangle.max = max;
+
+ m_triangles.push_back(triangle);
+}
diff --git a/src/graphics/common/modelfile.h b/src/graphics/common/modelfile.h
new file mode 100644
index 0000000..625df50
--- /dev/null
+++ b/src/graphics/common/modelfile.h
@@ -0,0 +1,118 @@
+// * This file is part of the COLOBOT source code
+// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
+// * 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/.
+
+// modelfile.h (aka modfile.h)
+
+#include "graphics/common/engine.h"
+#include "graphics/common/vertex.h"
+#include "graphics/common/material.h"
+#include "math/vector.h"
+
+#include <string>
+#include <vector>
+#include <iostream>
+
+
+class CInstanceManager;
+
+
+namespace Gfx {
+
+/**
+ \struct ModelTriangle
+ \brief Triangle of a 3D model
+ */
+struct ModelTriangle
+{
+ //! 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;
+ //! Min LOD threshold
+ float min;
+ //! Max LOD threshold
+ float max;
+ //! Rendering state to be set
+ long state;
+
+ ModelTriangle();
+};
+
+
+/**
+ \class CModelFile
+ \brief Model file reader/writer
+
+ Allows reading and writing model objects. Models are collections of ModelTriangle structs. */
+class CModelFile
+{
+public:
+ CModelFile(CInstanceManager* iMan);
+ ~CModelFile();
+
+ //! Returns the last error encountered
+ std::string GetError();
+
+ //! Reads a binary Colobot model from file
+ bool ReadModel(const std::string &filename, bool edit = false, bool meta = true);
+ //! Reads a binary Colobot model from stream
+ bool ReadModel(std::istream &stream, bool edit = false, bool meta = true);
+ //! Writes the model to Colobot binary model file
+ bool WriteModel(const std::string &filename);
+ //! Writes the model to Colobot binary model file
+ 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 height of model -- closest point to X and Z coords of \a pos
+ float GetHeight(Math::Vector pos);
+
+ //! Mirrors the model along the Z axis
+ void Mirror();
+
+ //! Creates an object in the graphics engine from the model
+ bool CreateEngineObject(int objRank, int addState = 0);
+
+protected:
+ //! Adds a triangle to the list
+ void CreateTriangle(Math::Vector p1, Math::Vector p2, Math::Vector p3, float min, float max);
+
+protected:
+ CInstanceManager* m_iMan;
+ CEngine* m_engine;
+
+ //! Last error
+ std::string m_error;
+
+ //! Model triangles
+ std::vector<Gfx::ModelTriangle> m_triangles;
+};
+
+}; // namespace Gfx
diff --git a/src/graphics/common/modfile.cpp b/src/graphics/common/modfile.cpp
deleted file mode 100644
index 6f80be7..0000000
--- a/src/graphics/common/modfile.cpp
+++ /dev/null
@@ -1,23 +0,0 @@
-// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
-// * 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/.
-
-// modfile.cpp
-
-#include "graphics/common/modfile.h"
-
-
-// TODO implementation \ No newline at end of file
diff --git a/src/graphics/common/modfile.h b/src/graphics/common/modfile.h
deleted file mode 100644
index c81739b..0000000
--- a/src/graphics/common/modfile.h
+++ /dev/null
@@ -1,114 +0,0 @@
-// * This file is part of the COLOBOT source code
-// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
-// * 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/.
-
-// modfile.h
-
-#include "engine.h"
-#include "vertex.h"
-#include "material.h"
-#include "math/vector.h"
-
-
-class CInstanceManager;
-
-
-namespace Gfx {
-
-struct OldModelTriangle1
-{
- char bUsed; // TRUE -> using
- char bSelect; // TRUE -> selected
- Vertex p1;
- Vertex p2;
- Vertex p3;
- Material material;
- char texName[20];
- float min;
- float max;
-}; // length = 196 bytes
-
-struct OldModelTriangle2
-{
- char bUsed; // TRUE -> used
- char bSelect; // TRUE -> selected
- Vertex p1;
- Vertex p2;
- Vertex p3;
- Material material;
- char texName[20];
- float min;
- float max;
- long state;
- short reserve1;
- short reserve2;
- short reserve3;
- short reserve4;
-};
-
-struct ModelTriangle
-{
- char bUsed; // TRUE -> used
- char bSelect; // TRUE -> selected
- VertexTex2 p1;
- VertexTex2 p2;
- VertexTex2 p3;
- Material material;
- char texName[20];
- float min;
- float max;
- long state;
- short texNum2;
- short reserve2;
- short reserve3;
- short reserve4;
-}; // length = 208 bytes
-
-
-
-
-class CModFile {
-public:
- CModFile(CInstanceManager* iMan);
- ~CModFile();
-
- bool ReadDXF(char *filename, float min, float max);
- bool AddModel(char *filename, int first, bool bEdit=false, bool bMeta=true);
- bool ReadModel(char *filename, bool bEdit=false, bool bMeta=true);
- bool WriteModel(char *filename);
-
- bool CreateEngineObject(int objRank, int addState=0);
- void Mirror();
-
- void SetTriangleUsed(int total);
- int RetTriangleUsed();
- int RetTriangleMax();
- ModelTriangle* RetTriangleList();
-
- float RetHeight(Math::Vector pos);
-
-protected:
- bool CreateTriangle(Math::Vector p1, Math::Vector p2, Math::Vector p3, float min, float max);
-
-protected:
- CInstanceManager* m_iMan;
- CEngine* m_engine;
-
- ModelTriangle* m_triangleTable;
- int m_triangleUsed;
-};
-
-};
diff --git a/src/graphics/common/test/CMakeLists.txt b/src/graphics/common/test/CMakeLists.txt
new file mode 100644
index 0000000..7274169
--- /dev/null
+++ b/src/graphics/common/test/CMakeLists.txt
@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 2.8)
+
+set(CMAKE_BUILD_TYPE debug)
+set(CMAKE_CXX_FLAGS_DEBUG "-Wall -g -O0")
+
+include_directories(. ../../..)
+add_executable(modelfile_test modelfile_test.cpp ../modelfile.cpp ../../../common/stringutils.cpp ../../../common/iman.cpp)
diff --git a/src/graphics/common/test/modelfile_test.cpp b/src/graphics/common/test/modelfile_test.cpp
new file mode 100644
index 0000000..cc44f98
--- /dev/null
+++ b/src/graphics/common/test/modelfile_test.cpp
@@ -0,0 +1,48 @@
+#include "graphics/common/modelfile.h"
+#include "common/iman.h"
+
+#include <iostream>
+
+
+int main(int argc, char *argv[])
+{
+ if (argc != 4)
+ {
+ std::cerr << "Usage: " << argv[0] << " {mod|dxf} in_file out_file" << std::endl;
+ return 1;
+ }
+
+ 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;
+}
diff --git a/src/graphics/common/vertex.h b/src/graphics/common/vertex.h
index 430c84c..c6375b9 100644
--- a/src/graphics/common/vertex.h
+++ b/src/graphics/common/vertex.h
@@ -94,6 +94,14 @@ struct VertexTex2
Math::Point aTexCoord = Math::Point(),
Math::Point aTexCoord2 = Math::Point())
: coord(aCoord), normal(aNormal), texCoord(aTexCoord), texCoord2(aTexCoord2) {}
+
+ void FromVertex(const Gfx::Vertex &v)
+ {
+ coord = v.coord;
+ normal = v.normal;
+ texCoord = v.texCoord;
+ texCoord2 = Math::Point();
+ }
};
}; // namespace Gfx