Rewritten model loading

- written new implementation of CModelFile (old CModFile)
- added stringutils and ioutils in src/common
- removed old CModel (model viewer)
dev-ui
Piotr Dziwinski 2012-07-11 20:50:42 +02:00
parent 3204360515
commit 2383a42347
13 changed files with 1305 additions and 303 deletions

View File

@ -38,6 +38,7 @@ common/iman.cpp
# common/modfile.cpp # common/modfile.cpp
# common/profile.cpp # common/profile.cpp
# common/restext.cpp # common/restext.cpp
common/stringutils.cpp
graphics/common/camera.cpp graphics/common/camera.cpp
graphics/common/cloud.cpp graphics/common/cloud.cpp
graphics/common/color.cpp graphics/common/color.cpp
@ -45,8 +46,7 @@ graphics/common/device.cpp
graphics/common/engine.cpp graphics/common/engine.cpp
graphics/common/light.cpp graphics/common/light.cpp
graphics/common/lightning.cpp graphics/common/lightning.cpp
graphics/common/model.cpp graphics/common/modelfile.cpp
graphics/common/modfile.cpp
graphics/common/particle.cpp graphics/common/particle.cpp
graphics/common/planet.cpp graphics/common/planet.cpp
graphics/common/pyro.cpp graphics/common/pyro.cpp

81
src/common/ioutils.h Normal file
View File

@ -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

149
src/common/stringutils.cpp Normal file
View File

@ -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;
}

77
src/common/stringutils.h Normal file
View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -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;
};
};

View File

@ -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)

View File

@ -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;
}

View File

@ -94,6 +94,14 @@ struct VertexTex2
Math::Point aTexCoord = Math::Point(), Math::Point aTexCoord = Math::Point(),
Math::Point aTexCoord2 = Math::Point()) Math::Point aTexCoord2 = Math::Point())
: coord(aCoord), normal(aNormal), texCoord(aTexCoord), texCoord2(aTexCoord2) {} : coord(aCoord), normal(aNormal), texCoord(aTexCoord), texCoord2(aTexCoord2) {}
void FromVertex(const Gfx::Vertex &v)
{
coord = v.coord;
normal = v.normal;
texCoord = v.texCoord;
texCoord2 = Math::Point();
}
}; };
}; // namespace Gfx }; // namespace Gfx