Split model I/O to separate files based on model format and removed new binary format
parent
d57370578f
commit
920a4c3fc8
|
@ -138,10 +138,14 @@ add_library(colobotbase STATIC
|
|||
graphics/model/model_manager.h
|
||||
graphics/model/model_mesh.cpp
|
||||
graphics/model/model_mesh.h
|
||||
graphics/model/model_mod.cpp
|
||||
graphics/model/model_mod.h
|
||||
graphics/model/model_output.cpp
|
||||
graphics/model/model_output.h
|
||||
graphics/model/model_shadow_spot.h
|
||||
graphics/model/model_triangle.h
|
||||
graphics/model/model_txt.cpp
|
||||
graphics/model/model_txt.h
|
||||
graphics/opengl/gl33device.cpp
|
||||
graphics/opengl/gl33device.h
|
||||
graphics/opengl/gl33renderers.cpp
|
||||
|
|
|
@ -29,7 +29,6 @@ namespace Gfx
|
|||
enum class ModelFormat
|
||||
{
|
||||
Text, //!< new text format
|
||||
Binary, //!< new binary format
|
||||
Old //!< old binary format, deprecated
|
||||
};
|
||||
|
||||
|
|
|
@ -19,85 +19,14 @@
|
|||
|
||||
#include "graphics/model/model_input.h"
|
||||
|
||||
#include "common/ioutils.h"
|
||||
#include "common/logger.h"
|
||||
|
||||
#include "common/resources/inputstream.h"
|
||||
#include "graphics/model/model_mod.h"
|
||||
#include "graphics/model/model_txt.h"
|
||||
|
||||
#include "graphics/model/model_io_exception.h"
|
||||
#include "graphics/model/model_io_structs.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <cstdio>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
namespace Gfx
|
||||
{
|
||||
|
||||
//! Legacy material structure
|
||||
struct LegacyMaterial
|
||||
{
|
||||
//! Diffuse color
|
||||
Color diffuse;
|
||||
//! Ambient color
|
||||
Color ambient;
|
||||
//! Specular color
|
||||
Color specular;
|
||||
|
||||
bool operator==(const LegacyMaterial& mat) const
|
||||
{
|
||||
return diffuse == mat.diffuse && ambient == mat.ambient && specular == mat.specular;
|
||||
}
|
||||
|
||||
bool operator!=(const LegacyMaterial& mat) const
|
||||
{
|
||||
return !operator==(mat);
|
||||
}
|
||||
};
|
||||
|
||||
// Private functions
|
||||
namespace ModelInput
|
||||
{
|
||||
void ReadTextModel(CModel &model, std::istream &stream);
|
||||
void ReadTextModelV1AndV2(CModel &model, std::istream &stream);
|
||||
|
||||
void ReadTextModelV3(CModel &model, std::istream &stream);
|
||||
ModelHeaderV3 ReadTextHeader(std::istream &stream);
|
||||
CModelMesh ReadTextMesh(std::istream &stream);
|
||||
|
||||
void ReadBinaryModel(CModel &model, std::istream &stream);
|
||||
void ReadBinaryModelV1AndV2(CModel &model, std::istream &stream);
|
||||
void ReadBinaryModelV3(CModel &model, std::istream &stream);
|
||||
|
||||
void ReadOldModel(CModel &model, std::istream &stream);
|
||||
std::vector<ModelTriangle> ReadOldModelV1(std::istream &stream, int totalTriangles);
|
||||
std::vector<ModelTriangle> ReadOldModelV2(std::istream &stream, int totalTriangles);
|
||||
std::vector<ModelTriangle> ReadOldModelV3(std::istream &stream, int totalTriangles);
|
||||
|
||||
Vertex3D ReadBinaryVertex(std::istream& stream);
|
||||
Vertex3D ReadBinaryVertexTex2(std::istream& stream);
|
||||
LegacyMaterial ReadBinaryMaterial(std::istream& stream);
|
||||
|
||||
std::string ReadLineString(std::istream& stream, const std::string& expectedPrefix);
|
||||
void ReadValuePrefix(std::istream& stream, const std::string& expectedPrefix);
|
||||
Vertex3D ParseVertexTex2(const std::string& text);
|
||||
LegacyMaterial ParseMaterial(const std::string& text);
|
||||
glm::vec3 ParseVector(const std::string& text);
|
||||
ModelCrashSphere ParseCrashSphere(const std::string& text);
|
||||
ModelShadowSpot ParseShadowSpot(const std::string& text);
|
||||
Math::Sphere ParseCameraCollisionSphere(const std::string& text);
|
||||
AlphaMode ParseTransparentMode(const std::string& text);
|
||||
std::string ParseSpecialMark(const std::string& text);
|
||||
|
||||
void ConvertOldTex1Name(ModelTriangle& triangle, const char* tex1Name);
|
||||
void ConvertFromOldRenderState(ModelTriangle& triangle, int state);
|
||||
ModelLODLevel MinMaxToLodLevel(float min, float max);
|
||||
}
|
||||
|
||||
using namespace IOUtils;
|
||||
|
||||
CModel ModelInput::Read(std::istream &stream, ModelFormat format)
|
||||
{
|
||||
stream.exceptions(std::ios_base::failbit | std::ios_base::badbit);
|
||||
|
@ -108,16 +37,12 @@ CModel ModelInput::Read(std::istream &stream, ModelFormat format)
|
|||
{
|
||||
switch (format)
|
||||
{
|
||||
case ModelFormat::Binary:
|
||||
ReadBinaryModel(model, stream);
|
||||
break;
|
||||
|
||||
case ModelFormat::Text:
|
||||
ReadTextModel(model, stream);
|
||||
ModelIO::ReadTextModel(model, stream);
|
||||
break;
|
||||
|
||||
case ModelFormat::Old:
|
||||
ReadOldModel(model, stream);
|
||||
ModelIO::ReadOldModel(model, stream);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -133,785 +58,6 @@ CModel ModelInput::Read(std::istream &stream, ModelFormat format)
|
|||
return model;
|
||||
}
|
||||
|
||||
void ModelInput::ReadBinaryModel(CModel &model, std::istream &stream)
|
||||
{
|
||||
int version = 0;
|
||||
try
|
||||
{
|
||||
version = ReadBinary<4, int>(stream);
|
||||
stream.seekg(std::ios_base::beg);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
throw CModelIOException(std::string("Error reading version number: ") + e.what());
|
||||
}
|
||||
|
||||
if (version == 1 || version == 2)
|
||||
ReadBinaryModelV1AndV2(model, stream);
|
||||
else if (version == 3)
|
||||
ReadBinaryModelV3(model, stream);
|
||||
else
|
||||
throw CModelIOException(std::string("Unexpected version number: ") + boost::lexical_cast<std::string>(version));
|
||||
}
|
||||
|
||||
void ModelInput::ReadBinaryModelV1AndV2(CModel &model, std::istream &stream)
|
||||
{
|
||||
ModelHeaderV1AndV2 header;
|
||||
try
|
||||
{
|
||||
header.version = ReadBinary<4, int>(stream);
|
||||
header.totalTriangles = ReadBinary<4, int>(stream);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
throw CModelIOException(std::string("Error reading model file header: ") + e.what());
|
||||
}
|
||||
|
||||
CModelMesh mesh;
|
||||
|
||||
try
|
||||
{
|
||||
for (int i = 0; i < header.totalTriangles; ++i)
|
||||
{
|
||||
ModelTriangleV1AndV2 t;
|
||||
|
||||
t.p1 = ReadBinaryVertexTex2(stream);
|
||||
t.p2 = ReadBinaryVertexTex2(stream);
|
||||
t.p3 = ReadBinaryVertexTex2(stream);
|
||||
auto material = ReadBinaryMaterial(stream);
|
||||
t.tex1Name = ReadBinaryString<1>(stream);
|
||||
t.tex2Name = ReadBinaryString<1>(stream);
|
||||
t.variableTex2 = ReadBinaryBool(stream);
|
||||
|
||||
auto diffuse = Gfx::ColorToIntColor(material.diffuse);
|
||||
glm::u8vec4 color = { diffuse.r, diffuse.g, diffuse.b, 255 };
|
||||
|
||||
t.p1.color = color;
|
||||
t.p2.color = color;
|
||||
t.p3.color = color;
|
||||
|
||||
if (header.version == 1)
|
||||
t.lodLevel = static_cast<ModelLODLevel>( ReadBinary<4, int>(stream) );
|
||||
|
||||
t.state = ReadBinary<4, int>(stream);
|
||||
|
||||
if (t.lodLevel == ModelLODLevel::Low ||
|
||||
t.lodLevel == ModelLODLevel::Medium)
|
||||
continue;
|
||||
|
||||
ModelTriangle triangle;
|
||||
triangle.p1 = t.p1;
|
||||
triangle.p2 = t.p2;
|
||||
triangle.p3 = t.p3;
|
||||
triangle.material.albedoTexture = t.tex1Name;
|
||||
triangle.material.detailTexture = t.tex2Name;
|
||||
triangle.material.variableDetail = t.variableTex2;
|
||||
ConvertFromOldRenderState(triangle, t.state);
|
||||
|
||||
mesh.AddTriangle(triangle);
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
throw CModelIOException(std::string("Error reading model data: ") + e.what());
|
||||
}
|
||||
|
||||
model.AddMesh("main", std::move(mesh));
|
||||
}
|
||||
|
||||
void ModelInput::ReadBinaryModelV3(CModel &model, std::istream &stream)
|
||||
{
|
||||
// TODO...
|
||||
}
|
||||
|
||||
void ModelInput::ReadTextModel(CModel &model, std::istream &stream)
|
||||
{
|
||||
int version = 0;
|
||||
try
|
||||
{
|
||||
version = boost::lexical_cast<int>(ReadLineString(stream, "version"));
|
||||
stream.seekg(std::ios_base::beg);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
throw CModelIOException(std::string("Error reading version number: ") + e.what());
|
||||
}
|
||||
|
||||
if (version == 1 || version == 2)
|
||||
ReadTextModelV1AndV2(model, stream);
|
||||
else if (version == 3)
|
||||
ReadTextModelV3(model, stream);
|
||||
else
|
||||
throw CModelIOException(std::string("Unexpected version number: ") + boost::lexical_cast<std::string>(version));
|
||||
}
|
||||
|
||||
void ModelInput::ReadTextModelV1AndV2(CModel &model, std::istream &stream)
|
||||
{
|
||||
ModelHeaderV1AndV2 header;
|
||||
|
||||
try
|
||||
{
|
||||
header.version = boost::lexical_cast<int>(ReadLineString(stream, "version"));
|
||||
header.totalTriangles = boost::lexical_cast<int>(ReadLineString(stream, "total_triangles"));
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
throw CModelIOException(std::string("Error reading model header: ") + e.what());
|
||||
}
|
||||
|
||||
CModelMesh mesh;
|
||||
|
||||
for (int i = 0; i < header.totalTriangles; ++i)
|
||||
{
|
||||
ModelTriangleV1AndV2 t;
|
||||
|
||||
std::string p1Text = ReadLineString(stream, "p1");
|
||||
t.p1 = ParseVertexTex2(p1Text);
|
||||
std::string p2Text = ReadLineString(stream, "p2");
|
||||
t.p2 = ParseVertexTex2(p2Text);
|
||||
std::string p3Text = ReadLineString(stream, "p3");
|
||||
t.p3 = ParseVertexTex2(p3Text);
|
||||
|
||||
std::string matText = ReadLineString(stream, "mat");
|
||||
auto material = ParseMaterial(matText);
|
||||
|
||||
auto diffuse = Gfx::ColorToIntColor(material.diffuse);
|
||||
glm::u8vec4 color = { diffuse.r, diffuse.g, diffuse.b, 255 };
|
||||
|
||||
t.p1.color = color;
|
||||
t.p2.color = color;
|
||||
t.p3.color = color;
|
||||
|
||||
t.tex1Name = ReadLineString(stream, "tex1");
|
||||
t.tex2Name = ReadLineString(stream, "tex2");
|
||||
std::string varTex2Ch = ReadLineString(stream, "var_tex2");
|
||||
t.variableTex2 = varTex2Ch == "Y";
|
||||
|
||||
if (header.version == 1)
|
||||
t.lodLevel = static_cast<ModelLODLevel>( boost::lexical_cast<int>(ReadLineString(stream, "lod_level")) );
|
||||
|
||||
t.state = boost::lexical_cast<int>(ReadLineString(stream, "state"));
|
||||
|
||||
if (t.lodLevel == ModelLODLevel::Low ||
|
||||
t.lodLevel == ModelLODLevel::Medium)
|
||||
continue;
|
||||
|
||||
ModelTriangle triangle;
|
||||
triangle.p1 = t.p1;
|
||||
triangle.p2 = t.p2;
|
||||
triangle.p3 = t.p3;
|
||||
triangle.material.albedoTexture = t.tex1Name;
|
||||
triangle.material.detailTexture = t.tex2Name;
|
||||
triangle.material.variableDetail = t.variableTex2;
|
||||
ConvertFromOldRenderState(triangle, t.state);
|
||||
|
||||
mesh.AddTriangle(triangle);
|
||||
}
|
||||
|
||||
model.AddMesh("main", std::move(mesh));
|
||||
}
|
||||
|
||||
void ModelInput::ReadTextModelV3(CModel &model, std::istream &stream)
|
||||
{
|
||||
ModelHeaderV3 header;
|
||||
|
||||
try
|
||||
{
|
||||
header = ReadTextHeader(stream);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
throw CModelIOException(std::string("Error reading model header: ") + e.what());
|
||||
}
|
||||
|
||||
for (int i = 0; i < header.totalCrashSpheres; ++i)
|
||||
{
|
||||
auto crashSphere = ParseCrashSphere(ReadLineString(stream, "crash_sphere"));
|
||||
model.AddCrashSphere(crashSphere);
|
||||
}
|
||||
|
||||
if (header.hasShadowSpot)
|
||||
{
|
||||
auto shadowSpot = ParseShadowSpot(ReadLineString(stream, "shadow_spot"));
|
||||
model.SetShadowSpot(shadowSpot);
|
||||
}
|
||||
|
||||
if (header.hasCameraCollisionSphere)
|
||||
{
|
||||
auto sphere = ParseCameraCollisionSphere(ReadLineString(stream, "camera_collision_sphere"));
|
||||
model.SetCameraCollisionSphere(sphere);
|
||||
}
|
||||
|
||||
for (int i = 0; i < header.totalMeshes; ++i)
|
||||
{
|
||||
std::string meshName = ReadLineString(stream, "mesh");
|
||||
CModelMesh mesh = ReadTextMesh(stream);
|
||||
model.AddMesh(meshName, std::move(mesh));
|
||||
}
|
||||
}
|
||||
|
||||
ModelHeaderV3 ModelInput::ReadTextHeader(std::istream &stream)
|
||||
{
|
||||
ModelHeaderV3 header;
|
||||
header.version = boost::lexical_cast<int>(ReadLineString(stream, "version"));
|
||||
header.totalCrashSpheres = boost::lexical_cast<int>(ReadLineString(stream, "total_crash_spheres"));
|
||||
header.hasShadowSpot = ReadLineString(stream, "has_shadow_spot") == std::string("Y");
|
||||
header.hasCameraCollisionSphere = ReadLineString(stream, "has_camera_collision_sphere") == std::string("Y");
|
||||
header.totalMeshes = boost::lexical_cast<int>(ReadLineString(stream, "total_meshes"));
|
||||
return header;
|
||||
}
|
||||
|
||||
CModelMesh ModelInput::ReadTextMesh(std::istream& stream)
|
||||
{
|
||||
CModelMesh mesh;
|
||||
|
||||
mesh.SetPosition(ParseVector(ReadLineString(stream, "position")));
|
||||
mesh.SetRotation(ParseVector(ReadLineString(stream, "rotation")));
|
||||
mesh.SetScale(ParseVector(ReadLineString(stream, "scale")));
|
||||
mesh.SetParent(ReadLineString(stream, "parent"));
|
||||
|
||||
int totalTriangles = boost::lexical_cast<int>(ReadLineString(stream, "total_triangles"));
|
||||
|
||||
for (int i = 0; i < totalTriangles; ++i)
|
||||
{
|
||||
ModelTriangleV3 t;
|
||||
|
||||
std::string p1Text = ReadLineString(stream, "p1");
|
||||
t.p1 = ParseVertexTex2(p1Text);
|
||||
std::string p2Text = ReadLineString(stream, "p2");
|
||||
t.p2 = ParseVertexTex2(p2Text);
|
||||
std::string p3Text = ReadLineString(stream, "p3");
|
||||
t.p3 = ParseVertexTex2(p3Text);
|
||||
|
||||
std::string matText = ReadLineString(stream, "mat");
|
||||
LegacyMaterial mat = ParseMaterial(matText);
|
||||
|
||||
auto diffuse = Gfx::ColorToIntColor(mat.diffuse);
|
||||
glm::u8vec4 color = { diffuse.r, diffuse.g, diffuse.b, 255 };
|
||||
|
||||
t.p1.color = color;
|
||||
t.p2.color = color;
|
||||
t.p3.color = color;
|
||||
|
||||
t.material.albedoTexture = ReadLineString(stream, "tex1");
|
||||
t.material.detailTexture = ReadLineString(stream, "tex2");
|
||||
t.material.variableDetail = ReadLineString(stream, "var_tex2") == std::string("Y");
|
||||
|
||||
t.material.alphaMode = ParseTransparentMode(ReadLineString(stream, "trans_mode"));
|
||||
t.material.tag = ParseSpecialMark(ReadLineString(stream, "mark"));
|
||||
bool doubleSided = ReadLineString(stream, "dbl_side") == std::string("Y");
|
||||
t.material.cullFace = doubleSided ? CullFace::NONE : CullFace::BACK;
|
||||
|
||||
if (t.material.alphaMode != AlphaMode::NONE)
|
||||
t.material.alphaThreshold = 0.5f;
|
||||
|
||||
mesh.AddTriangle(t);
|
||||
}
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
void ModelInput::ReadOldModel(CModel &model, std::istream &stream)
|
||||
{
|
||||
OldModelHeader header;
|
||||
|
||||
try
|
||||
{
|
||||
header.revision = ReadBinary<4, int>(stream);
|
||||
header.version = ReadBinary<4, int>(stream);
|
||||
header.totalTriangles = ReadBinary<4, int>(stream);
|
||||
for (int i = 0; i < 10; ++i)
|
||||
header.reserved[i] = ReadBinary<4, int>(stream);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
throw CModelIOException(std::string("Error reading model file header: ") + e.what());
|
||||
}
|
||||
|
||||
std::vector<ModelTriangle> triangles;
|
||||
|
||||
try
|
||||
{
|
||||
if (header.revision == 1 && header.version == 0)
|
||||
{
|
||||
triangles = ReadOldModelV1(stream, header.totalTriangles);
|
||||
}
|
||||
else if (header.revision == 1 && header.version == 1)
|
||||
{
|
||||
triangles = ReadOldModelV2(stream, header.totalTriangles);
|
||||
}
|
||||
else
|
||||
{
|
||||
triangles = ReadOldModelV3(stream, header.totalTriangles);
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
throw CModelIOException(std::string("Error reading model triangles: ") + e.what());
|
||||
}
|
||||
|
||||
CModelMesh mesh;
|
||||
|
||||
for (const auto& triangle : triangles)
|
||||
mesh.AddTriangle(triangle);
|
||||
|
||||
model.AddMesh("main", std::move(mesh));
|
||||
}
|
||||
|
||||
std::vector<ModelTriangle> ModelInput::ReadOldModelV1(std::istream &stream, int totalTriangles)
|
||||
{
|
||||
std::vector<ModelTriangle> triangles;
|
||||
|
||||
for (int i = 0; i < totalTriangles; ++i)
|
||||
{
|
||||
OldModelTriangleV1 t;
|
||||
t.used = ReadBinary<1, char>(stream);
|
||||
t.selected = ReadBinary<1, char>(stream);
|
||||
|
||||
/* padding */ ReadBinary<2, unsigned int>(stream);
|
||||
|
||||
t.p1 = ReadBinaryVertex(stream);
|
||||
t.p2 = ReadBinaryVertex(stream);
|
||||
t.p3 = ReadBinaryVertex(stream);
|
||||
|
||||
auto material = ReadBinaryMaterial(stream);
|
||||
stream.read(t.texName, 20);
|
||||
t.min = ReadBinaryFloat(stream);
|
||||
t.max = ReadBinaryFloat(stream);
|
||||
|
||||
ModelLODLevel lodLevel = MinMaxToLodLevel(t.min, t.max);
|
||||
if (lodLevel == ModelLODLevel::Low ||
|
||||
lodLevel == ModelLODLevel::Medium)
|
||||
continue;
|
||||
|
||||
ModelTriangle triangle;
|
||||
triangle.p1 = t.p1;
|
||||
triangle.p2 = t.p2;
|
||||
triangle.p3 = t.p3;
|
||||
|
||||
auto diffuse = Gfx::ColorToIntColor(material.diffuse);
|
||||
glm::u8vec4 color = { diffuse.r, diffuse.g, diffuse.b, 255 };
|
||||
|
||||
triangle.p1.color = color;
|
||||
triangle.p2.color = color;
|
||||
triangle.p3.color = color;
|
||||
|
||||
ConvertOldTex1Name(triangle, t.texName);
|
||||
|
||||
triangles.push_back(triangle);
|
||||
}
|
||||
|
||||
return triangles;
|
||||
}
|
||||
|
||||
std::vector<ModelTriangle> ModelInput::ReadOldModelV2(std::istream &stream, int totalTriangles)
|
||||
{
|
||||
std::vector<ModelTriangle> triangles;
|
||||
|
||||
for (int i = 0; i < totalTriangles; ++i)
|
||||
{
|
||||
OldModelTriangleV2 t;
|
||||
t.used = ReadBinary<1, char>(stream);
|
||||
t.selected = ReadBinary<1, char>(stream);
|
||||
|
||||
/* padding */ ReadBinary<2, unsigned int>(stream);
|
||||
|
||||
t.p1 = ReadBinaryVertex(stream);
|
||||
t.p2 = ReadBinaryVertex(stream);
|
||||
t.p3 = ReadBinaryVertex(stream);
|
||||
|
||||
auto material = ReadBinaryMaterial(stream);
|
||||
stream.read(t.texName, 20);
|
||||
t.min = ReadBinaryFloat(stream);
|
||||
t.max = ReadBinaryFloat(stream);
|
||||
t.state = ReadBinary<4, long>(stream);
|
||||
|
||||
t.reserved1 = ReadBinary<2, short>(stream);
|
||||
t.reserved2 = ReadBinary<2, short>(stream);
|
||||
t.reserved3 = ReadBinary<2, short>(stream);
|
||||
t.reserved4 = ReadBinary<2, short>(stream);
|
||||
|
||||
ModelLODLevel lodLevel = MinMaxToLodLevel(t.min, t.max);
|
||||
if (lodLevel == ModelLODLevel::Low ||
|
||||
lodLevel == ModelLODLevel::Medium)
|
||||
continue;
|
||||
|
||||
ModelTriangle triangle;
|
||||
triangle.p1 = t.p1;
|
||||
triangle.p2 = t.p2;
|
||||
triangle.p3 = t.p3;
|
||||
|
||||
auto diffuse = Gfx::ColorToIntColor(material.diffuse);
|
||||
glm::u8vec4 color = { diffuse.r, diffuse.g, diffuse.b, 255 };
|
||||
|
||||
triangle.p1.color = color;
|
||||
triangle.p2.color = color;
|
||||
triangle.p3.color = color;
|
||||
|
||||
ConvertOldTex1Name(triangle, t.texName);
|
||||
|
||||
ConvertFromOldRenderState(triangle, t.state);
|
||||
|
||||
triangles.push_back(triangle);
|
||||
}
|
||||
|
||||
return triangles;
|
||||
}
|
||||
|
||||
std::vector<ModelTriangle> ModelInput::ReadOldModelV3(std::istream &stream, int totalTriangles)
|
||||
{
|
||||
std::vector<ModelTriangle> triangles;
|
||||
|
||||
for (int i = 0; i < totalTriangles; ++i)
|
||||
{
|
||||
OldModelTriangleV3 t;
|
||||
t.used = ReadBinary<1, char>(stream);
|
||||
t.selected = ReadBinary<1, char>(stream);
|
||||
|
||||
/* padding */ ReadBinary<2, unsigned int>(stream);
|
||||
|
||||
t.p1 = ReadBinaryVertexTex2(stream);
|
||||
t.p2 = ReadBinaryVertexTex2(stream);
|
||||
t.p3 = ReadBinaryVertexTex2(stream);
|
||||
|
||||
auto material = ReadBinaryMaterial(stream);
|
||||
stream.read(t.texName, 20);
|
||||
t.min = ReadBinaryFloat(stream);
|
||||
t.max = ReadBinaryFloat(stream);
|
||||
t.state = ReadBinary<4, long>(stream);
|
||||
t.texNum2 = ReadBinary<2, short>(stream);
|
||||
|
||||
t.reserved2 = ReadBinary<2, short>(stream);
|
||||
t.reserved3 = ReadBinary<2, short>(stream);
|
||||
t.reserved4 = ReadBinary<2, short>(stream);
|
||||
|
||||
ModelLODLevel lodLevel = MinMaxToLodLevel(t.min, t.max);
|
||||
if (lodLevel == ModelLODLevel::Low ||
|
||||
lodLevel == ModelLODLevel::Medium)
|
||||
continue;
|
||||
|
||||
ModelTriangle triangle;
|
||||
triangle.p1 = t.p1;
|
||||
triangle.p2 = t.p2;
|
||||
triangle.p3 = t.p3;
|
||||
|
||||
auto diffuse = Gfx::ColorToIntColor(material.diffuse);
|
||||
glm::u8vec4 color = { diffuse.r, diffuse.g, diffuse.b, 255 };
|
||||
|
||||
triangle.p1.color = color;
|
||||
triangle.p2.color = color;
|
||||
triangle.p3.color = color;
|
||||
|
||||
ConvertOldTex1Name(triangle, t.texName);
|
||||
|
||||
ConvertFromOldRenderState(triangle, t.state);
|
||||
triangle.material.variableDetail = t.texNum2 == 1;
|
||||
|
||||
if (!triangle.material.variableDetail && t.texNum2 != 0)
|
||||
{
|
||||
char tex2Name[20] = { 0 };
|
||||
std::sprintf(tex2Name, "dirty%.2d.png", t.texNum2);
|
||||
triangle.material.detailTexture = tex2Name;
|
||||
}
|
||||
|
||||
triangles.push_back(triangle);
|
||||
}
|
||||
|
||||
return triangles;
|
||||
}
|
||||
|
||||
ModelLODLevel ModelInput::MinMaxToLodLevel(float min, float max)
|
||||
{
|
||||
if (min == 0.0f && max == 100.0f)
|
||||
return ModelLODLevel::High;
|
||||
else if (min == 100.0f && max == 200.0f)
|
||||
return ModelLODLevel::Medium;
|
||||
else if (min == 200.0f && max == 1000000.0f)
|
||||
return ModelLODLevel::Low;
|
||||
else if (min == 0.0f && max == 1000000.0f)
|
||||
return ModelLODLevel::Constant;
|
||||
|
||||
return ModelLODLevel::Constant;
|
||||
}
|
||||
|
||||
void ModelInput::ConvertOldTex1Name(ModelTriangle& triangle, const char* tex1Name)
|
||||
{
|
||||
triangle.material.albedoTexture = tex1Name;
|
||||
boost::replace_all(triangle.material.albedoTexture, "bmp", "png");
|
||||
boost::replace_all(triangle.material.albedoTexture, "tga", "png");
|
||||
}
|
||||
|
||||
void ModelInput::ConvertFromOldRenderState(ModelTriangle& triangle, int state)
|
||||
{
|
||||
if (triangle.material.albedoTexture == "plant.png" || (state & static_cast<int>(ModelRenderState::Alpha)) != 0)
|
||||
{
|
||||
triangle.material.alphaMode = AlphaMode::MASK;
|
||||
triangle.material.alphaThreshold = 0.5f;
|
||||
}
|
||||
else
|
||||
triangle.material.alphaMode = AlphaMode::NONE;
|
||||
|
||||
if ((state & static_cast<int>(ModelRenderState::Part1)) != 0)
|
||||
triangle.material.tag = "tracker_right";
|
||||
else if ((state & static_cast<int>(ModelRenderState::Part2)) != 0)
|
||||
triangle.material.tag = "tracker_left";
|
||||
else if ((state & static_cast<int>(ModelRenderState::Part3)) != 0)
|
||||
triangle.material.tag = "energy";
|
||||
else
|
||||
triangle.material.tag = "";
|
||||
|
||||
bool doubleSided = (state & static_cast<int>(ModelRenderState::TwoFace)) != 0;
|
||||
triangle.material.cullFace = doubleSided ? CullFace::NONE : CullFace::BACK;
|
||||
}
|
||||
|
||||
Vertex3D ModelInput::ReadBinaryVertex(std::istream& stream)
|
||||
{
|
||||
Vertex3D vertex;
|
||||
|
||||
vertex.position.x = ReadBinaryFloat(stream);
|
||||
vertex.position.y = ReadBinaryFloat(stream);
|
||||
vertex.position.z = ReadBinaryFloat(stream);
|
||||
|
||||
vertex.normal.x = ReadBinaryFloat(stream);
|
||||
vertex.normal.y = ReadBinaryFloat(stream);
|
||||
vertex.normal.z = ReadBinaryFloat(stream);
|
||||
|
||||
vertex.uv.x = ReadBinaryFloat(stream);
|
||||
vertex.uv.y = ReadBinaryFloat(stream);
|
||||
|
||||
return vertex;
|
||||
}
|
||||
|
||||
Vertex3D ModelInput::ReadBinaryVertexTex2(std::istream& stream)
|
||||
{
|
||||
Vertex3D vertex;
|
||||
|
||||
vertex.position.x = ReadBinaryFloat(stream);
|
||||
vertex.position.y = ReadBinaryFloat(stream);
|
||||
vertex.position.z = ReadBinaryFloat(stream);
|
||||
|
||||
vertex.normal.x = ReadBinaryFloat(stream);
|
||||
vertex.normal.y = ReadBinaryFloat(stream);
|
||||
vertex.normal.z = ReadBinaryFloat(stream);
|
||||
|
||||
vertex.uv.x = ReadBinaryFloat(stream);
|
||||
vertex.uv.y = ReadBinaryFloat(stream);
|
||||
|
||||
vertex.uv2.x = ReadBinaryFloat(stream);
|
||||
vertex.uv2.y = ReadBinaryFloat(stream);
|
||||
|
||||
return vertex;
|
||||
}
|
||||
|
||||
LegacyMaterial ModelInput::ReadBinaryMaterial(std::istream& stream)
|
||||
{
|
||||
LegacyMaterial material;
|
||||
|
||||
material.diffuse.r = ReadBinaryFloat(stream);
|
||||
material.diffuse.g = ReadBinaryFloat(stream);
|
||||
material.diffuse.b = ReadBinaryFloat(stream);
|
||||
material.diffuse.a = ReadBinaryFloat(stream);
|
||||
|
||||
material.ambient.r = ReadBinaryFloat(stream);
|
||||
material.ambient.g = ReadBinaryFloat(stream);
|
||||
material.ambient.b = ReadBinaryFloat(stream);
|
||||
material.ambient.a = ReadBinaryFloat(stream);
|
||||
|
||||
material.specular.r = ReadBinaryFloat(stream);
|
||||
material.specular.g = ReadBinaryFloat(stream);
|
||||
material.specular.b = ReadBinaryFloat(stream);
|
||||
material.specular.a = ReadBinaryFloat(stream);
|
||||
|
||||
/* emissive.r = */ ReadBinaryFloat(stream);
|
||||
/* emissive.g = */ ReadBinaryFloat(stream);
|
||||
/* emissive.b = */ ReadBinaryFloat(stream);
|
||||
/* emissive.a = */ ReadBinaryFloat(stream);
|
||||
|
||||
/* power = */ ReadBinaryFloat(stream);
|
||||
|
||||
return material;
|
||||
}
|
||||
|
||||
|
||||
std::string ModelInput::ReadLineString(std::istream& stream, const std::string& expectedPrefix)
|
||||
{
|
||||
std::string line;
|
||||
while (true)
|
||||
{
|
||||
if (stream.eof())
|
||||
throw CModelIOException("Unexpected EOF");
|
||||
|
||||
std::getline(stream, line);
|
||||
boost::trim_right(line);
|
||||
if (!line.empty() && line[0] != '#')
|
||||
break;
|
||||
}
|
||||
|
||||
std::stringstream s;
|
||||
s.str(line);
|
||||
|
||||
std::string prefix;
|
||||
s >> prefix;
|
||||
if (prefix != expectedPrefix)
|
||||
throw CModelIOException(std::string("Unexpected prefix: '") + prefix + "'");
|
||||
|
||||
std::string value;
|
||||
std::getline(s, value);
|
||||
boost::trim_left(value);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
void ModelInput::ReadValuePrefix(std::istream& stream, const std::string& expectedPrefix)
|
||||
{
|
||||
std::string prefix;
|
||||
stream >> prefix;
|
||||
if (prefix != expectedPrefix)
|
||||
throw CModelIOException(std::string("Unexpected prefix: '") + prefix + "', expected was: '" + expectedPrefix + "'");
|
||||
}
|
||||
|
||||
Vertex3D ModelInput::ParseVertexTex2(const std::string& text)
|
||||
{
|
||||
Vertex3D vertex;
|
||||
|
||||
std::stringstream stream;
|
||||
stream.str(text);
|
||||
|
||||
ReadValuePrefix(stream, "c");
|
||||
stream >> vertex.position.x >> vertex.position.y >> vertex.position.z;
|
||||
|
||||
ReadValuePrefix(stream, "n");
|
||||
stream >> vertex.normal.x >> vertex.normal.y >> vertex.normal.z;
|
||||
|
||||
ReadValuePrefix(stream, "t1");
|
||||
stream >> vertex.uv.x >> vertex.uv.y;
|
||||
|
||||
ReadValuePrefix(stream, "t2");
|
||||
stream >> vertex.uv2.x >> vertex.uv2.y;
|
||||
|
||||
return vertex;
|
||||
}
|
||||
|
||||
LegacyMaterial ModelInput::ParseMaterial(const std::string& text)
|
||||
{
|
||||
LegacyMaterial material;
|
||||
|
||||
std::stringstream stream;
|
||||
stream.str(text);
|
||||
|
||||
ReadValuePrefix(stream, "dif");
|
||||
stream >> material.diffuse.r
|
||||
>> material.diffuse.g
|
||||
>> material.diffuse.b
|
||||
>> material.diffuse.a;
|
||||
|
||||
ReadValuePrefix(stream, "amb");
|
||||
stream >> material.ambient.r
|
||||
>> material.ambient.g
|
||||
>> material.ambient.b
|
||||
>> material.ambient.a;
|
||||
|
||||
ReadValuePrefix(stream, "spc");
|
||||
stream >> material.specular.r
|
||||
>> material.specular.g
|
||||
>> material.specular.b
|
||||
>> material.specular.a;
|
||||
|
||||
return material;
|
||||
}
|
||||
|
||||
glm::vec3 ModelInput::ParseVector(const std::string& text)
|
||||
{
|
||||
glm::vec3 vector = { 0, 0, 0 };
|
||||
|
||||
std::stringstream stream;
|
||||
stream.str(text);
|
||||
|
||||
stream >> vector.x >> vector.y >> vector.z;
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
ModelCrashSphere ModelInput::ParseCrashSphere(const std::string& text)
|
||||
{
|
||||
ModelCrashSphere crashSphere;
|
||||
|
||||
std::stringstream stream;
|
||||
stream.str(text);
|
||||
|
||||
ReadValuePrefix(stream, "pos");
|
||||
stream >> crashSphere.position.x
|
||||
>> crashSphere.position.y
|
||||
>> crashSphere.position.z;
|
||||
|
||||
ReadValuePrefix(stream, "rad");
|
||||
stream >> crashSphere.radius;
|
||||
|
||||
ReadValuePrefix(stream, "sound");
|
||||
stream >> crashSphere.sound;
|
||||
|
||||
ReadValuePrefix(stream, "hard");
|
||||
stream >> crashSphere.hardness;
|
||||
|
||||
return crashSphere;
|
||||
}
|
||||
|
||||
ModelShadowSpot ModelInput::ParseShadowSpot(const std::string& text)
|
||||
{
|
||||
ModelShadowSpot shadowSpot;
|
||||
|
||||
std::stringstream stream;
|
||||
stream.str(text);
|
||||
|
||||
ReadValuePrefix(stream, "rad");
|
||||
stream >> shadowSpot.radius;
|
||||
|
||||
ReadValuePrefix(stream, "int");
|
||||
stream >> shadowSpot.intensity;
|
||||
|
||||
return shadowSpot;
|
||||
}
|
||||
|
||||
Math::Sphere ModelInput::ParseCameraCollisionSphere(const std::string& text)
|
||||
{
|
||||
Math::Sphere sphere;
|
||||
|
||||
std::stringstream stream;
|
||||
stream.str(text);
|
||||
|
||||
ReadValuePrefix(stream, "pos");
|
||||
stream >> sphere.pos.x
|
||||
>> sphere.pos.y
|
||||
>> sphere.pos.z;
|
||||
|
||||
ReadValuePrefix(stream, "rad");
|
||||
stream >> sphere.radius;
|
||||
|
||||
return sphere;
|
||||
}
|
||||
|
||||
AlphaMode ModelInput::ParseTransparentMode(const std::string& text)
|
||||
{
|
||||
if (text == "none")
|
||||
return AlphaMode::NONE;
|
||||
else if (text == "alpha")
|
||||
return AlphaMode::MASK;
|
||||
else
|
||||
return AlphaMode::NONE;
|
||||
}
|
||||
|
||||
std::string ModelInput::ParseSpecialMark(const std::string& text)
|
||||
{
|
||||
if (text == "none")
|
||||
return "";
|
||||
else if (text == "part1")
|
||||
return "tracker_right";
|
||||
else if (text == "part2")
|
||||
return "tracker_left";
|
||||
else if (text == "part3")
|
||||
return "energy";
|
||||
else
|
||||
throw CModelIOException(std::string("Unexpected special mark: '") + text + "'");
|
||||
}
|
||||
|
||||
} // namespace Gfx
|
||||
|
|
|
@ -57,6 +57,27 @@ enum class ModelRenderState
|
|||
Alpha = 8192 //!< old ENG_RSTATE_ALPHA
|
||||
};
|
||||
|
||||
//! Legacy material structure
|
||||
struct LegacyMaterial
|
||||
{
|
||||
//! Diffuse color
|
||||
Color diffuse;
|
||||
//! Ambient color
|
||||
Color ambient;
|
||||
//! Specular color
|
||||
Color specular;
|
||||
|
||||
bool operator==(const LegacyMaterial& mat) const
|
||||
{
|
||||
return diffuse == mat.diffuse && ambient == mat.ambient && specular == mat.specular;
|
||||
}
|
||||
|
||||
bool operator!=(const LegacyMaterial& mat) const
|
||||
{
|
||||
return !operator==(mat);
|
||||
}
|
||||
};
|
||||
|
||||
/*******************************************************
|
||||
New model formats
|
||||
*******************************************************/
|
||||
|
|
|
@ -0,0 +1,371 @@
|
|||
/*
|
||||
* This file is part of the Colobot: Gold Edition source code
|
||||
* Copyright (C) 2001-2022, Daniel Roux, EPSITEC SA & TerranovaTeam
|
||||
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
|
||||
*
|
||||
* 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://gnu.org/licenses
|
||||
*/
|
||||
|
||||
#include "graphics/model/model_mod.h"
|
||||
|
||||
#include "common/ioutils.h"
|
||||
#include "common/resources/inputstream.h"
|
||||
|
||||
#include "graphics/model/model_io_exception.h"
|
||||
#include "graphics/model/model_io_structs.h"
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace IOUtils;
|
||||
|
||||
namespace Gfx::ModelIO
|
||||
{
|
||||
|
||||
std::vector<ModelTriangle> ReadOldModelV1(std::istream& stream, int totalTriangles);
|
||||
std::vector<ModelTriangle> ReadOldModelV2(std::istream& stream, int totalTriangles);
|
||||
std::vector<ModelTriangle> ReadOldModelV3(std::istream& stream, int totalTriangles);
|
||||
|
||||
Vertex3D ReadBinaryVertex(std::istream& stream);
|
||||
Vertex3D ReadBinaryVertexTex2(std::istream& stream);
|
||||
LegacyMaterial ReadBinaryMaterial(std::istream& stream);
|
||||
|
||||
void ConvertOldTex1Name(ModelTriangle& triangle, const char* tex1Name);
|
||||
void ConvertFromOldRenderState(ModelTriangle& triangle, int state);
|
||||
ModelLODLevel MinMaxToLodLevel(float min, float max);
|
||||
|
||||
void ReadOldModel(CModel& model, std::istream& stream)
|
||||
{
|
||||
OldModelHeader header;
|
||||
|
||||
try
|
||||
{
|
||||
header.revision = ReadBinary<4, int>(stream);
|
||||
header.version = ReadBinary<4, int>(stream);
|
||||
header.totalTriangles = ReadBinary<4, int>(stream);
|
||||
for (int i = 0; i < 10; ++i)
|
||||
header.reserved[i] = ReadBinary<4, int>(stream);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
throw CModelIOException(std::string("Error reading model file header: ") + e.what());
|
||||
}
|
||||
|
||||
std::vector<ModelTriangle> triangles;
|
||||
|
||||
try
|
||||
{
|
||||
if (header.revision == 1 && header.version == 0)
|
||||
{
|
||||
triangles = ReadOldModelV1(stream, header.totalTriangles);
|
||||
}
|
||||
else if (header.revision == 1 && header.version == 1)
|
||||
{
|
||||
triangles = ReadOldModelV2(stream, header.totalTriangles);
|
||||
}
|
||||
else
|
||||
{
|
||||
triangles = ReadOldModelV3(stream, header.totalTriangles);
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
throw CModelIOException(std::string("Error reading model triangles: ") + e.what());
|
||||
}
|
||||
|
||||
CModelMesh mesh;
|
||||
|
||||
for (const auto& triangle : triangles)
|
||||
mesh.AddTriangle(triangle);
|
||||
|
||||
model.AddMesh("main", std::move(mesh));
|
||||
}
|
||||
|
||||
std::vector<ModelTriangle> ReadOldModelV1(std::istream& stream, int totalTriangles)
|
||||
{
|
||||
std::vector<ModelTriangle> triangles;
|
||||
|
||||
for (int i = 0; i < totalTriangles; ++i)
|
||||
{
|
||||
OldModelTriangleV1 t;
|
||||
t.used = ReadBinary<1, char>(stream);
|
||||
t.selected = ReadBinary<1, char>(stream);
|
||||
|
||||
/* padding */ ReadBinary<2, unsigned int>(stream);
|
||||
|
||||
t.p1 = ReadBinaryVertex(stream);
|
||||
t.p2 = ReadBinaryVertex(stream);
|
||||
t.p3 = ReadBinaryVertex(stream);
|
||||
|
||||
auto material = ReadBinaryMaterial(stream);
|
||||
stream.read(t.texName, 20);
|
||||
t.min = ReadBinaryFloat(stream);
|
||||
t.max = ReadBinaryFloat(stream);
|
||||
|
||||
ModelLODLevel lodLevel = MinMaxToLodLevel(t.min, t.max);
|
||||
if (lodLevel == ModelLODLevel::Low ||
|
||||
lodLevel == ModelLODLevel::Medium)
|
||||
continue;
|
||||
|
||||
ModelTriangle triangle;
|
||||
triangle.p1 = t.p1;
|
||||
triangle.p2 = t.p2;
|
||||
triangle.p3 = t.p3;
|
||||
|
||||
auto diffuse = Gfx::ColorToIntColor(material.diffuse);
|
||||
glm::u8vec4 color = { diffuse.r, diffuse.g, diffuse.b, 255 };
|
||||
|
||||
triangle.p1.color = color;
|
||||
triangle.p2.color = color;
|
||||
triangle.p3.color = color;
|
||||
|
||||
ConvertOldTex1Name(triangle, t.texName);
|
||||
|
||||
triangles.push_back(triangle);
|
||||
}
|
||||
|
||||
return triangles;
|
||||
}
|
||||
|
||||
std::vector<ModelTriangle> ReadOldModelV2(std::istream& stream, int totalTriangles)
|
||||
{
|
||||
std::vector<ModelTriangle> triangles;
|
||||
|
||||
for (int i = 0; i < totalTriangles; ++i)
|
||||
{
|
||||
OldModelTriangleV2 t;
|
||||
t.used = ReadBinary<1, char>(stream);
|
||||
t.selected = ReadBinary<1, char>(stream);
|
||||
|
||||
/* padding */ ReadBinary<2, unsigned int>(stream);
|
||||
|
||||
t.p1 = ReadBinaryVertex(stream);
|
||||
t.p2 = ReadBinaryVertex(stream);
|
||||
t.p3 = ReadBinaryVertex(stream);
|
||||
|
||||
auto material = ReadBinaryMaterial(stream);
|
||||
stream.read(t.texName, 20);
|
||||
t.min = ReadBinaryFloat(stream);
|
||||
t.max = ReadBinaryFloat(stream);
|
||||
t.state = ReadBinary<4, long>(stream);
|
||||
|
||||
t.reserved1 = ReadBinary<2, short>(stream);
|
||||
t.reserved2 = ReadBinary<2, short>(stream);
|
||||
t.reserved3 = ReadBinary<2, short>(stream);
|
||||
t.reserved4 = ReadBinary<2, short>(stream);
|
||||
|
||||
ModelLODLevel lodLevel = MinMaxToLodLevel(t.min, t.max);
|
||||
if (lodLevel == ModelLODLevel::Low ||
|
||||
lodLevel == ModelLODLevel::Medium)
|
||||
continue;
|
||||
|
||||
ModelTriangle triangle;
|
||||
triangle.p1 = t.p1;
|
||||
triangle.p2 = t.p2;
|
||||
triangle.p3 = t.p3;
|
||||
|
||||
auto diffuse = Gfx::ColorToIntColor(material.diffuse);
|
||||
glm::u8vec4 color = { diffuse.r, diffuse.g, diffuse.b, 255 };
|
||||
|
||||
triangle.p1.color = color;
|
||||
triangle.p2.color = color;
|
||||
triangle.p3.color = color;
|
||||
|
||||
ConvertOldTex1Name(triangle, t.texName);
|
||||
|
||||
ConvertFromOldRenderState(triangle, t.state);
|
||||
|
||||
triangles.push_back(triangle);
|
||||
}
|
||||
|
||||
return triangles;
|
||||
}
|
||||
|
||||
std::vector<ModelTriangle> ReadOldModelV3(std::istream& stream, int totalTriangles)
|
||||
{
|
||||
std::vector<ModelTriangle> triangles;
|
||||
|
||||
for (int i = 0; i < totalTriangles; ++i)
|
||||
{
|
||||
OldModelTriangleV3 t;
|
||||
t.used = ReadBinary<1, char>(stream);
|
||||
t.selected = ReadBinary<1, char>(stream);
|
||||
|
||||
/* padding */ ReadBinary<2, unsigned int>(stream);
|
||||
|
||||
t.p1 = ReadBinaryVertexTex2(stream);
|
||||
t.p2 = ReadBinaryVertexTex2(stream);
|
||||
t.p3 = ReadBinaryVertexTex2(stream);
|
||||
|
||||
auto material = ReadBinaryMaterial(stream);
|
||||
stream.read(t.texName, 20);
|
||||
t.min = ReadBinaryFloat(stream);
|
||||
t.max = ReadBinaryFloat(stream);
|
||||
t.state = ReadBinary<4, long>(stream);
|
||||
t.texNum2 = ReadBinary<2, short>(stream);
|
||||
|
||||
t.reserved2 = ReadBinary<2, short>(stream);
|
||||
t.reserved3 = ReadBinary<2, short>(stream);
|
||||
t.reserved4 = ReadBinary<2, short>(stream);
|
||||
|
||||
ModelLODLevel lodLevel = MinMaxToLodLevel(t.min, t.max);
|
||||
if (lodLevel == ModelLODLevel::Low ||
|
||||
lodLevel == ModelLODLevel::Medium)
|
||||
continue;
|
||||
|
||||
ModelTriangle triangle;
|
||||
triangle.p1 = t.p1;
|
||||
triangle.p2 = t.p2;
|
||||
triangle.p3 = t.p3;
|
||||
|
||||
auto diffuse = Gfx::ColorToIntColor(material.diffuse);
|
||||
glm::u8vec4 color = { diffuse.r, diffuse.g, diffuse.b, 255 };
|
||||
|
||||
triangle.p1.color = color;
|
||||
triangle.p2.color = color;
|
||||
triangle.p3.color = color;
|
||||
|
||||
ConvertOldTex1Name(triangle, t.texName);
|
||||
|
||||
ConvertFromOldRenderState(triangle, t.state);
|
||||
triangle.material.variableDetail = t.texNum2 == 1;
|
||||
|
||||
if (!triangle.material.variableDetail && t.texNum2 != 0)
|
||||
{
|
||||
char tex2Name[20] = { 0 };
|
||||
std::sprintf(tex2Name, "dirty%.2d.png", t.texNum2);
|
||||
triangle.material.detailTexture = tex2Name;
|
||||
}
|
||||
|
||||
triangles.push_back(triangle);
|
||||
}
|
||||
|
||||
return triangles;
|
||||
}
|
||||
|
||||
ModelLODLevel MinMaxToLodLevel(float min, float max)
|
||||
{
|
||||
if (min == 0.0f && max == 100.0f)
|
||||
return ModelLODLevel::High;
|
||||
else if (min == 100.0f && max == 200.0f)
|
||||
return ModelLODLevel::Medium;
|
||||
else if (min == 200.0f && max == 1000000.0f)
|
||||
return ModelLODLevel::Low;
|
||||
else if (min == 0.0f && max == 1000000.0f)
|
||||
return ModelLODLevel::Constant;
|
||||
|
||||
return ModelLODLevel::Constant;
|
||||
}
|
||||
|
||||
void ConvertOldTex1Name(ModelTriangle& triangle, const char* tex1Name)
|
||||
{
|
||||
triangle.material.albedoTexture = tex1Name;
|
||||
boost::replace_all(triangle.material.albedoTexture, "bmp", "png");
|
||||
boost::replace_all(triangle.material.albedoTexture, "tga", "png");
|
||||
}
|
||||
|
||||
void ConvertFromOldRenderState(ModelTriangle& triangle, int state)
|
||||
{
|
||||
if (triangle.material.albedoTexture == "plant.png" || (state & static_cast<int>(ModelRenderState::Alpha)) != 0)
|
||||
{
|
||||
triangle.material.alphaMode = AlphaMode::MASK;
|
||||
triangle.material.alphaThreshold = 0.5f;
|
||||
}
|
||||
else
|
||||
triangle.material.alphaMode = AlphaMode::NONE;
|
||||
|
||||
if ((state & static_cast<int>(ModelRenderState::Part1)) != 0)
|
||||
triangle.material.tag = "tracker_right";
|
||||
else if ((state & static_cast<int>(ModelRenderState::Part2)) != 0)
|
||||
triangle.material.tag = "tracker_left";
|
||||
else if ((state & static_cast<int>(ModelRenderState::Part3)) != 0)
|
||||
triangle.material.tag = "energy";
|
||||
else
|
||||
triangle.material.tag = "";
|
||||
|
||||
bool doubleSided = (state & static_cast<int>(ModelRenderState::TwoFace)) != 0;
|
||||
triangle.material.cullFace = doubleSided ? CullFace::NONE : CullFace::BACK;
|
||||
}
|
||||
|
||||
Vertex3D ReadBinaryVertex(std::istream& stream)
|
||||
{
|
||||
Vertex3D vertex;
|
||||
|
||||
vertex.position.x = ReadBinaryFloat(stream);
|
||||
vertex.position.y = ReadBinaryFloat(stream);
|
||||
vertex.position.z = ReadBinaryFloat(stream);
|
||||
|
||||
vertex.normal.x = ReadBinaryFloat(stream);
|
||||
vertex.normal.y = ReadBinaryFloat(stream);
|
||||
vertex.normal.z = ReadBinaryFloat(stream);
|
||||
|
||||
vertex.uv.x = ReadBinaryFloat(stream);
|
||||
vertex.uv.y = ReadBinaryFloat(stream);
|
||||
|
||||
return vertex;
|
||||
}
|
||||
|
||||
Vertex3D ReadBinaryVertexTex2(std::istream& stream)
|
||||
{
|
||||
Vertex3D vertex;
|
||||
|
||||
vertex.position.x = ReadBinaryFloat(stream);
|
||||
vertex.position.y = ReadBinaryFloat(stream);
|
||||
vertex.position.z = ReadBinaryFloat(stream);
|
||||
|
||||
vertex.normal.x = ReadBinaryFloat(stream);
|
||||
vertex.normal.y = ReadBinaryFloat(stream);
|
||||
vertex.normal.z = ReadBinaryFloat(stream);
|
||||
|
||||
vertex.uv.x = ReadBinaryFloat(stream);
|
||||
vertex.uv.y = ReadBinaryFloat(stream);
|
||||
|
||||
vertex.uv2.x = ReadBinaryFloat(stream);
|
||||
vertex.uv2.y = ReadBinaryFloat(stream);
|
||||
|
||||
return vertex;
|
||||
}
|
||||
|
||||
LegacyMaterial ReadBinaryMaterial(std::istream& stream)
|
||||
{
|
||||
LegacyMaterial material;
|
||||
|
||||
material.diffuse.r = ReadBinaryFloat(stream);
|
||||
material.diffuse.g = ReadBinaryFloat(stream);
|
||||
material.diffuse.b = ReadBinaryFloat(stream);
|
||||
material.diffuse.a = ReadBinaryFloat(stream);
|
||||
|
||||
material.ambient.r = ReadBinaryFloat(stream);
|
||||
material.ambient.g = ReadBinaryFloat(stream);
|
||||
material.ambient.b = ReadBinaryFloat(stream);
|
||||
material.ambient.a = ReadBinaryFloat(stream);
|
||||
|
||||
material.specular.r = ReadBinaryFloat(stream);
|
||||
material.specular.g = ReadBinaryFloat(stream);
|
||||
material.specular.b = ReadBinaryFloat(stream);
|
||||
material.specular.a = ReadBinaryFloat(stream);
|
||||
|
||||
/* emissive.r = */ ReadBinaryFloat(stream);
|
||||
/* emissive.g = */ ReadBinaryFloat(stream);
|
||||
/* emissive.b = */ ReadBinaryFloat(stream);
|
||||
/* emissive.a = */ ReadBinaryFloat(stream);
|
||||
|
||||
/* power = */ ReadBinaryFloat(stream);
|
||||
|
||||
return material;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* This file is part of the Colobot: Gold Edition source code
|
||||
* Copyright (C) 2001-2022, Daniel Roux, EPSITEC SA & TerranovaTeam
|
||||
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
|
||||
*
|
||||
* 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://gnu.org/licenses
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "graphics/model/model.h"
|
||||
#include "graphics/model/model_format.h"
|
||||
|
||||
#include <istream>
|
||||
|
||||
/**
|
||||
* \namespace ModelInput
|
||||
* \brief Namespace with functions to read model files
|
||||
*/
|
||||
namespace Gfx::ModelIO
|
||||
{
|
||||
|
||||
void ReadOldModel(CModel& model, std::istream& stream);
|
||||
|
||||
}
|
|
@ -0,0 +1,425 @@
|
|||
/*
|
||||
* This file is part of the Colobot: Gold Edition source code
|
||||
* Copyright (C) 2001-2022, Daniel Roux, EPSITEC SA & TerranovaTeam
|
||||
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
|
||||
*
|
||||
* 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://gnu.org/licenses
|
||||
*/
|
||||
|
||||
#include "graphics/model/model_mod.h"
|
||||
|
||||
#include "common/ioutils.h"
|
||||
#include "common/resources/inputstream.h"
|
||||
|
||||
#include "graphics/model/model_io_exception.h"
|
||||
#include "graphics/model/model_io_structs.h"
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
using namespace IOUtils;
|
||||
|
||||
namespace Gfx::ModelIO
|
||||
{
|
||||
|
||||
void ReadTextModelV1AndV2(CModel& model, std::istream& stream);
|
||||
void ReadTextModelV3(CModel& model, std::istream& stream);
|
||||
ModelHeaderV3 ReadTextHeader(std::istream& stream);
|
||||
CModelMesh ReadTextMesh(std::istream& stream);
|
||||
|
||||
std::string ReadLineString(std::istream& stream, const std::string& expectedPrefix);
|
||||
void ReadValuePrefix(std::istream& stream, const std::string& expectedPrefix);
|
||||
Vertex3D ParseVertexTex2(const std::string& text);
|
||||
LegacyMaterial ParseMaterial(const std::string& text);
|
||||
glm::vec3 ParseVector(const std::string& text);
|
||||
ModelCrashSphere ParseCrashSphere(const std::string& text);
|
||||
ModelShadowSpot ParseShadowSpot(const std::string& text);
|
||||
Math::Sphere ParseCameraCollisionSphere(const std::string& text);
|
||||
AlphaMode ParseTransparentMode(const std::string& text);
|
||||
std::string ParseSpecialMark(const std::string& text);
|
||||
|
||||
void ConvertFromOldRenderState(ModelTriangle& triangle, int state);
|
||||
|
||||
void ReadTextModel(CModel& model, std::istream& stream)
|
||||
{
|
||||
int version = 0;
|
||||
try
|
||||
{
|
||||
version = boost::lexical_cast<int>(ReadLineString(stream, "version"));
|
||||
stream.seekg(std::ios_base::beg);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
throw CModelIOException(std::string("Error reading version number: ") + e.what());
|
||||
}
|
||||
|
||||
if (version == 1 || version == 2)
|
||||
ReadTextModelV1AndV2(model, stream);
|
||||
else if (version == 3)
|
||||
ReadTextModelV3(model, stream);
|
||||
else
|
||||
throw CModelIOException(std::string("Unexpected version number: ") + boost::lexical_cast<std::string>(version));
|
||||
}
|
||||
|
||||
void ReadTextModelV1AndV2(CModel& model, std::istream& stream)
|
||||
{
|
||||
ModelHeaderV1AndV2 header;
|
||||
|
||||
try
|
||||
{
|
||||
header.version = boost::lexical_cast<int>(ReadLineString(stream, "version"));
|
||||
header.totalTriangles = boost::lexical_cast<int>(ReadLineString(stream, "total_triangles"));
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
throw CModelIOException(std::string("Error reading model header: ") + e.what());
|
||||
}
|
||||
|
||||
CModelMesh mesh;
|
||||
|
||||
for (int i = 0; i < header.totalTriangles; ++i)
|
||||
{
|
||||
ModelTriangleV1AndV2 t;
|
||||
|
||||
std::string p1Text = ReadLineString(stream, "p1");
|
||||
t.p1 = ParseVertexTex2(p1Text);
|
||||
std::string p2Text = ReadLineString(stream, "p2");
|
||||
t.p2 = ParseVertexTex2(p2Text);
|
||||
std::string p3Text = ReadLineString(stream, "p3");
|
||||
t.p3 = ParseVertexTex2(p3Text);
|
||||
|
||||
std::string matText = ReadLineString(stream, "mat");
|
||||
auto material = ParseMaterial(matText);
|
||||
|
||||
auto diffuse = Gfx::ColorToIntColor(material.diffuse);
|
||||
glm::u8vec4 color = { diffuse.r, diffuse.g, diffuse.b, 255 };
|
||||
|
||||
t.p1.color = color;
|
||||
t.p2.color = color;
|
||||
t.p3.color = color;
|
||||
|
||||
t.tex1Name = ReadLineString(stream, "tex1");
|
||||
t.tex2Name = ReadLineString(stream, "tex2");
|
||||
std::string varTex2Ch = ReadLineString(stream, "var_tex2");
|
||||
t.variableTex2 = varTex2Ch == "Y";
|
||||
|
||||
if (header.version == 1)
|
||||
t.lodLevel = static_cast<ModelLODLevel>(boost::lexical_cast<int>(ReadLineString(stream, "lod_level")));
|
||||
|
||||
t.state = boost::lexical_cast<int>(ReadLineString(stream, "state"));
|
||||
|
||||
if (t.lodLevel == ModelLODLevel::Low ||
|
||||
t.lodLevel == ModelLODLevel::Medium)
|
||||
continue;
|
||||
|
||||
ModelTriangle triangle;
|
||||
triangle.p1 = t.p1;
|
||||
triangle.p2 = t.p2;
|
||||
triangle.p3 = t.p3;
|
||||
triangle.material.albedoTexture = t.tex1Name;
|
||||
triangle.material.detailTexture = t.tex2Name;
|
||||
triangle.material.variableDetail = t.variableTex2;
|
||||
ConvertFromOldRenderState(triangle, t.state);
|
||||
|
||||
mesh.AddTriangle(triangle);
|
||||
}
|
||||
|
||||
model.AddMesh("main", std::move(mesh));
|
||||
}
|
||||
|
||||
void ReadTextModelV3(CModel& model, std::istream& stream)
|
||||
{
|
||||
ModelHeaderV3 header;
|
||||
|
||||
try
|
||||
{
|
||||
header = ReadTextHeader(stream);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
throw CModelIOException(std::string("Error reading model header: ") + e.what());
|
||||
}
|
||||
|
||||
for (int i = 0; i < header.totalCrashSpheres; ++i)
|
||||
{
|
||||
auto crashSphere = ParseCrashSphere(ReadLineString(stream, "crash_sphere"));
|
||||
model.AddCrashSphere(crashSphere);
|
||||
}
|
||||
|
||||
if (header.hasShadowSpot)
|
||||
{
|
||||
auto shadowSpot = ParseShadowSpot(ReadLineString(stream, "shadow_spot"));
|
||||
model.SetShadowSpot(shadowSpot);
|
||||
}
|
||||
|
||||
if (header.hasCameraCollisionSphere)
|
||||
{
|
||||
auto sphere = ParseCameraCollisionSphere(ReadLineString(stream, "camera_collision_sphere"));
|
||||
model.SetCameraCollisionSphere(sphere);
|
||||
}
|
||||
|
||||
for (int i = 0; i < header.totalMeshes; ++i)
|
||||
{
|
||||
std::string meshName = ReadLineString(stream, "mesh");
|
||||
CModelMesh mesh = ReadTextMesh(stream);
|
||||
model.AddMesh(meshName, std::move(mesh));
|
||||
}
|
||||
}
|
||||
|
||||
ModelHeaderV3 ReadTextHeader(std::istream& stream)
|
||||
{
|
||||
ModelHeaderV3 header;
|
||||
header.version = boost::lexical_cast<int>(ReadLineString(stream, "version"));
|
||||
header.totalCrashSpheres = boost::lexical_cast<int>(ReadLineString(stream, "total_crash_spheres"));
|
||||
header.hasShadowSpot = ReadLineString(stream, "has_shadow_spot") == std::string("Y");
|
||||
header.hasCameraCollisionSphere = ReadLineString(stream, "has_camera_collision_sphere") == std::string("Y");
|
||||
header.totalMeshes = boost::lexical_cast<int>(ReadLineString(stream, "total_meshes"));
|
||||
return header;
|
||||
}
|
||||
|
||||
CModelMesh ReadTextMesh(std::istream& stream)
|
||||
{
|
||||
CModelMesh mesh;
|
||||
|
||||
mesh.SetPosition(ParseVector(ReadLineString(stream, "position")));
|
||||
mesh.SetRotation(ParseVector(ReadLineString(stream, "rotation")));
|
||||
mesh.SetScale(ParseVector(ReadLineString(stream, "scale")));
|
||||
mesh.SetParent(ReadLineString(stream, "parent"));
|
||||
|
||||
int totalTriangles = boost::lexical_cast<int>(ReadLineString(stream, "total_triangles"));
|
||||
|
||||
for (int i = 0; i < totalTriangles; ++i)
|
||||
{
|
||||
ModelTriangleV3 t;
|
||||
|
||||
std::string p1Text = ReadLineString(stream, "p1");
|
||||
t.p1 = ParseVertexTex2(p1Text);
|
||||
std::string p2Text = ReadLineString(stream, "p2");
|
||||
t.p2 = ParseVertexTex2(p2Text);
|
||||
std::string p3Text = ReadLineString(stream, "p3");
|
||||
t.p3 = ParseVertexTex2(p3Text);
|
||||
|
||||
std::string matText = ReadLineString(stream, "mat");
|
||||
LegacyMaterial mat = ParseMaterial(matText);
|
||||
|
||||
auto diffuse = Gfx::ColorToIntColor(mat.diffuse);
|
||||
glm::u8vec4 color = { diffuse.r, diffuse.g, diffuse.b, 255 };
|
||||
|
||||
t.p1.color = color;
|
||||
t.p2.color = color;
|
||||
t.p3.color = color;
|
||||
|
||||
t.material.albedoTexture = ReadLineString(stream, "tex1");
|
||||
t.material.detailTexture = ReadLineString(stream, "tex2");
|
||||
t.material.variableDetail = ReadLineString(stream, "var_tex2") == std::string("Y");
|
||||
|
||||
t.material.alphaMode = ParseTransparentMode(ReadLineString(stream, "trans_mode"));
|
||||
t.material.tag = ParseSpecialMark(ReadLineString(stream, "mark"));
|
||||
bool doubleSided = ReadLineString(stream, "dbl_side") == std::string("Y");
|
||||
t.material.cullFace = doubleSided ? CullFace::NONE : CullFace::BACK;
|
||||
|
||||
if (t.material.alphaMode != AlphaMode::NONE)
|
||||
t.material.alphaThreshold = 0.5f;
|
||||
|
||||
mesh.AddTriangle(t);
|
||||
}
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
std::string ReadLineString(std::istream& stream, const std::string& expectedPrefix)
|
||||
{
|
||||
std::string line;
|
||||
while (true)
|
||||
{
|
||||
if (stream.eof())
|
||||
throw CModelIOException("Unexpected EOF");
|
||||
|
||||
std::getline(stream, line);
|
||||
boost::trim_right(line);
|
||||
if (!line.empty() && line[0] != '#')
|
||||
break;
|
||||
}
|
||||
|
||||
std::stringstream s;
|
||||
s.str(line);
|
||||
|
||||
std::string prefix;
|
||||
s >> prefix;
|
||||
if (prefix != expectedPrefix)
|
||||
throw CModelIOException(std::string("Unexpected prefix: '") + prefix + "'");
|
||||
|
||||
std::string value;
|
||||
std::getline(s, value);
|
||||
boost::trim_left(value);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
void ReadValuePrefix(std::istream& stream, const std::string& expectedPrefix)
|
||||
{
|
||||
std::string prefix;
|
||||
stream >> prefix;
|
||||
if (prefix != expectedPrefix)
|
||||
throw CModelIOException(std::string("Unexpected prefix: '") + prefix + "', expected was: '" + expectedPrefix + "'");
|
||||
}
|
||||
|
||||
Vertex3D ParseVertexTex2(const std::string& text)
|
||||
{
|
||||
Vertex3D vertex;
|
||||
|
||||
std::stringstream stream;
|
||||
stream.str(text);
|
||||
|
||||
ReadValuePrefix(stream, "c");
|
||||
stream >> vertex.position.x >> vertex.position.y >> vertex.position.z;
|
||||
|
||||
ReadValuePrefix(stream, "n");
|
||||
stream >> vertex.normal.x >> vertex.normal.y >> vertex.normal.z;
|
||||
|
||||
ReadValuePrefix(stream, "t1");
|
||||
stream >> vertex.uv.x >> vertex.uv.y;
|
||||
|
||||
ReadValuePrefix(stream, "t2");
|
||||
stream >> vertex.uv2.x >> vertex.uv2.y;
|
||||
|
||||
return vertex;
|
||||
}
|
||||
|
||||
LegacyMaterial ParseMaterial(const std::string& text)
|
||||
{
|
||||
LegacyMaterial material;
|
||||
|
||||
std::stringstream stream;
|
||||
stream.str(text);
|
||||
|
||||
ReadValuePrefix(stream, "dif");
|
||||
stream >> material.diffuse.r
|
||||
>> material.diffuse.g
|
||||
>> material.diffuse.b
|
||||
>> material.diffuse.a;
|
||||
|
||||
ReadValuePrefix(stream, "amb");
|
||||
stream >> material.ambient.r
|
||||
>> material.ambient.g
|
||||
>> material.ambient.b
|
||||
>> material.ambient.a;
|
||||
|
||||
ReadValuePrefix(stream, "spc");
|
||||
stream >> material.specular.r
|
||||
>> material.specular.g
|
||||
>> material.specular.b
|
||||
>> material.specular.a;
|
||||
|
||||
return material;
|
||||
}
|
||||
|
||||
glm::vec3 ParseVector(const std::string& text)
|
||||
{
|
||||
glm::vec3 vector = { 0, 0, 0 };
|
||||
|
||||
std::stringstream stream;
|
||||
stream.str(text);
|
||||
|
||||
stream >> vector.x >> vector.y >> vector.z;
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
ModelCrashSphere ParseCrashSphere(const std::string& text)
|
||||
{
|
||||
ModelCrashSphere crashSphere;
|
||||
|
||||
std::stringstream stream;
|
||||
stream.str(text);
|
||||
|
||||
ReadValuePrefix(stream, "pos");
|
||||
stream >> crashSphere.position.x
|
||||
>> crashSphere.position.y
|
||||
>> crashSphere.position.z;
|
||||
|
||||
ReadValuePrefix(stream, "rad");
|
||||
stream >> crashSphere.radius;
|
||||
|
||||
ReadValuePrefix(stream, "sound");
|
||||
stream >> crashSphere.sound;
|
||||
|
||||
ReadValuePrefix(stream, "hard");
|
||||
stream >> crashSphere.hardness;
|
||||
|
||||
return crashSphere;
|
||||
}
|
||||
|
||||
ModelShadowSpot ParseShadowSpot(const std::string& text)
|
||||
{
|
||||
ModelShadowSpot shadowSpot;
|
||||
|
||||
std::stringstream stream;
|
||||
stream.str(text);
|
||||
|
||||
ReadValuePrefix(stream, "rad");
|
||||
stream >> shadowSpot.radius;
|
||||
|
||||
ReadValuePrefix(stream, "int");
|
||||
stream >> shadowSpot.intensity;
|
||||
|
||||
return shadowSpot;
|
||||
}
|
||||
|
||||
Math::Sphere ParseCameraCollisionSphere(const std::string& text)
|
||||
{
|
||||
Math::Sphere sphere;
|
||||
|
||||
std::stringstream stream;
|
||||
stream.str(text);
|
||||
|
||||
ReadValuePrefix(stream, "pos");
|
||||
stream >> sphere.pos.x
|
||||
>> sphere.pos.y
|
||||
>> sphere.pos.z;
|
||||
|
||||
ReadValuePrefix(stream, "rad");
|
||||
stream >> sphere.radius;
|
||||
|
||||
return sphere;
|
||||
}
|
||||
|
||||
AlphaMode ParseTransparentMode(const std::string& text)
|
||||
{
|
||||
if (text == "none")
|
||||
return AlphaMode::NONE;
|
||||
else if (text == "alpha")
|
||||
return AlphaMode::MASK;
|
||||
else
|
||||
return AlphaMode::NONE;
|
||||
}
|
||||
|
||||
std::string ParseSpecialMark(const std::string& text)
|
||||
{
|
||||
if (text == "none")
|
||||
return "";
|
||||
else if (text == "part1")
|
||||
return "tracker_right";
|
||||
else if (text == "part2")
|
||||
return "tracker_left";
|
||||
else if (text == "part3")
|
||||
return "energy";
|
||||
else
|
||||
throw CModelIOException(std::string("Unexpected special mark: '") + text + "'");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* This file is part of the Colobot: Gold Edition source code
|
||||
* Copyright (C) 2001-2022, Daniel Roux, EPSITEC SA & TerranovaTeam
|
||||
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
|
||||
*
|
||||
* 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://gnu.org/licenses
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "graphics/model/model.h"
|
||||
#include "graphics/model/model_format.h"
|
||||
|
||||
#include <istream>
|
||||
|
||||
/**
|
||||
* \namespace ModelInput
|
||||
* \brief Namespace with functions to read model files
|
||||
*/
|
||||
namespace Gfx::ModelIO
|
||||
{
|
||||
|
||||
void ReadTextModel(CModel& model, std::istream& stream);
|
||||
|
||||
}
|
Loading…
Reference in New Issue