Refactor model-related code
* refactored model loading code based on code from dev-models * support new model format V2 (without LOD levels) * removed LOD levels support in CEngine and from model files * preparations for new model format V3: - support for multiple meshes in one model file - support for saving crash spheres and shadow spots - removed all direct dependencies on CEngine enum values - quantized model rendering states to new flags and enumsmaster
parent
9b232ee3f5
commit
93e950584a
2
data
2
data
|
@ -1 +1 @@
|
|||
Subproject commit 73bb8f9ac0f8af3e810455af2ab2dd5113af03eb
|
||||
Subproject commit c1da1d3ca64d8b6450023d9a6f095b5e8a80da63
|
|
@ -104,8 +104,7 @@ set(BASE_SOURCES
|
|||
graphics/engine/engine.cpp
|
||||
graphics/engine/lightman.cpp
|
||||
graphics/engine/lightning.cpp
|
||||
graphics/engine/modelfile.cpp
|
||||
graphics/engine/modelmanager.cpp
|
||||
graphics/engine/oldmodelmanager.cpp
|
||||
graphics/engine/particle.cpp
|
||||
graphics/engine/planet.cpp
|
||||
graphics/engine/pyro.cpp
|
||||
|
@ -118,6 +117,11 @@ set(BASE_SOURCES
|
|||
graphics/opengl/gldevice.cpp
|
||||
graphics/opengl/glframebuffer.cpp
|
||||
graphics/opengl/glutil.cpp
|
||||
graphics/model/model.cpp
|
||||
graphics/model/model_input.cpp
|
||||
graphics/model/model_manager.cpp
|
||||
graphics/model/model_mesh.cpp
|
||||
graphics/model/model_output.cpp
|
||||
object/auto/auto.cpp
|
||||
object/auto/autobase.cpp
|
||||
object/auto/autoconvert.cpp
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
#include "common/stringutils.h"
|
||||
#include "common/resources/resourcemanager.h"
|
||||
|
||||
#include "graphics/engine/modelmanager.h"
|
||||
#include "graphics/core/nulldevice.h"
|
||||
#include "graphics/opengl/glutil.h"
|
||||
|
||||
|
|
|
@ -70,7 +70,7 @@ T ReadBinary(std::istream &istr)
|
|||
/**
|
||||
* false is 0; true is 1.
|
||||
*/
|
||||
void WriteBinaryBool(float value, std::ostream &ostr)
|
||||
inline void WriteBinaryBool(float value, std::ostream &ostr)
|
||||
{
|
||||
unsigned char v = value ? 1 : 0;
|
||||
IOUtils::WriteBinary<1, unsigned char>(v, ostr);
|
||||
|
@ -80,7 +80,7 @@ void WriteBinaryBool(float value, std::ostream &ostr)
|
|||
/**
|
||||
* 0 is false; other values are true.
|
||||
*/
|
||||
bool ReadBinaryBool(std::istream &istr)
|
||||
inline bool ReadBinaryBool(std::istream &istr)
|
||||
{
|
||||
int v = IOUtils::ReadBinary<1, unsigned char>(istr);
|
||||
return v != 0;
|
||||
|
@ -91,7 +91,7 @@ bool ReadBinaryBool(std::istream &istr)
|
|||
* 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)
|
||||
inline void WriteBinaryFloat(float value, std::ostream &ostr)
|
||||
{
|
||||
union { float fValue; unsigned int iValue; } u;
|
||||
memset(&u, 0, sizeof(u));
|
||||
|
@ -104,7 +104,7 @@ void WriteBinaryFloat(float value, std::ostream &ostr)
|
|||
* Read order is little-endian
|
||||
* NOTE: code is probably not portable as there are platforms with other float representations.
|
||||
*/
|
||||
float ReadBinaryFloat(std::istream &istr)
|
||||
inline float ReadBinaryFloat(std::istream &istr)
|
||||
{
|
||||
union { float fValue; unsigned int iValue; } u;
|
||||
memset(&u, 0, sizeof(u));
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
#include "graphics/engine/cloud.h"
|
||||
#include "graphics/engine/lightman.h"
|
||||
#include "graphics/engine/lightning.h"
|
||||
#include "graphics/engine/modelmanager.h"
|
||||
#include "graphics/engine/oldmodelmanager.h"
|
||||
#include "graphics/engine/particle.h"
|
||||
#include "graphics/engine/planet.h"
|
||||
#include "graphics/engine/pyro_manager.h"
|
||||
|
@ -240,7 +240,7 @@ CDevice* CEngine::GetDevice()
|
|||
return m_device;
|
||||
}
|
||||
|
||||
CModelManager* CEngine::GetModelManager()
|
||||
COldModelManager* CEngine::GetModelManager()
|
||||
{
|
||||
return m_modelManager.get();
|
||||
}
|
||||
|
@ -299,7 +299,7 @@ bool CEngine::Create()
|
|||
{
|
||||
m_size = m_app->GetVideoConfig().size;
|
||||
|
||||
m_modelManager.reset(new CModelManager(this));
|
||||
m_modelManager.reset(new COldModelManager(this));
|
||||
m_pyroManager.reset(new CPyroManager());
|
||||
m_lightMan = new CLightManager(this);
|
||||
m_text = new CText(this);
|
||||
|
@ -595,19 +595,7 @@ EngineBaseObjTexTier& CEngine::AddLevel2(EngineBaseObject& p1, const std::string
|
|||
return p1.next.back();
|
||||
}
|
||||
|
||||
EngineBaseObjLODTier& CEngine::AddLevel3(EngineBaseObjTexTier& p2, LODLevel lodLevel)
|
||||
{
|
||||
for (int i = 0; i < static_cast<int>( p2.next.size() ); i++)
|
||||
{
|
||||
if (p2.next[i].lodLevel == lodLevel)
|
||||
return p2.next[i];
|
||||
}
|
||||
|
||||
p2.next.push_back(EngineBaseObjLODTier(lodLevel));
|
||||
return p2.next.back();
|
||||
}
|
||||
|
||||
EngineBaseObjDataTier& CEngine::AddLevel4(EngineBaseObjLODTier& p3, EngineTriangleType type,
|
||||
EngineBaseObjDataTier& CEngine::AddLevel3(EngineBaseObjTexTier& p3, EngineTriangleType type,
|
||||
const Material& material, int state)
|
||||
{
|
||||
for (int i = 0; i < static_cast<int>( p3.next.size() ); i++)
|
||||
|
@ -658,15 +646,9 @@ void CEngine::DeleteBaseObject(int baseObjRank)
|
|||
|
||||
for (int l3 = 0; l3 < static_cast<int>( p2.next.size() ); l3++)
|
||||
{
|
||||
EngineBaseObjLODTier& p3 = p2.next[l3];
|
||||
|
||||
for (int l4 = 0; l4 < static_cast<int>( p3.next.size() ); l4++)
|
||||
{
|
||||
EngineBaseObjDataTier& p4 = p3.next[l4];
|
||||
|
||||
m_device->DestroyStaticBuffer(p4.staticBufferId);
|
||||
p4.staticBufferId = 0;
|
||||
}
|
||||
EngineBaseObjDataTier& p3 = p2.next[l3];
|
||||
m_device->DestroyStaticBuffer(p3.staticBufferId);
|
||||
p3.staticBufferId = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -689,15 +671,9 @@ void CEngine::DeleteAllBaseObjects()
|
|||
|
||||
for (int l3 = 0; l3 < static_cast<int>( p2.next.size() ); l3++)
|
||||
{
|
||||
EngineBaseObjLODTier& p3 = p2.next[l3];
|
||||
|
||||
for (int l4 = 0; l4 < static_cast<int>( p3.next.size() ); l4++)
|
||||
{
|
||||
EngineBaseObjDataTier& p4 = p3.next[l4];
|
||||
|
||||
m_device->DestroyStaticBuffer(p4.staticBufferId);
|
||||
p4.staticBufferId = 0;
|
||||
}
|
||||
EngineBaseObjDataTier& p3 = p2.next[l3];
|
||||
m_device->DestroyStaticBuffer(p3.staticBufferId);
|
||||
p3.staticBufferId = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -723,13 +699,8 @@ void CEngine::CopyBaseObject(int sourceBaseObjRank, int destBaseObjRank)
|
|||
|
||||
for (int l3 = 0; l3 < static_cast<int>( p2.next.size() ); l3++)
|
||||
{
|
||||
EngineBaseObjLODTier& p3 = p2.next[l3];
|
||||
|
||||
for (int l4 = 0; l4 < static_cast<int>( p3.next.size() ); l4++)
|
||||
{
|
||||
EngineBaseObjDataTier& p4 = p3.next[l4];
|
||||
p4.staticBufferId = 0;
|
||||
}
|
||||
EngineBaseObjDataTier& p3 = p2.next[l3];
|
||||
p3.staticBufferId = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -738,18 +709,17 @@ void CEngine::AddBaseObjTriangles(int baseObjRank, const std::vector<VertexTex2>
|
|||
EngineTriangleType triangleType,
|
||||
const Material& material, int state,
|
||||
std::string tex1Name, std::string tex2Name,
|
||||
LODLevel lodLevel, bool globalUpdate)
|
||||
bool globalUpdate)
|
||||
{
|
||||
assert(baseObjRank >= 0 && baseObjRank < static_cast<int>( m_baseObjects.size() ));
|
||||
|
||||
EngineBaseObject& p1 = m_baseObjects[baseObjRank];
|
||||
EngineBaseObjTexTier& p2 = AddLevel2(p1, tex1Name, tex2Name);
|
||||
EngineBaseObjLODTier& p3 = AddLevel3(p2, lodLevel);
|
||||
EngineBaseObjDataTier& p4 = AddLevel4(p3, triangleType, material, state);
|
||||
EngineBaseObjDataTier& p3 = AddLevel3(p2, triangleType, material, state);
|
||||
|
||||
p4.vertices.insert(p4.vertices.end(), vertices.begin(), vertices.end());
|
||||
p3.vertices.insert(p3.vertices.end(), vertices.begin(), vertices.end());
|
||||
|
||||
p4.updateStaticBuffer = true;
|
||||
p3.updateStaticBuffer = true;
|
||||
m_updateStaticBuffers = true;
|
||||
|
||||
if (globalUpdate)
|
||||
|
@ -779,19 +749,18 @@ void CEngine::AddBaseObjTriangles(int baseObjRank, const std::vector<VertexTex2>
|
|||
|
||||
void CEngine::AddBaseObjQuick(int baseObjRank, const EngineBaseObjDataTier& buffer,
|
||||
std::string tex1Name, std::string tex2Name,
|
||||
LODLevel lodLevel, bool globalUpdate)
|
||||
bool globalUpdate)
|
||||
{
|
||||
assert(baseObjRank >= 0 && baseObjRank < static_cast<int>( m_baseObjects.size() ));
|
||||
|
||||
EngineBaseObject& p1 = m_baseObjects[baseObjRank];
|
||||
EngineBaseObjTexTier& p2 = AddLevel2(p1, tex1Name, tex2Name);
|
||||
EngineBaseObjLODTier& p3 = AddLevel3(p2, lodLevel);
|
||||
|
||||
p3.next.push_back(buffer);
|
||||
p2.next.push_back(buffer);
|
||||
|
||||
EngineBaseObjDataTier& p4 = p3.next.back();
|
||||
EngineBaseObjDataTier& p3 = p2.next.back();
|
||||
|
||||
UpdateStaticBuffer(p4);
|
||||
UpdateStaticBuffer(p3);
|
||||
|
||||
if (globalUpdate)
|
||||
{
|
||||
|
@ -799,23 +768,23 @@ void CEngine::AddBaseObjQuick(int baseObjRank, const EngineBaseObjDataTier& buff
|
|||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < static_cast<int>( p4.vertices.size() ); i++)
|
||||
for (int i = 0; i < static_cast<int>( p3.vertices.size() ); i++)
|
||||
{
|
||||
p1.bboxMin.x = Math::Min(p4.vertices[i].coord.x, p1.bboxMin.x);
|
||||
p1.bboxMin.y = Math::Min(p4.vertices[i].coord.y, p1.bboxMin.y);
|
||||
p1.bboxMin.z = Math::Min(p4.vertices[i].coord.z, p1.bboxMin.z);
|
||||
p1.bboxMax.x = Math::Max(p4.vertices[i].coord.x, p1.bboxMax.x);
|
||||
p1.bboxMax.y = Math::Max(p4.vertices[i].coord.y, p1.bboxMax.y);
|
||||
p1.bboxMax.z = Math::Max(p4.vertices[i].coord.z, p1.bboxMax.z);
|
||||
p1.bboxMin.x = Math::Min(p3.vertices[i].coord.x, p1.bboxMin.x);
|
||||
p1.bboxMin.y = Math::Min(p3.vertices[i].coord.y, p1.bboxMin.y);
|
||||
p1.bboxMin.z = Math::Min(p3.vertices[i].coord.z, p1.bboxMin.z);
|
||||
p1.bboxMax.x = Math::Max(p3.vertices[i].coord.x, p1.bboxMax.x);
|
||||
p1.bboxMax.y = Math::Max(p3.vertices[i].coord.y, p1.bboxMax.y);
|
||||
p1.bboxMax.z = Math::Max(p3.vertices[i].coord.z, p1.bboxMax.z);
|
||||
}
|
||||
|
||||
p1.radius = Math::Max(p1.bboxMin.Length(), p1.bboxMax.Length());
|
||||
}
|
||||
|
||||
if (p4.type == ENG_TRIANGLE_TYPE_TRIANGLES)
|
||||
p1.totalTriangles += p4.vertices.size() / 3;
|
||||
else if (p4.type == ENG_TRIANGLE_TYPE_SURFACE)
|
||||
p1.totalTriangles += p4.vertices.size() - 2;
|
||||
if (p3.type == ENG_TRIANGLE_TYPE_TRIANGLES)
|
||||
p1.totalTriangles += p3.vertices.size() / 3;
|
||||
else if (p3.type == ENG_TRIANGLE_TYPE_SURFACE)
|
||||
p1.totalTriangles += p3.vertices.size() - 2;
|
||||
}
|
||||
|
||||
void CEngine::DebugObject(int objRank)
|
||||
|
@ -876,21 +845,13 @@ void CEngine::DebugObject(int objRank)
|
|||
|
||||
for (int l3 = 0; l3 < static_cast<int>( p2.next.size() ); l3++)
|
||||
{
|
||||
EngineBaseObjLODTier& p3 = p2.next[l3];
|
||||
EngineBaseObjDataTier& p3 = p2.next[l3];
|
||||
|
||||
l->Debug(" l3:\n");
|
||||
l->Debug(" lodLevel: %d\n", p3.lodLevel);
|
||||
|
||||
for (int l4 = 0; l4 < static_cast<int>( p3.next.size() ); l4++)
|
||||
{
|
||||
EngineBaseObjDataTier& p4 = p3.next[l4];
|
||||
|
||||
l->Debug(" l4:\n");
|
||||
l->Debug(" type: %d\n", p4.type);
|
||||
l->Debug(" state: %d\n", p4.state);
|
||||
l->Debug(" staticBufferId: %u\n", p4.staticBufferId);
|
||||
l->Debug(" updateStaticBuffer: %s\n", p4.updateStaticBuffer ? "true" : "false");
|
||||
}
|
||||
l->Debug(" l3:\n");
|
||||
l->Debug(" type: %d\n", p3.type);
|
||||
l->Debug(" state: %d\n", p3.state);
|
||||
l->Debug(" staticBufferId: %u\n", p3.staticBufferId);
|
||||
l->Debug(" updateStaticBuffer: %s\n", p3.updateStaticBuffer ? "true" : "false");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1038,7 +999,7 @@ int CEngine::GetObjectTotalTriangles(int objRank)
|
|||
|
||||
EngineBaseObjDataTier* CEngine::FindTriangles(int objRank, const Material& material,
|
||||
int state, std::string tex1Name,
|
||||
std::string tex2Name, int lodLevelMask)
|
||||
std::string tex2Name)
|
||||
{
|
||||
assert(objRank >= 0 && objRank < static_cast<int>( m_objects.size() ));
|
||||
|
||||
|
@ -1059,28 +1020,20 @@ EngineBaseObjDataTier* CEngine::FindTriangles(int objRank, const Material& mater
|
|||
|
||||
for (int l3 = 0; l3 < static_cast<int>( p2.next.size() ); l3++)
|
||||
{
|
||||
EngineBaseObjLODTier& p3 = p2.next[l3];
|
||||
EngineBaseObjDataTier& p3 = p2.next[l3];
|
||||
|
||||
if ((p3.lodLevel & lodLevelMask) == 0)
|
||||
if ( (p3.state & (~(ENG_RSTATE_DUAL_BLACK|ENG_RSTATE_DUAL_WHITE))) != state ||
|
||||
p3.material != material )
|
||||
continue;
|
||||
|
||||
for (int l4 = 0; l4 < static_cast<int>( p3.next.size() ); l4++)
|
||||
{
|
||||
EngineBaseObjDataTier& p4 = p3.next[l4];
|
||||
|
||||
if ( (p4.state & (~(ENG_RSTATE_DUAL_BLACK|ENG_RSTATE_DUAL_WHITE))) != state ||
|
||||
p4.material != material )
|
||||
continue;
|
||||
|
||||
return &p4;
|
||||
}
|
||||
return &p3;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int CEngine::GetPartialTriangles(int objRank, int lodLevelMask, float percent, int maxCount,
|
||||
int CEngine::GetPartialTriangles(int objRank, float percent, int maxCount,
|
||||
std::vector<EngineTriangle>& triangles)
|
||||
{
|
||||
assert(objRank >= 0 && objRank < static_cast<int>( m_objects.size() ));
|
||||
|
@ -1105,62 +1058,54 @@ int CEngine::GetPartialTriangles(int objRank, int lodLevelMask, float percent, i
|
|||
|
||||
for (int l3 = 0; l3 < static_cast<int>( p2.next.size() ); l3++)
|
||||
{
|
||||
EngineBaseObjLODTier& p3 = p2.next[l3];
|
||||
EngineBaseObjDataTier& p3 = p2.next[l3];
|
||||
|
||||
if ((p3.lodLevel & lodLevelMask) == 0)
|
||||
continue;
|
||||
|
||||
for (int l4 = 0; l4 < static_cast<int>( p3.next.size() ); l4++)
|
||||
if (p3.type == ENG_TRIANGLE_TYPE_TRIANGLES)
|
||||
{
|
||||
EngineBaseObjDataTier& p4 = p3.next[l4];
|
||||
|
||||
if (p4.type == ENG_TRIANGLE_TYPE_TRIANGLES)
|
||||
for (int i = 0; i < static_cast<int>( p3.vertices.size() ); i += 3)
|
||||
{
|
||||
for (int i = 0; i < static_cast<int>( p4.vertices.size() ); i += 3)
|
||||
{
|
||||
if (static_cast<float>(actualCount) / total >= percent)
|
||||
break;
|
||||
if (static_cast<float>(actualCount) / total >= percent)
|
||||
break;
|
||||
|
||||
if (actualCount >= maxCount)
|
||||
break;
|
||||
if (actualCount >= maxCount)
|
||||
break;
|
||||
|
||||
EngineTriangle t;
|
||||
t.triangle[0] = p4.vertices[i];
|
||||
t.triangle[1] = p4.vertices[i+1];
|
||||
t.triangle[2] = p4.vertices[i+2];
|
||||
t.material = p4.material;
|
||||
t.state = p4.state;
|
||||
t.tex1Name = p2.tex1Name;
|
||||
t.tex2Name = p2.tex2Name;
|
||||
EngineTriangle t;
|
||||
t.triangle[0] = p3.vertices[i];
|
||||
t.triangle[1] = p3.vertices[i+1];
|
||||
t.triangle[2] = p3.vertices[i+2];
|
||||
t.material = p3.material;
|
||||
t.state = p3.state;
|
||||
t.tex1Name = p2.tex1Name;
|
||||
t.tex2Name = p2.tex2Name;
|
||||
|
||||
triangles.push_back(t);
|
||||
triangles.push_back(t);
|
||||
|
||||
++actualCount;
|
||||
}
|
||||
++actualCount;
|
||||
}
|
||||
else if (p4.type == ENG_TRIANGLE_TYPE_SURFACE)
|
||||
}
|
||||
else if (p3.type == ENG_TRIANGLE_TYPE_SURFACE)
|
||||
{
|
||||
for (int i = 0; i < static_cast<int>( p3.vertices.size() ); i += 1)
|
||||
{
|
||||
for (int i = 0; i < static_cast<int>( p4.vertices.size() ); i += 1)
|
||||
{
|
||||
if (static_cast<float>(actualCount) / total >= percent)
|
||||
break;
|
||||
if (static_cast<float>(actualCount) / total >= percent)
|
||||
break;
|
||||
|
||||
if (actualCount >= maxCount)
|
||||
break;
|
||||
if (actualCount >= maxCount)
|
||||
break;
|
||||
|
||||
EngineTriangle t;
|
||||
t.triangle[0] = p4.vertices[i];
|
||||
t.triangle[1] = p4.vertices[i+1];
|
||||
t.triangle[2] = p4.vertices[i+2];
|
||||
t.material = p4.material;
|
||||
t.state = p4.state;
|
||||
t.tex1Name = p2.tex1Name;
|
||||
t.tex2Name = p2.tex2Name;
|
||||
EngineTriangle t;
|
||||
t.triangle[0] = p3.vertices[i];
|
||||
t.triangle[1] = p3.vertices[i+1];
|
||||
t.triangle[2] = p3.vertices[i+2];
|
||||
t.material = p3.material;
|
||||
t.state = p3.state;
|
||||
t.tex1Name = p2.tex1Name;
|
||||
t.tex2Name = p2.tex2Name;
|
||||
|
||||
triangles.push_back(t);
|
||||
triangles.push_back(t);
|
||||
|
||||
++actualCount;
|
||||
}
|
||||
++actualCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1201,12 +1146,12 @@ void CEngine::ChangeSecondTexture(int objRank, const std::string& tex2Name)
|
|||
|
||||
void CEngine::ChangeTextureMapping(int objRank, const Material& mat, int state,
|
||||
const std::string& tex1Name, const std::string& tex2Name,
|
||||
int lodLevelMask, EngineTextureMapping mode,
|
||||
EngineTextureMapping mode,
|
||||
float au, float bu, float av, float bv)
|
||||
{
|
||||
assert(objRank >= 0 && objRank < static_cast<int>( m_objects.size() ));
|
||||
|
||||
EngineBaseObjDataTier* p4 = FindTriangles(objRank, mat, state, tex1Name, tex2Name, lodLevelMask);
|
||||
EngineBaseObjDataTier* p4 = FindTriangles(objRank, mat, state, tex1Name, tex2Name);
|
||||
if (p4 == nullptr)
|
||||
return;
|
||||
|
||||
|
@ -1263,12 +1208,12 @@ void CEngine::ChangeTextureMapping(int objRank, const Material& mat, int state,
|
|||
|
||||
void CEngine::TrackTextureMapping(int objRank, const Material& mat, int state,
|
||||
const std::string& tex1Name, const std::string& tex2Name,
|
||||
int lodLevelMask, EngineTextureMapping mode,
|
||||
EngineTextureMapping mode,
|
||||
float pos, float factor, float tl, float ts, float tt)
|
||||
{
|
||||
assert(objRank >= 0 && objRank < static_cast<int>( m_objects.size() ));
|
||||
|
||||
EngineBaseObjDataTier* p4 = FindTriangles(objRank, mat, state, tex1Name, tex2Name, lodLevelMask);
|
||||
EngineBaseObjDataTier* p4 = FindTriangles(objRank, mat, state, tex1Name, tex2Name);
|
||||
if (p4 == nullptr)
|
||||
return;
|
||||
|
||||
|
@ -1730,24 +1675,19 @@ void CEngine::UpdateGeometry()
|
|||
|
||||
for (int l3 = 0; l3 < static_cast<int>( p2.next.size() ); l3++)
|
||||
{
|
||||
EngineBaseObjLODTier& p3 = p2.next[l3];
|
||||
EngineBaseObjDataTier& p3 = p2.next[l3];
|
||||
|
||||
for (int l4 = 0; l4 < static_cast<int>( p3.next.size() ); l4++)
|
||||
for (int i = 0; i < static_cast<int>( p3.vertices.size() ); i++)
|
||||
{
|
||||
EngineBaseObjDataTier& p4 = p3.next[l4];
|
||||
|
||||
for (int i = 0; i < static_cast<int>( p4.vertices.size() ); i++)
|
||||
{
|
||||
p1.bboxMin.x = Math::Min(p4.vertices[i].coord.x, p1.bboxMin.x);
|
||||
p1.bboxMin.y = Math::Min(p4.vertices[i].coord.y, p1.bboxMin.y);
|
||||
p1.bboxMin.z = Math::Min(p4.vertices[i].coord.z, p1.bboxMin.z);
|
||||
p1.bboxMax.x = Math::Max(p4.vertices[i].coord.x, p1.bboxMax.x);
|
||||
p1.bboxMax.y = Math::Max(p4.vertices[i].coord.y, p1.bboxMax.y);
|
||||
p1.bboxMax.z = Math::Max(p4.vertices[i].coord.z, p1.bboxMax.z);
|
||||
}
|
||||
|
||||
p1.radius = Math::Max(p1.bboxMin.Length(), p1.bboxMax.Length());
|
||||
p1.bboxMin.x = Math::Min(p3.vertices[i].coord.x, p1.bboxMin.x);
|
||||
p1.bboxMin.y = Math::Min(p3.vertices[i].coord.y, p1.bboxMin.y);
|
||||
p1.bboxMin.z = Math::Min(p3.vertices[i].coord.z, p1.bboxMin.z);
|
||||
p1.bboxMax.x = Math::Max(p3.vertices[i].coord.x, p1.bboxMax.x);
|
||||
p1.bboxMax.y = Math::Max(p3.vertices[i].coord.y, p1.bboxMax.y);
|
||||
p1.bboxMax.z = Math::Max(p3.vertices[i].coord.z, p1.bboxMax.z);
|
||||
}
|
||||
|
||||
p1.radius = Math::Max(p1.bboxMin.Length(), p1.bboxMax.Length());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1790,17 +1730,12 @@ void CEngine::UpdateStaticBuffers()
|
|||
|
||||
for (int l3 = 0; l3 < static_cast<int>( p2.next.size() ); l3++)
|
||||
{
|
||||
EngineBaseObjLODTier& p3 = p2.next[l3];
|
||||
EngineBaseObjDataTier& p3 = p2.next[l3];
|
||||
|
||||
for (int l4 = 0; l4 < static_cast<int>( p3.next.size() ); l4++)
|
||||
{
|
||||
EngineBaseObjDataTier& p4 = p3.next[l4];
|
||||
|
||||
if (! p4.updateStaticBuffer)
|
||||
if (! p3.updateStaticBuffer)
|
||||
continue;
|
||||
|
||||
UpdateStaticBuffer(p4);
|
||||
}
|
||||
UpdateStaticBuffer(p3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1890,37 +1825,29 @@ int CEngine::DetectObject(Math::Point mouse)
|
|||
|
||||
for (int l3 = 0; l3 < static_cast<int>( p2.next.size() ); l3++)
|
||||
{
|
||||
EngineBaseObjLODTier& p3 = p2.next[l3];
|
||||
EngineBaseObjDataTier& p3 = p2.next[l3];
|
||||
|
||||
if (p3.lodLevel != LOD_Constant && p3.lodLevel != LOD_High)
|
||||
continue;
|
||||
|
||||
for (int l4 = 0; l4 < static_cast<int>( p3.next.size() ); l4++)
|
||||
if (p3.type == ENG_TRIANGLE_TYPE_TRIANGLES)
|
||||
{
|
||||
EngineBaseObjDataTier& p4 = p3.next[l4];
|
||||
|
||||
if (p4.type == ENG_TRIANGLE_TYPE_TRIANGLES)
|
||||
for (int i = 0; i < static_cast<int>( p3.vertices.size() ); i += 3)
|
||||
{
|
||||
for (int i = 0; i < static_cast<int>( p4.vertices.size() ); i += 3)
|
||||
float dist = 0.0f;
|
||||
if (DetectTriangle(mouse, &p3.vertices[i], objRank, dist) && dist < min)
|
||||
{
|
||||
float dist = 0.0f;
|
||||
if (DetectTriangle(mouse, &p4.vertices[i], objRank, dist) && dist < min)
|
||||
{
|
||||
min = dist;
|
||||
nearest = objRank;
|
||||
}
|
||||
min = dist;
|
||||
nearest = objRank;
|
||||
}
|
||||
}
|
||||
else if (p4.type == ENG_TRIANGLE_TYPE_SURFACE)
|
||||
}
|
||||
else if (p3.type == ENG_TRIANGLE_TYPE_SURFACE)
|
||||
{
|
||||
for (int i = 0; i < static_cast<int>( p3.vertices.size() ) - 2; i += 1)
|
||||
{
|
||||
for (int i = 0; i < static_cast<int>( p4.vertices.size() ) - 2; i += 1)
|
||||
float dist = 0.0f;
|
||||
if (DetectTriangle(mouse, &p3.vertices[i], objRank, dist) && dist < min)
|
||||
{
|
||||
float dist = 0.0f;
|
||||
if (DetectTriangle(mouse, &p4.vertices[i], objRank, dist) && dist < min)
|
||||
{
|
||||
min = dist;
|
||||
nearest = objRank;
|
||||
}
|
||||
min = dist;
|
||||
nearest = objRank;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2005,43 +1932,6 @@ bool CEngine::IsVisible(int objRank)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool CEngine::IsWithinLODLimit(float distance, LODLevel lodLevel)
|
||||
{
|
||||
float min = 0.0f, max = 0.0f;
|
||||
|
||||
if (lodLevel == LOD_Constant)
|
||||
{
|
||||
min = 0.0f;
|
||||
max = m_terrainVision * m_clippingDistance;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (lodLevel == LOD_High)
|
||||
{
|
||||
min = 0.0f;
|
||||
max = 100.0f;
|
||||
}
|
||||
else if (lodLevel == LOD_Medium)
|
||||
{
|
||||
min = 100.0f;
|
||||
max = 200.0f;
|
||||
}
|
||||
else if (lodLevel == LOD_Low)
|
||||
{
|
||||
min = 100.0f;
|
||||
max = 1000000.0f;
|
||||
}
|
||||
|
||||
min *= m_size.x / 640.0f;
|
||||
min *= 1.0f+m_objectDetail*2.0f;
|
||||
|
||||
max *= m_size.x / 640.0f;
|
||||
max *= 1.0f+m_objectDetail*2.0f;
|
||||
}
|
||||
|
||||
return distance >= min && distance < max;
|
||||
}
|
||||
|
||||
bool CEngine::TransformPoint(Math::Vector& p2D, int objRank, Math::Vector p3D)
|
||||
{
|
||||
assert(objRank >= 0 && objRank < static_cast<int>(m_objects.size()));
|
||||
|
@ -3327,20 +3217,12 @@ void CEngine::Draw3DScene()
|
|||
|
||||
for (int l3 = 0; l3 < static_cast<int>( p2.next.size() ); l3++)
|
||||
{
|
||||
EngineBaseObjLODTier& p3 = p2.next[l3];
|
||||
EngineBaseObjDataTier& p3 = p2.next[l3];
|
||||
|
||||
if (! IsWithinLODLimit(m_objects[objRank].distance, p3.lodLevel))
|
||||
continue;
|
||||
SetMaterial(p3.material);
|
||||
SetState(p3.state);
|
||||
|
||||
for (int l4 = 0; l4 < static_cast<int>( p3.next.size() ); l4++)
|
||||
{
|
||||
EngineBaseObjDataTier& p4 = p3.next[l4];
|
||||
|
||||
SetMaterial(p4.material);
|
||||
SetState(p4.state);
|
||||
|
||||
DrawObject(p4);
|
||||
}
|
||||
DrawObject(p3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3398,26 +3280,18 @@ void CEngine::Draw3DScene()
|
|||
|
||||
for (int l3 = 0; l3 < static_cast<int>( p2.next.size() ); l3++)
|
||||
{
|
||||
EngineBaseObjLODTier& p3 = p2.next[l3];
|
||||
EngineBaseObjDataTier& p3 = p2.next[l3];
|
||||
|
||||
if (! IsWithinLODLimit(m_objects[objRank].distance, p3.lodLevel))
|
||||
continue;
|
||||
|
||||
for (int l4 = 0; l4 < static_cast<int>( p3.next.size() ); l4++)
|
||||
if (m_objects[objRank].transparency != 0.0f) // transparent ?
|
||||
{
|
||||
EngineBaseObjDataTier& p4 = p3.next[l4];
|
||||
|
||||
if (m_objects[objRank].transparency != 0.0f) // transparent ?
|
||||
{
|
||||
transparent = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
SetMaterial(p4.material);
|
||||
SetState(p4.state);
|
||||
|
||||
DrawObject(p4);
|
||||
transparent = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
SetMaterial(p3.material);
|
||||
SetState(p3.state);
|
||||
|
||||
DrawObject(p3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3468,23 +3342,15 @@ void CEngine::Draw3DScene()
|
|||
|
||||
for (int l3 = 0; l3 < static_cast<int>( p2.next.size() ); l3++)
|
||||
{
|
||||
EngineBaseObjLODTier& p3 = p2.next[l3];
|
||||
EngineBaseObjDataTier& p3 = p2.next[l3];
|
||||
|
||||
if (! IsWithinLODLimit(m_objects[objRank].distance, p3.lodLevel))
|
||||
if (m_objects[objRank].transparency == 0.0f)
|
||||
continue;
|
||||
|
||||
for (int l4 = 0; l4 < static_cast<int>( p3.next.size() ); l4++)
|
||||
{
|
||||
EngineBaseObjDataTier& p4 = p3.next[l4];
|
||||
SetMaterial(p3.material);
|
||||
SetState(tState, tColor);
|
||||
|
||||
if (m_objects[objRank].transparency == 0.0f)
|
||||
continue;
|
||||
|
||||
SetMaterial(p4.material);
|
||||
SetState(tState, tColor);
|
||||
|
||||
DrawObject(p4);
|
||||
}
|
||||
DrawObject(p3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3688,17 +3554,8 @@ void CEngine::RenderShadowMap()
|
|||
|
||||
for (int l3 = 0; l3 < static_cast<int>(p2.next.size()); l3++)
|
||||
{
|
||||
EngineBaseObjLODTier& p3 = p2.next[l3];
|
||||
|
||||
if (!IsWithinLODLimit(m_objects[objRank].distance, p3.lodLevel))
|
||||
continue;
|
||||
|
||||
for (int l4 = 0; l4 < static_cast<int>(p3.next.size()); l4++)
|
||||
{
|
||||
EngineBaseObjDataTier& p4 = p3.next[l4];
|
||||
|
||||
DrawObject(p4);
|
||||
}
|
||||
EngineBaseObjDataTier& p3 = p2.next[l3];
|
||||
DrawObject(p3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4046,20 +3903,12 @@ void CEngine::DrawInterface()
|
|||
|
||||
for (int l3 = 0; l3 < static_cast<int>( p2.next.size() ); l3++)
|
||||
{
|
||||
EngineBaseObjLODTier& p3 = p2.next[l3];
|
||||
EngineBaseObjDataTier& p3 = p2.next[l3];
|
||||
|
||||
if (! IsWithinLODLimit(m_objects[objRank].distance, p3.lodLevel))
|
||||
continue;
|
||||
SetMaterial(p3.material);
|
||||
SetState(p3.state);
|
||||
|
||||
for (int l4 = 0; l4 < static_cast<int>( p3.next.size() ); l4++)
|
||||
{
|
||||
EngineBaseObjDataTier& p4 = p3.next[l4];
|
||||
|
||||
SetMaterial(p4.material);
|
||||
SetState(p4.state);
|
||||
|
||||
DrawObject(p4);
|
||||
}
|
||||
DrawObject(p3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,8 +35,6 @@
|
|||
#include "graphics/core/texture.h"
|
||||
#include "graphics/core/vertex.h"
|
||||
|
||||
#include "graphics/engine/modelfile.h"
|
||||
|
||||
#include "math/intpoint.h"
|
||||
#include "math/matrix.h"
|
||||
#include "math/point.h"
|
||||
|
@ -62,7 +60,7 @@ namespace Gfx {
|
|||
|
||||
|
||||
class CDevice;
|
||||
class CModelManager;
|
||||
class COldModelManager;
|
||||
class CLightManager;
|
||||
class CText;
|
||||
class CParticle;
|
||||
|
@ -189,7 +187,7 @@ enum EngineObjectType
|
|||
|
||||
/**
|
||||
* \struct EngineBaseObjDataTier
|
||||
* \brief Tier 4 of object tree (data)
|
||||
* \brief Tier 3 of object tree (data)
|
||||
*/
|
||||
struct EngineBaseObjDataTier
|
||||
{
|
||||
|
@ -211,20 +209,6 @@ struct EngineBaseObjDataTier
|
|||
{}
|
||||
};
|
||||
|
||||
/**
|
||||
* \struct EngineBaseObjLODTier
|
||||
* \brief Tier 3 of base object tree (LOD)
|
||||
*/
|
||||
struct EngineBaseObjLODTier
|
||||
{
|
||||
LODLevel lodLevel;
|
||||
std::vector<EngineBaseObjDataTier> next;
|
||||
|
||||
inline EngineBaseObjLODTier(LODLevel _lodLevel = LOD_Constant)
|
||||
: lodLevel(_lodLevel)
|
||||
{}
|
||||
};
|
||||
|
||||
/**
|
||||
* \struct EngineBaseObjTexTier
|
||||
* \brief Tier 2 of base object tree (textures)
|
||||
|
@ -235,7 +219,7 @@ struct EngineBaseObjTexTier
|
|||
Texture tex1;
|
||||
std::string tex2Name;
|
||||
Texture tex2;
|
||||
std::vector<EngineBaseObjLODTier> next;
|
||||
std::vector<EngineBaseObjDataTier> next;
|
||||
|
||||
inline EngineBaseObjTexTier(const std::string& _tex1Name = "", const std::string& _tex2Name = "")
|
||||
: tex1Name(_tex1Name)
|
||||
|
@ -261,7 +245,7 @@ struct EngineBaseObject
|
|||
Math::Vector bboxMax;
|
||||
//! Radius of the sphere at the origin
|
||||
float radius;
|
||||
//! Next tier (LOD)
|
||||
//! Next tier (Tex)
|
||||
std::vector<EngineBaseObjTexTier> next;
|
||||
|
||||
inline EngineBaseObject()
|
||||
|
@ -644,8 +628,7 @@ struct EngineMouse
|
|||
* The 4 tiers contain the following information:
|
||||
* - level 1 (EngineBaseObject) - geometric statistics
|
||||
* - level 2 (EngineBaseObjTexTier) - two textures (names and structs) applied to triangles,
|
||||
* - level 3 (EngineBaseObjLODTier) - minumum and maximum LOD (=level of detail)
|
||||
* - level 4 (EngineBaseObjDataTier) - type of object*, material, render state and the actual vertex data
|
||||
* - level 3 (EngineBaseObjDataTier) - type of object*, material, render state and the actual vertex data
|
||||
*
|
||||
* *NOTE: type of object in this context means only the internal type in 3D engine. It is not related
|
||||
* to CObject types.
|
||||
|
@ -697,7 +680,7 @@ public:
|
|||
|
||||
//! Returns the text rendering engine
|
||||
CText* GetText();
|
||||
CModelManager* GetModelManager();
|
||||
COldModelManager* GetModelManager();
|
||||
CPyroManager* GetPyroManager();
|
||||
//! Returns the light manager
|
||||
CLightManager* GetLightManager();
|
||||
|
@ -809,12 +792,12 @@ public:
|
|||
EngineTriangleType triangleType,
|
||||
const Material& material, int state,
|
||||
std::string tex1Name, std::string tex2Name,
|
||||
LODLevel lodLevel, bool globalUpdate);
|
||||
bool globalUpdate);
|
||||
|
||||
//! Adds a tier 4 engine object directly
|
||||
void AddBaseObjQuick(int baseObjRank, const EngineBaseObjDataTier& buffer,
|
||||
std::string tex1Name, std::string tex2Name,
|
||||
LODLevel lodLevel, bool globalUpdate);
|
||||
bool globalUpdate);
|
||||
|
||||
// Objects
|
||||
|
||||
|
@ -862,11 +845,10 @@ public:
|
|||
|
||||
//! Returns the first found tier 4 engine object for the given params or nullptr if not found
|
||||
EngineBaseObjDataTier* FindTriangles(int objRank, const Material& material,
|
||||
int state, std::string tex1Name, std::string tex2Name,
|
||||
int lodLevelMask);
|
||||
int state, std::string tex1Name, std::string tex2Name);
|
||||
|
||||
//! Returns a partial list of triangles for given object
|
||||
int GetPartialTriangles(int objRank, int lodLevelMask, float percent, int maxCount,
|
||||
int GetPartialTriangles(int objRank, float percent, int maxCount,
|
||||
std::vector<EngineTriangle>& triangles);
|
||||
|
||||
//! Changes the 2nd texure for given object
|
||||
|
@ -875,13 +857,13 @@ public:
|
|||
//! Changes (recalculates) texture mapping for given object
|
||||
void ChangeTextureMapping(int objRank, const Material& mat, int state,
|
||||
const std::string& tex1Name, const std::string& tex2Name,
|
||||
int lodLevelMask, EngineTextureMapping mode,
|
||||
EngineTextureMapping mode,
|
||||
float au, float bu, float av, float bv);
|
||||
|
||||
//! Changes texture mapping for robot tracks
|
||||
void TrackTextureMapping(int objRank, const Material& mat, int state,
|
||||
const std::string& tex1Name, const std::string& tex2Name,
|
||||
int lodLevelMask, EngineTextureMapping mode,
|
||||
EngineTextureMapping mode,
|
||||
float pos, float factor, float tl, float ts, float tt);
|
||||
|
||||
//! Detects the target object that is selected with the mouse
|
||||
|
@ -1297,10 +1279,8 @@ protected:
|
|||
|
||||
//! Creates a new tier 2 object (texture)
|
||||
EngineBaseObjTexTier& AddLevel2(EngineBaseObject& p1, const std::string& tex1Name, const std::string& tex2Name);
|
||||
//! Creates a new tier 3 object (LOD)
|
||||
EngineBaseObjLODTier& AddLevel3(EngineBaseObjTexTier &p2, LODLevel lodLevel);
|
||||
//! Creates a new tier 4 object (data)
|
||||
EngineBaseObjDataTier& AddLevel4(EngineBaseObjLODTier &p3, EngineTriangleType type,
|
||||
//! Creates a new tier 3 object (data)
|
||||
EngineBaseObjDataTier& AddLevel3(EngineBaseObjTexTier &p3, EngineTriangleType type,
|
||||
const Material& mat, int state);
|
||||
|
||||
//! Create texture and add it to cache
|
||||
|
@ -1309,9 +1289,6 @@ protected:
|
|||
//! Tests whether the given object is visible
|
||||
bool IsVisible(int objRank);
|
||||
|
||||
//! Checks whether the given distance is within LOD min & max limit
|
||||
bool IsWithinLODLimit(float distance, LODLevel lodLevel);
|
||||
|
||||
//! Detects whether an object is affected by the mouse
|
||||
bool DetectBBox(int objRank, Math::Point mouse);
|
||||
|
||||
|
@ -1341,7 +1318,7 @@ protected:
|
|||
CApplication* m_app;
|
||||
CSoundInterface* m_sound;
|
||||
CDevice* m_device;
|
||||
std::unique_ptr<CModelManager> m_modelManager;
|
||||
std::unique_ptr<COldModelManager> m_modelManager;
|
||||
CText* m_text;
|
||||
CLightManager* m_lightMan;
|
||||
CParticle* m_particle;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,159 +0,0 @@
|
|||
/*
|
||||
* This file is part of the Colobot: Gold Edition source code
|
||||
* Copyright (C) 2001-2014, Daniel Roux, EPSITEC SA & TerranovaTeam
|
||||
* http://epsiteс.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
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file graphics/engine/modelfile.h
|
||||
* \brief Model loading - CModelFile class (aka modfile)
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "graphics/core/vertex.h"
|
||||
#include "graphics/core/material.h"
|
||||
|
||||
#include "math/vector.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
|
||||
// Graphics module namespace
|
||||
namespace Gfx {
|
||||
|
||||
|
||||
/**
|
||||
* \enum LODLevel
|
||||
* \brief Level-of-detail
|
||||
*
|
||||
* A quantified replacement for older values of min/max.
|
||||
*/
|
||||
enum LODLevel
|
||||
{
|
||||
LOD_Constant = -1, //!< triangle is always visible, no matter at what distance
|
||||
LOD_Low = 1, //!< triangle is visible at farthest distance (lowest quality)
|
||||
LOD_Medium = 2, //!< triangle is visible at medium distance (medium quality)
|
||||
LOD_High = 4 //!< triangle is visible at closest distance (highest quality)
|
||||
};
|
||||
|
||||
/**
|
||||
* \struct ModelTriangle
|
||||
* \brief Triangle of a 3D model
|
||||
*/
|
||||
struct ModelTriangle
|
||||
{
|
||||
//! 1st vertex
|
||||
VertexTex2 p1;
|
||||
//! 2nd vertex
|
||||
VertexTex2 p2;
|
||||
//! 3rd vertex
|
||||
VertexTex2 p3;
|
||||
//! Material
|
||||
Material material;
|
||||
//! Name of 1st texture
|
||||
std::string tex1Name;
|
||||
//! Name of 2nd texture
|
||||
std::string tex2Name;
|
||||
//! If true, 2nd texture will be taken from current engine setting
|
||||
bool variableTex2;
|
||||
//! LOD level
|
||||
LODLevel lodLevel;
|
||||
//! Rendering state to be set
|
||||
int state;
|
||||
|
||||
ModelTriangle()
|
||||
{
|
||||
variableTex2 = true;
|
||||
lodLevel = LOD_Constant;
|
||||
state = 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \class CModelFile
|
||||
* \brief Model file reader/writer
|
||||
*
|
||||
* Allows reading and writing model objects. Models are collections of ModelTriangle structs.
|
||||
*/
|
||||
class CModelFile
|
||||
{
|
||||
public:
|
||||
CModelFile();
|
||||
~CModelFile();
|
||||
|
||||
//! Reads a model in text format from file
|
||||
bool ReadTextModel(const std::string &fileName);
|
||||
//! Reads a model in text format from stream
|
||||
bool ReadTextModel(std::istream &stream);
|
||||
|
||||
//! Writes the model in text format to a file
|
||||
bool WriteTextModel(const std::string &fileName);
|
||||
//! Writes the model in text format to a stream
|
||||
bool WriteTextModel(std::ostream &stream);
|
||||
|
||||
//! Reads a model in new binary format from file
|
||||
bool ReadBinaryModel(const std::string &fileName);
|
||||
//! Reads a model in new binary format from stream
|
||||
bool ReadBinaryModel(std::istream &stream);
|
||||
|
||||
//! Writes the model in binary format to a file
|
||||
bool WriteBinaryModel(const std::string &fileName);
|
||||
//! Writes the model in binary format to a stream
|
||||
bool WriteBinaryModel(std::ostream &stream);
|
||||
|
||||
//! Reads a binary Colobot model from file
|
||||
//! @deprecated
|
||||
bool ReadModel(const std::string &fileName);
|
||||
//! Reads a binary Colobot model from stream
|
||||
//! @deprecated
|
||||
bool ReadModel(std::istream &stream);
|
||||
//! Writes the model to Colobot binary model file
|
||||
//! @deprecated
|
||||
bool WriteModel(const std::string &fileName);
|
||||
//! Writes the model to Colobot binary model file
|
||||
//! @deprecated
|
||||
bool WriteModel(std::ostream &stream);
|
||||
|
||||
//! Returns the number of triangles in model
|
||||
int GetTriangleCount();
|
||||
|
||||
//! Returns the triangle vector
|
||||
const std::vector<ModelTriangle>& GetTriangles();
|
||||
|
||||
//! Controls printing of debug information
|
||||
void SetPrintDebugInfo(bool printDebugInfo);
|
||||
|
||||
protected:
|
||||
//@{
|
||||
//! @deprecated min, max conversions
|
||||
LODLevel MinMaxToLodLevel(float min, float max);
|
||||
void LODLevelToMinMax(LODLevel lodLevel, float& min, float& max);
|
||||
//@}
|
||||
|
||||
protected:
|
||||
//! Model triangles
|
||||
std::vector<ModelTriangle> m_triangles;
|
||||
bool m_printDebugInfo;
|
||||
};
|
||||
|
||||
}; // namespace Gfx
|
||||
|
|
@ -17,45 +17,57 @@
|
|||
* along with this program. If not, see http://gnu.org/licenses
|
||||
*/
|
||||
|
||||
#include "graphics/engine/modelmanager.h"
|
||||
#include "graphics/engine/oldmodelmanager.h"
|
||||
|
||||
#include "app/app.h"
|
||||
|
||||
#include "common/logger.h"
|
||||
#include "common/resources/inputstream.h"
|
||||
|
||||
#include "graphics/engine/engine.h"
|
||||
|
||||
#include "graphics/model/model_input.h"
|
||||
#include "graphics/model/model_io_exception.h"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
namespace Gfx {
|
||||
|
||||
CModelManager::CModelManager(CEngine* engine)
|
||||
COldModelManager::COldModelManager(CEngine* engine)
|
||||
{
|
||||
m_engine = engine;
|
||||
}
|
||||
|
||||
CModelManager::~CModelManager()
|
||||
COldModelManager::~COldModelManager()
|
||||
{
|
||||
}
|
||||
|
||||
bool CModelManager::LoadModel(const std::string& fileName, bool mirrored)
|
||||
bool COldModelManager::LoadModel(const std::string& fileName, bool mirrored)
|
||||
{
|
||||
GetLogger()->Debug("Loading model '%s'\n", fileName.c_str());
|
||||
|
||||
CModelFile modelFile;
|
||||
|
||||
if (CApplication::GetInstance().IsDebugModeActive(DEBUG_MODELS))
|
||||
modelFile.SetPrintDebugInfo(true);
|
||||
|
||||
if (!modelFile.ReadModel("models/" + fileName))
|
||||
CModel model;
|
||||
try
|
||||
{
|
||||
GetLogger()->Error("Loading model '%s' failed\n", fileName.c_str());
|
||||
CInputStream stream;
|
||||
stream.open("models/" + fileName);
|
||||
if (!stream.is_open())
|
||||
throw CModelIOException(std::string("Could not open file '") + fileName + "'");
|
||||
|
||||
model = ModelInput::Read(stream, ModelFormat::Old);
|
||||
}
|
||||
catch (const CModelIOException& e)
|
||||
{
|
||||
GetLogger()->Error("Loading model '%s' failed: %s\n", fileName.c_str(), e.what());
|
||||
return false;
|
||||
}
|
||||
|
||||
CModelMesh* mesh = model.GetMesh("main");
|
||||
assert(mesh != nullptr);
|
||||
|
||||
ModelInfo modelInfo;
|
||||
modelInfo.baseObjRank = m_engine->CreateBaseObject();
|
||||
modelInfo.triangles = modelFile.GetTriangles();
|
||||
modelInfo.triangles = mesh->GetTriangles();
|
||||
|
||||
if (mirrored)
|
||||
Mirror(modelInfo.triangles);
|
||||
|
@ -65,41 +77,37 @@ bool CModelManager::LoadModel(const std::string& fileName, bool mirrored)
|
|||
|
||||
std::vector<VertexTex2> vs(3, VertexTex2());
|
||||
|
||||
for (int i = 0; i < static_cast<int>( modelInfo.triangles.size() ); i++)
|
||||
for (const auto& triangle : modelInfo.triangles)
|
||||
{
|
||||
int state = modelInfo.triangles[i].state;
|
||||
std::string tex1Name = "objects/"+modelInfo.triangles[i].tex1Name;
|
||||
if(modelInfo.triangles[i].tex1Name.empty())
|
||||
tex1Name.clear();
|
||||
std::string tex2Name = modelInfo.triangles[i].tex2Name;
|
||||
vs[0] = triangle.p1;
|
||||
vs[1] = triangle.p2;
|
||||
vs[2] = triangle.p3;
|
||||
|
||||
if (modelInfo.triangles[i].variableTex2)
|
||||
{
|
||||
state |= ENG_RSTATE_DUAL_BLACK;
|
||||
Material material;
|
||||
material.ambient = triangle.ambient;
|
||||
material.diffuse = triangle.diffuse;
|
||||
material.specular = triangle.specular;
|
||||
|
||||
/*TODO: This seems to be not used by Colobot
|
||||
if (texNum >= 1 && texNum <= 10)
|
||||
state |= ENG_RSTATE_DUAL_BLACK;
|
||||
int state = GetEngineState(triangle);
|
||||
|
||||
if (texNum >= 11 && texNum <= 20)
|
||||
state |= ENG_RSTATE_DUAL_WHITE;*/
|
||||
std::string tex1Name;
|
||||
if (!triangle.tex1Name.empty())
|
||||
tex1Name = "objects/" + triangle.tex1Name;
|
||||
|
||||
std::string tex2Name;
|
||||
if (triangle.variableTex2)
|
||||
tex2Name = m_engine->GetSecondTexture();
|
||||
}
|
||||
|
||||
vs[0] = modelInfo.triangles[i].p1;
|
||||
vs[1] = modelInfo.triangles[i].p2;
|
||||
vs[2] = modelInfo.triangles[i].p3;
|
||||
else
|
||||
tex2Name = triangle.tex2Name;
|
||||
|
||||
m_engine->AddBaseObjTriangles(modelInfo.baseObjRank, vs, ENG_TRIANGLE_TYPE_TRIANGLES,
|
||||
modelInfo.triangles[i].material, state,
|
||||
tex1Name, tex2Name,
|
||||
modelInfo.triangles[i].lodLevel, false);
|
||||
material, state, tex1Name, tex2Name, false);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CModelManager::AddModelReference(const std::string& fileName, bool mirrored, int objRank)
|
||||
bool COldModelManager::AddModelReference(const std::string& fileName, bool mirrored, int objRank)
|
||||
{
|
||||
auto it = m_models.find(FileInfo(fileName, mirrored));
|
||||
if (it == m_models.end())
|
||||
|
@ -115,7 +123,7 @@ bool CModelManager::AddModelReference(const std::string& fileName, bool mirrored
|
|||
return true;
|
||||
}
|
||||
|
||||
bool CModelManager::AddModelCopy(const std::string& fileName, bool mirrored, int objRank)
|
||||
bool COldModelManager::AddModelCopy(const std::string& fileName, bool mirrored, int objRank)
|
||||
{
|
||||
auto it = m_models.find(FileInfo(fileName, mirrored));
|
||||
if (it == m_models.end())
|
||||
|
@ -135,12 +143,12 @@ bool CModelManager::AddModelCopy(const std::string& fileName, bool mirrored, int
|
|||
return true;
|
||||
}
|
||||
|
||||
bool CModelManager::IsModelLoaded(const std::string& fileName, bool mirrored)
|
||||
bool COldModelManager::IsModelLoaded(const std::string& fileName, bool mirrored)
|
||||
{
|
||||
return m_models.count(FileInfo(fileName, mirrored)) > 0;
|
||||
}
|
||||
|
||||
int CModelManager::GetModelBaseObjRank(const std::string& fileName, bool mirrored)
|
||||
int COldModelManager::GetModelBaseObjRank(const std::string& fileName, bool mirrored)
|
||||
{
|
||||
auto it = m_models.find(FileInfo(fileName, mirrored));
|
||||
if (it == m_models.end())
|
||||
|
@ -149,7 +157,7 @@ int CModelManager::GetModelBaseObjRank(const std::string& fileName, bool mirrore
|
|||
return (*it).second.baseObjRank;
|
||||
}
|
||||
|
||||
void CModelManager::DeleteAllModelCopies()
|
||||
void COldModelManager::DeleteAllModelCopies()
|
||||
{
|
||||
for (int baseObjRank : m_copiesBaseRanks)
|
||||
{
|
||||
|
@ -159,7 +167,7 @@ void CModelManager::DeleteAllModelCopies()
|
|||
m_copiesBaseRanks.clear();
|
||||
}
|
||||
|
||||
void CModelManager::UnloadModel(const std::string& fileName, bool mirrored)
|
||||
void COldModelManager::UnloadModel(const std::string& fileName, bool mirrored)
|
||||
{
|
||||
auto it = m_models.find(FileInfo(fileName, mirrored));
|
||||
if (it == m_models.end())
|
||||
|
@ -170,7 +178,7 @@ void CModelManager::UnloadModel(const std::string& fileName, bool mirrored)
|
|||
m_models.erase(it);
|
||||
}
|
||||
|
||||
void CModelManager::UnloadAllModels()
|
||||
void COldModelManager::UnloadAllModels()
|
||||
{
|
||||
for (auto& mf : m_models)
|
||||
m_engine->DeleteBaseObject(mf.second.baseObjRank);
|
||||
|
@ -178,7 +186,7 @@ void CModelManager::UnloadAllModels()
|
|||
m_models.clear();
|
||||
}
|
||||
|
||||
void CModelManager::Mirror(std::vector<ModelTriangle>& triangles)
|
||||
void COldModelManager::Mirror(std::vector<ModelTriangle>& triangles)
|
||||
{
|
||||
for (int i = 0; i < static_cast<int>( triangles.size() ); i++)
|
||||
{
|
||||
|
@ -196,28 +204,54 @@ void CModelManager::Mirror(std::vector<ModelTriangle>& triangles)
|
|||
}
|
||||
}
|
||||
|
||||
float CModelManager::GetHeight(std::vector<ModelTriangle>& triangles, Math::Vector pos)
|
||||
int COldModelManager::GetEngineState(const ModelTriangle& triangle)
|
||||
{
|
||||
const float limit = 5.0f;
|
||||
int state = 0;
|
||||
|
||||
for (int i = 0; i < static_cast<int>( triangles.size() ); i++)
|
||||
if (!triangle.tex2Name.empty() || triangle.variableTex2)
|
||||
state |= ENG_RSTATE_DUAL_BLACK;
|
||||
|
||||
switch (triangle.transparentMode)
|
||||
{
|
||||
if ( fabs(pos.x - triangles[i].p1.coord.x) < limit &&
|
||||
fabs(pos.z - triangles[i].p1.coord.z) < limit )
|
||||
return triangles[i].p1.coord.y;
|
||||
case ModelTransparentMode::None:
|
||||
break;
|
||||
|
||||
if ( fabs(pos.x - triangles[i].p2.coord.x) < limit &&
|
||||
fabs(pos.z - triangles[i].p2.coord.z) < limit )
|
||||
return triangles[i].p2.coord.y;
|
||||
case ModelTransparentMode::AlphaChannel:
|
||||
state |= ENG_RSTATE_ALPHA;
|
||||
break;
|
||||
|
||||
if ( fabs(pos.x - triangles[i].p3.coord.x) < limit &&
|
||||
fabs(pos.z - triangles[i].p3.coord.z) < limit )
|
||||
return triangles[i].p3.coord.y;
|
||||
case ModelTransparentMode::MapBlackToAlpha:
|
||||
state |= ENG_RSTATE_TTEXTURE_BLACK;
|
||||
break;
|
||||
|
||||
case ModelTransparentMode::MapWhiteToAlpha:
|
||||
state |= ENG_RSTATE_TTEXTURE_WHITE;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0.0f;
|
||||
}
|
||||
switch (triangle.specialMark)
|
||||
{
|
||||
case ModelSpecialMark::None:
|
||||
break;
|
||||
|
||||
case ModelSpecialMark::Part1:
|
||||
state |= ENG_RSTATE_PART1;
|
||||
break;
|
||||
|
||||
case ModelSpecialMark::Part2:
|
||||
state |= ENG_RSTATE_PART2;
|
||||
break;
|
||||
|
||||
case ModelSpecialMark::Part3:
|
||||
state |= ENG_RSTATE_PART3;
|
||||
break;
|
||||
}
|
||||
|
||||
if (triangle.doubleSided)
|
||||
state |= ENG_RSTATE_2FACE;
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
#include "common/singleton.h"
|
||||
|
||||
#include "graphics/engine/modelfile.h"
|
||||
#include "graphics/model/model_triangle.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
@ -33,7 +33,7 @@ class CEngine;
|
|||
class CModelFile;
|
||||
|
||||
/**
|
||||
* \class CModelManager
|
||||
* \class COldModelManager
|
||||
* \brief Manager for static models
|
||||
*
|
||||
* The manager allows for loading models as static objects and adding
|
||||
|
@ -51,11 +51,11 @@ class CModelFile;
|
|||
* its own and unique base engine object. This is especially useful
|
||||
* for models where the geometry must be altered.
|
||||
*/
|
||||
class CModelManager
|
||||
class COldModelManager
|
||||
{
|
||||
public:
|
||||
CModelManager(CEngine* engine);
|
||||
~CModelManager();
|
||||
COldModelManager(CEngine* engine);
|
||||
~COldModelManager();
|
||||
|
||||
//! Loads a model from given file
|
||||
bool LoadModel(const std::string& fileName, bool mirrored);
|
||||
|
@ -81,12 +81,12 @@ public:
|
|||
void UnloadAllModels();
|
||||
|
||||
protected:
|
||||
//! Returns the height of model -- closest point to X and Z coords of \a pos
|
||||
float GetHeight(std::vector<ModelTriangle>& triangles, Math::Vector pos);
|
||||
|
||||
//! Mirrors the model along the Z axis
|
||||
void Mirror(std::vector<ModelTriangle>& triangles);
|
||||
|
||||
//! Converts from model to engine rendering state
|
||||
int GetEngineState(const ModelTriangle& triangle);
|
||||
|
||||
private:
|
||||
struct ModelInfo
|
||||
{
|
|
@ -1427,17 +1427,8 @@ void CPyro::CreateTriangle(CObject* obj, ObjectType oType, int part)
|
|||
percent = 0.50f;
|
||||
}
|
||||
|
||||
LODLevel lodLevel = LOD_High;
|
||||
|
||||
if (oType == OBJECT_MOTHER ||
|
||||
oType == OBJECT_TEEN28 ||
|
||||
oType == OBJECT_TEEN31)
|
||||
{
|
||||
lodLevel = LOD_Constant;
|
||||
}
|
||||
|
||||
std::vector<EngineTriangle> buffer;
|
||||
total = m_engine->GetPartialTriangles(objRank, lodLevel, percent, 100, buffer);
|
||||
total = m_engine->GetPartialTriangles(objRank, percent, 100, buffer);
|
||||
|
||||
for (int i = 0; i < total; i++)
|
||||
{
|
||||
|
|
|
@ -716,7 +716,7 @@ bool CTerrain::CreateMosaic(int ox, int oy, int step, int objRank,
|
|||
buffer.vertices.push_back(p2);
|
||||
}
|
||||
|
||||
m_engine->AddBaseObjQuick(baseObjRank, buffer, texName1, texName2, LOD_Constant, true);
|
||||
m_engine->AddBaseObjQuick(baseObjRank, buffer, texName1, texName2, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
#include "graphics/model/model.h"
|
||||
|
||||
#include "common/logger.h"
|
||||
|
||||
|
||||
namespace Gfx {
|
||||
|
||||
int CModel::GetMeshCount() const
|
||||
{
|
||||
return m_meshes.size();
|
||||
}
|
||||
|
||||
CModelMesh* CModel::GetMesh(const std::string& name)
|
||||
{
|
||||
auto it = m_meshes.find(name);
|
||||
if (it == m_meshes.end())
|
||||
{
|
||||
GetLogger()->Error("Mesh named '%s' not found in model!\n", name.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
return &(it->second);
|
||||
}
|
||||
|
||||
const CModelMesh* CModel::GetMesh(const std::string& name) const
|
||||
{
|
||||
auto it = m_meshes.find(name);
|
||||
if (it == m_meshes.end())
|
||||
{
|
||||
GetLogger()->Error("Mesh named '%s' not found in model!\n", name.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
return &(it->second);
|
||||
}
|
||||
|
||||
void CModel::AddMesh(const std::string& name, CModelMesh&& mesh)
|
||||
{
|
||||
m_meshes[name] = mesh;
|
||||
}
|
||||
|
||||
const boost::optional<ModelShadowSpot>& CModel::GetShadowSpot() const
|
||||
{
|
||||
return m_shadowSpot;
|
||||
}
|
||||
|
||||
void CModel::SetShadowSpot(const ModelShadowSpot& shadowSpot)
|
||||
{
|
||||
m_shadowSpot = shadowSpot;
|
||||
}
|
||||
|
||||
const std::vector<ModelCrashSphere>& CModel::GetCrashSpheres() const
|
||||
{
|
||||
return m_crashSpheres;
|
||||
}
|
||||
|
||||
void CModel::AddCrashSphere(const ModelCrashSphere& crashSphere)
|
||||
{
|
||||
m_crashSpheres.push_back(crashSphere);
|
||||
}
|
||||
|
||||
} // namespace Gfx
|
|
@ -0,0 +1,46 @@
|
|||
#pragma once
|
||||
|
||||
#include "graphics/model/model_crash_sphere.h"
|
||||
#include "graphics/model/model_mesh.h"
|
||||
#include "graphics/model/model_shadow_spot.h"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
namespace Gfx {
|
||||
|
||||
/**
|
||||
* \class CModel
|
||||
* \brief 3D model saved in model file
|
||||
*/
|
||||
class CModel
|
||||
{
|
||||
public:
|
||||
//! Returns mesh count
|
||||
int GetMeshCount() const;
|
||||
//! Return a mesh with given \a name
|
||||
CModelMesh* GetMesh(const std::string& name);
|
||||
//! Return a mesh with given \a name
|
||||
const CModelMesh* GetMesh(const std::string& name) const;
|
||||
//! Add new \a mesh with given \a name
|
||||
void AddMesh(const std::string& name, CModelMesh&& mesh);
|
||||
|
||||
//! Returns the optional shadow spot associated with model
|
||||
const boost::optional<ModelShadowSpot>& GetShadowSpot() const;
|
||||
//! Sets the shadow spot associated with model
|
||||
void SetShadowSpot(const ModelShadowSpot& shadowSpot);
|
||||
|
||||
//! Returns the model's crash spheres
|
||||
const std::vector<ModelCrashSphere>& GetCrashSpheres() const;
|
||||
//! Adds a new crash sphere
|
||||
void AddCrashSphere(const ModelCrashSphere& crashSphere);
|
||||
|
||||
private:
|
||||
std::map<std::string, CModelMesh> m_meshes;
|
||||
boost::optional<ModelShadowSpot> m_shadowSpot;
|
||||
std::vector<ModelCrashSphere> m_crashSpheres;
|
||||
};
|
||||
|
||||
} // namespace Gfx
|
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
#include "math/vector.h"
|
||||
|
||||
namespace Gfx {
|
||||
|
||||
/**
|
||||
* \struct ModelCrashSphere
|
||||
* \brief Crash sphere data as saved in model file
|
||||
*/
|
||||
struct ModelCrashSphere
|
||||
{
|
||||
Math::Vector position;
|
||||
float radius = 0.0f;
|
||||
std::string sound;
|
||||
float hardness = 0.0f;
|
||||
};
|
||||
|
||||
} // namespace Gfx
|
|
@ -0,0 +1,16 @@
|
|||
#pragma once
|
||||
|
||||
namespace Gfx {
|
||||
|
||||
/**
|
||||
* \enum ModelFormat
|
||||
* \brief Describes model format to use
|
||||
*/
|
||||
enum class ModelFormat
|
||||
{
|
||||
Text, //!< new text format
|
||||
Binary, //!< new binary format
|
||||
Old //!< old binary format, deprecated
|
||||
};
|
||||
|
||||
} // namespace Gfx
|
|
@ -0,0 +1,670 @@
|
|||
#include "graphics/model/model_input.h"
|
||||
|
||||
#include "common/ioutils.h"
|
||||
#include "common/logger.h"
|
||||
#include "common/resources/inputstream.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 {
|
||||
|
||||
// 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);
|
||||
|
||||
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);
|
||||
|
||||
Vertex ReadBinaryVertex(std::istream& stream);
|
||||
VertexTex2 ReadBinaryVertexTex2(std::istream& stream);
|
||||
Material ReadBinaryMaterial(std::istream& stream);
|
||||
|
||||
std::string ReadLineString(std::istream& stream, const std::string& prefix);
|
||||
VertexTex2 ParseVertexTex2(const std::string& text);
|
||||
Material ParseTextMaterial(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);
|
||||
|
||||
CModel model;
|
||||
|
||||
try
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case ModelFormat::Binary:
|
||||
ReadBinaryModel(model, stream);
|
||||
break;
|
||||
|
||||
case ModelFormat::Text:
|
||||
ReadTextModel(model, stream);
|
||||
break;
|
||||
|
||||
case ModelFormat::Old:
|
||||
ReadOldModel(model, stream);
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (const CModelIOException& e)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
throw CModelIOException(std::string("Other error while reading model data: ") + e.what());
|
||||
}
|
||||
|
||||
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: ") + std::to_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);
|
||||
t.material = ReadBinaryMaterial(stream);
|
||||
t.tex1Name = ReadBinaryString<1>(stream);
|
||||
t.tex2Name = ReadBinaryString<1>(stream);
|
||||
t.variableTex2 = ReadBinaryBool(stream);
|
||||
|
||||
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.diffuse = t.material.diffuse;
|
||||
triangle.specular = t.material.specular;
|
||||
triangle.ambient = t.material.ambient;
|
||||
triangle.tex1Name = t.tex1Name;
|
||||
triangle.tex2Name = t.tex2Name;
|
||||
triangle.variableTex2 = 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: ") + std::to_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");
|
||||
t.material = ParseTextMaterial(matText);
|
||||
|
||||
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.ambient = t.material.ambient;
|
||||
triangle.diffuse = t.material.diffuse;
|
||||
triangle.specular = t.material.specular;
|
||||
triangle.tex1Name = t.tex1Name;
|
||||
triangle.tex2Name = t.tex2Name;
|
||||
triangle.variableTex2 = t.variableTex2;
|
||||
ConvertFromOldRenderState(triangle, t.state);
|
||||
|
||||
mesh.AddTriangle(triangle);
|
||||
}
|
||||
|
||||
model.AddMesh("main", std::move(mesh));
|
||||
}
|
||||
|
||||
void ModelInput::ReadTextModelV3(CModel &model, std::istream &stream)
|
||||
{
|
||||
// TODO...
|
||||
}
|
||||
|
||||
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;
|
||||
mesh.SetTriangles(std::move(triangles));
|
||||
|
||||
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);
|
||||
|
||||
t.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.FromVertex(t.p1);
|
||||
triangle.p2.FromVertex(t.p2);
|
||||
triangle.p3.FromVertex(t.p3);
|
||||
|
||||
triangle.ambient = t.material.ambient;
|
||||
triangle.diffuse = t.material.diffuse;
|
||||
triangle.specular = t.material.specular;
|
||||
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);
|
||||
|
||||
t.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.FromVertex(t.p1);
|
||||
triangle.p2.FromVertex(t.p2);
|
||||
triangle.p3.FromVertex(t.p3);
|
||||
|
||||
triangle.ambient = t.material.ambient;
|
||||
triangle.diffuse = t.material.diffuse;
|
||||
triangle.specular = t.material.specular;
|
||||
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);
|
||||
|
||||
t.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;
|
||||
|
||||
triangle.ambient = t.material.ambient;
|
||||
triangle.diffuse = t.material.diffuse;
|
||||
triangle.specular = t.material.specular;
|
||||
ConvertOldTex1Name(triangle, t.texName);
|
||||
|
||||
ConvertFromOldRenderState(triangle, t.state);
|
||||
triangle.variableTex2 = t.texNum2 == 1;
|
||||
|
||||
if (!triangle.variableTex2 && t.texNum2 != 0)
|
||||
{
|
||||
char tex2Name[20] = { 0 };
|
||||
std::sprintf(tex2Name, "dirty%.2d.png", t.texNum2);
|
||||
triangle.tex2Name = 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.tex1Name = tex1Name;
|
||||
boost::replace_all(triangle.tex1Name, "bmp", "png");
|
||||
boost::replace_all(triangle.tex1Name, "tga", "png");
|
||||
}
|
||||
|
||||
void ModelInput::ConvertFromOldRenderState(ModelTriangle& triangle, int state)
|
||||
{
|
||||
if (triangle.tex1Name == "plant.png" || (state & static_cast<int>(ModelRenderState::Alpha)) != 0)
|
||||
triangle.transparentMode = ModelTransparentMode::AlphaChannel;
|
||||
else if ((state & static_cast<int>(ModelRenderState::TTextureBlack)) != 0)
|
||||
triangle.transparentMode = ModelTransparentMode::MapBlackToAlpha;
|
||||
else if ((state & static_cast<int>(ModelRenderState::TTextureWhite)) != 0)
|
||||
triangle.transparentMode = ModelTransparentMode::MapWhiteToAlpha;
|
||||
else
|
||||
triangle.transparentMode = ModelTransparentMode::None;
|
||||
|
||||
if ((state & static_cast<int>(ModelRenderState::Part1)) != 0)
|
||||
triangle.specialMark = ModelSpecialMark::Part1;
|
||||
else if ((state & static_cast<int>(ModelRenderState::Part2)) != 0)
|
||||
triangle.specialMark = ModelSpecialMark::Part2;
|
||||
else if ((state & static_cast<int>(ModelRenderState::Part3)) != 0)
|
||||
triangle.specialMark = ModelSpecialMark::Part3;
|
||||
else
|
||||
triangle.specialMark = ModelSpecialMark::None;
|
||||
|
||||
triangle.doubleSided = (state & static_cast<int>(ModelRenderState::TwoFace)) != 0;
|
||||
}
|
||||
|
||||
Vertex ModelInput::ReadBinaryVertex(std::istream& stream)
|
||||
{
|
||||
Vertex vertex;
|
||||
|
||||
vertex.coord.x = ReadBinaryFloat(stream);
|
||||
vertex.coord.y = ReadBinaryFloat(stream);
|
||||
vertex.coord.z = ReadBinaryFloat(stream);
|
||||
|
||||
vertex.normal.x = ReadBinaryFloat(stream);
|
||||
vertex.normal.y = ReadBinaryFloat(stream);
|
||||
vertex.normal.z = ReadBinaryFloat(stream);
|
||||
|
||||
vertex.texCoord.x = ReadBinaryFloat(stream);
|
||||
vertex.texCoord.y = ReadBinaryFloat(stream);
|
||||
|
||||
return vertex;
|
||||
}
|
||||
|
||||
VertexTex2 ModelInput::ReadBinaryVertexTex2(std::istream& stream)
|
||||
{
|
||||
VertexTex2 vertex;
|
||||
|
||||
vertex.coord.x = ReadBinaryFloat(stream);
|
||||
vertex.coord.y = ReadBinaryFloat(stream);
|
||||
vertex.coord.z = ReadBinaryFloat(stream);
|
||||
|
||||
vertex.normal.x = ReadBinaryFloat(stream);
|
||||
vertex.normal.y = ReadBinaryFloat(stream);
|
||||
vertex.normal.z = ReadBinaryFloat(stream);
|
||||
|
||||
vertex.texCoord.x = ReadBinaryFloat(stream);
|
||||
vertex.texCoord.y = ReadBinaryFloat(stream);
|
||||
|
||||
vertex.texCoord2.x = ReadBinaryFloat(stream);
|
||||
vertex.texCoord2.y = ReadBinaryFloat(stream);
|
||||
|
||||
return vertex;
|
||||
}
|
||||
|
||||
Material ModelInput::ReadBinaryMaterial(std::istream& stream)
|
||||
{
|
||||
Material 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);
|
||||
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;
|
||||
}
|
||||
|
||||
VertexTex2 ModelInput::ParseVertexTex2(const std::string& text)
|
||||
{
|
||||
VertexTex2 vertex;
|
||||
|
||||
std::stringstream stream;
|
||||
stream.str(text);
|
||||
|
||||
std::string prefix;
|
||||
|
||||
stream >> prefix;
|
||||
if (prefix != "c")
|
||||
throw CModelIOException(std::string("Unexpected prefix: '") + prefix + "'");
|
||||
|
||||
stream >> vertex.coord.x >> vertex.coord.y >> vertex.coord.z;
|
||||
|
||||
stream >> prefix;
|
||||
if (prefix != "n")
|
||||
throw CModelIOException(std::string("Unexpected prefix: '") + prefix + "'");
|
||||
|
||||
stream >> vertex.normal.x >> vertex.normal.y >> vertex.normal.z;
|
||||
|
||||
stream >> prefix;
|
||||
if (prefix != "t1")
|
||||
throw CModelIOException(std::string("Unexpected prefix: '") + prefix + "'");
|
||||
|
||||
stream >> vertex.texCoord.x >> vertex.texCoord.y;
|
||||
|
||||
stream >> prefix;
|
||||
if (prefix != "t2")
|
||||
throw CModelIOException(std::string("Unexpected prefix: '") + prefix + "'");
|
||||
|
||||
stream >> vertex.texCoord2.x >> vertex.texCoord2.y;
|
||||
|
||||
return vertex;
|
||||
}
|
||||
|
||||
Material ModelInput::ParseTextMaterial(const std::string& text)
|
||||
{
|
||||
Material material;
|
||||
|
||||
std::stringstream stream;
|
||||
stream.str(text);
|
||||
|
||||
std::string prefix;
|
||||
|
||||
stream >> prefix;
|
||||
if (prefix != "dif")
|
||||
throw CModelIOException(std::string("Unexpected prefix: '") + prefix + "'");
|
||||
|
||||
stream >> material.diffuse.r
|
||||
>> material.diffuse.g
|
||||
>> material.diffuse.b
|
||||
>> material.diffuse.a;
|
||||
|
||||
stream >> prefix;
|
||||
if (prefix != "amb")
|
||||
throw CModelIOException(std::string("Unexpected prefix: '") + prefix + "'");
|
||||
|
||||
stream >> material.ambient.r
|
||||
>> material.ambient.g
|
||||
>> material.ambient.b
|
||||
>> material.ambient.a;
|
||||
|
||||
stream >> prefix;
|
||||
if (prefix != "spc")
|
||||
throw CModelIOException(std::string("Unexpected prefix: '") + prefix + "'");
|
||||
|
||||
stream >> material.specular.r
|
||||
>> material.specular.g
|
||||
>> material.specular.b
|
||||
>> material.specular.a;
|
||||
|
||||
return material;
|
||||
}
|
||||
|
||||
} // namespace Gfx
|
|
@ -0,0 +1,23 @@
|
|||
#pragma once
|
||||
|
||||
#include "graphics/model/model.h"
|
||||
#include "graphics/model/model_format.h"
|
||||
|
||||
#include <istream>
|
||||
|
||||
namespace Gfx {
|
||||
|
||||
/**
|
||||
* \namespace ModelInput
|
||||
* \brief Namespace with functions to read model files
|
||||
*/
|
||||
namespace ModelInput
|
||||
{
|
||||
//! Reads model from \a stream in given \a format
|
||||
/**
|
||||
* @throws CModelIOException on read/write error
|
||||
*/
|
||||
CModel Read(std::istream &stream, ModelFormat format);
|
||||
}
|
||||
|
||||
} // namespace Gfx
|
|
@ -0,0 +1,15 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
namespace Gfx {
|
||||
|
||||
class CModelIOException : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
explicit CModelIOException(const std::string& error)
|
||||
: std::runtime_error(error)
|
||||
{}
|
||||
};
|
||||
|
||||
} // namespace Gfx
|
|
@ -0,0 +1,243 @@
|
|||
#pragma once
|
||||
|
||||
#include "graphics/core/material.h"
|
||||
#include "graphics/model/model_triangle.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace Gfx {
|
||||
|
||||
/*******************************************************
|
||||
Deprecated enums/magic values
|
||||
*******************************************************/
|
||||
|
||||
/**
|
||||
* \enum ModelLODLevel
|
||||
* \brief Old level-of-detail enum
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
enum class ModelLODLevel
|
||||
{
|
||||
Constant = -1, //!< triangle is always visible, no matter at what distance
|
||||
Low = 1, //!< triangle is visible at farthest distance (lowest quality)
|
||||
Medium = 2, //!< triangle is visible at medium distance (medium quality)
|
||||
High = 4 //!< triangle is visible at closest distance (highest quality)
|
||||
};
|
||||
|
||||
/**
|
||||
* \enum ModelRenderState
|
||||
* \brief Old render state enum (values copied from EngineRenderState)
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
enum class ModelRenderState
|
||||
{
|
||||
TTextureBlack = 1, //!< old ENG_RSTATE_TTEXTURE_BLACK
|
||||
TTextureWhite = 2, //!< old ENG_RSTATE_TTEXTURE_WHITE
|
||||
Part1 = 256, //!< old ENG_RSTATE_PART1
|
||||
Part2 = 512, //!< old ENG_RSTATE_PART2
|
||||
Part3 = 1024, //!< old ENG_RSTATE_PART3
|
||||
TwoFace = 4096, //!< old ENG_RSTATE_2FACE
|
||||
Alpha = 8192 //!< old ENG_RSTATE_ALPHA
|
||||
};
|
||||
|
||||
/*******************************************************
|
||||
New model formats
|
||||
*******************************************************/
|
||||
|
||||
/**
|
||||
* \struct ModelHeaderV1AndV2
|
||||
* \brief Header for new model file version 1 and 2
|
||||
*/
|
||||
struct ModelHeaderV1AndV2
|
||||
{
|
||||
//! File version (1, 2, ...)
|
||||
int version = 0;
|
||||
//! Total number of triangles
|
||||
int totalTriangles = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* \struct ModelTriangleV1AndV2
|
||||
* \brief Triangle of new model file version 1 and 2
|
||||
*/
|
||||
struct ModelTriangleV1AndV2
|
||||
{
|
||||
//! 1st vertex
|
||||
VertexTex2 p1;
|
||||
//! 2nd vertex
|
||||
VertexTex2 p2;
|
||||
//! 3rd vertex
|
||||
VertexTex2 p3;
|
||||
//! Material
|
||||
Material material;
|
||||
//! Name of 1st texture
|
||||
std::string tex1Name;
|
||||
//! Name of 2nd texture
|
||||
std::string tex2Name;
|
||||
//! If true, 2nd texture will be taken from current engine setting
|
||||
bool variableTex2 = true;
|
||||
//! LOD level (only version 1)
|
||||
ModelLODLevel lodLevel = ModelLODLevel::Constant;
|
||||
//! Rendering state to be set
|
||||
int state = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* \struct ModelHeaderV3
|
||||
* \brief Header for new model file version 3
|
||||
*/
|
||||
struct ModelHeaderV3
|
||||
{
|
||||
//! File version (1, 2, ...)
|
||||
int version = 0;
|
||||
//! Total number of meshes
|
||||
int totalMeshes = 0;
|
||||
//! Total number of crash spheres
|
||||
int totalCrashSpheres = 0;
|
||||
//! Whether model has shadow spot
|
||||
bool shadowSpot = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* \struct ModelMeshHeaderV3
|
||||
* \brief Header for mesh saved in new model file version 3
|
||||
*/
|
||||
struct ModelMeshHeaderV3
|
||||
{
|
||||
//! Total number of triangles
|
||||
int totalTriangles = 0;
|
||||
//! Mesh name
|
||||
std::string name;
|
||||
//! Parent mesh name
|
||||
std::string parentName;
|
||||
//! Mesh position
|
||||
Math::Vector position;
|
||||
//! Mesh rotation
|
||||
Math::Vector rotation;
|
||||
//! Mesh scale
|
||||
Math::Vector scale;
|
||||
};
|
||||
|
||||
/**
|
||||
* \struct ModelTriangleV3
|
||||
* \brief Mesh triangle saved in new model file version 3
|
||||
*
|
||||
* NOTE: this is newest version, always same as ModelTriangle struct.
|
||||
*/
|
||||
struct ModelTriangleV3 : ModelTriangle {};
|
||||
|
||||
|
||||
|
||||
/*******************************************************
|
||||
Deprecated formats
|
||||
*******************************************************/
|
||||
|
||||
/**
|
||||
* \struct OldModelHeader
|
||||
* \brief Old Colobot binary model header info
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
struct OldModelHeader
|
||||
{
|
||||
//! Revision number
|
||||
int revision;
|
||||
//! Version number
|
||||
int version;
|
||||
//! Total number of triangles
|
||||
int totalTriangles;
|
||||
//! Reserved area
|
||||
int reserved[10];
|
||||
|
||||
OldModelHeader()
|
||||
{
|
||||
memset(this, 0, sizeof(*this));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \struct OldModelTriangleV1
|
||||
* \brief Old Colobot binary model file version 1
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
struct OldModelTriangleV1
|
||||
{
|
||||
char used;
|
||||
char selected;
|
||||
Vertex p1;
|
||||
Vertex p2;
|
||||
Vertex p3;
|
||||
Material material;
|
||||
char texName[20];
|
||||
float min;
|
||||
float max;
|
||||
|
||||
OldModelTriangleV1()
|
||||
{
|
||||
memset(this, 0, sizeof(*this));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* \struct OldModelTriangleV2
|
||||
* \brief Old Colobot binary model file version 2
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
struct OldModelTriangleV2
|
||||
{
|
||||
char used;
|
||||
char selected;
|
||||
Vertex p1;
|
||||
Vertex p2;
|
||||
Vertex p3;
|
||||
Material material;
|
||||
char texName[20];
|
||||
float min;
|
||||
float max;
|
||||
long state;
|
||||
short reserved1;
|
||||
short reserved2;
|
||||
short reserved3;
|
||||
short reserved4;
|
||||
|
||||
OldModelTriangleV2()
|
||||
{
|
||||
memset(this, 0, sizeof(*this));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* \struct OldModelTriangleV3
|
||||
* \brief Old Colobot binary model file version 3
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
struct OldModelTriangleV3
|
||||
{
|
||||
char used;
|
||||
char selected;
|
||||
VertexTex2 p1;
|
||||
VertexTex2 p2;
|
||||
VertexTex2 p3;
|
||||
Material material;
|
||||
char texName[20];
|
||||
float min;
|
||||
float max;
|
||||
long state;
|
||||
short texNum2;
|
||||
short reserved2;
|
||||
short reserved3;
|
||||
short reserved4;
|
||||
|
||||
OldModelTriangleV3()
|
||||
{
|
||||
memset(this, 0, sizeof(*this));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Gfx
|
|
@ -0,0 +1,32 @@
|
|||
#include "graphics/model/model_manager.h"
|
||||
|
||||
#include "common/resources/inputstream.h"
|
||||
|
||||
#include "graphics/model/model_input.h"
|
||||
#include "graphics/model/model_io_exception.h"
|
||||
|
||||
namespace Gfx {
|
||||
|
||||
CModel& CModelManager::GetModel(const std::string& fileName)
|
||||
{
|
||||
auto it = m_models.find(fileName);
|
||||
if (it != m_models.end())
|
||||
return it->second;
|
||||
|
||||
CInputStream stream;
|
||||
stream.open("models-new/" + fileName);
|
||||
if (!stream.is_open())
|
||||
throw CModelIOException(std::string("Could not open file '") + fileName + "'");
|
||||
|
||||
CModel model = ModelInput::Read(stream, ModelFormat::Text);
|
||||
m_models[fileName] = model;
|
||||
|
||||
return m_models[fileName];
|
||||
}
|
||||
|
||||
void CModelManager::ClearCache()
|
||||
{
|
||||
m_models.clear();
|
||||
}
|
||||
|
||||
} // namespace Gfx
|
|
@ -0,0 +1,28 @@
|
|||
#pragma once
|
||||
|
||||
#include "graphics/model/model.h"
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace Gfx {
|
||||
|
||||
/**
|
||||
* \class CModelManager
|
||||
* \brief Manager for models read from model files
|
||||
*/
|
||||
class CModelManager
|
||||
{
|
||||
public:
|
||||
//! Returns a model read from \a fileName
|
||||
/** @throws CModelIOException on read error */
|
||||
CModel& GetModel(const std::string& fileName);
|
||||
|
||||
//! Clears cached models
|
||||
void ClearCache();
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, CModel> m_models;
|
||||
};
|
||||
|
||||
} // namespace Gfx
|
|
@ -0,0 +1,65 @@
|
|||
#include "graphics/model/model_mesh.h"
|
||||
|
||||
namespace Gfx {
|
||||
|
||||
void CModelMesh::AddTriangle(const ModelTriangle& triangle)
|
||||
{
|
||||
m_triangles.push_back(triangle);
|
||||
}
|
||||
|
||||
void CModelMesh::SetTriangles(std::vector<ModelTriangle>&& triangles)
|
||||
{
|
||||
m_triangles = triangles;
|
||||
}
|
||||
|
||||
const std::vector<ModelTriangle>& CModelMesh::GetTriangles() const
|
||||
{
|
||||
return m_triangles;
|
||||
}
|
||||
|
||||
int CModelMesh::GetTriangleCount() const
|
||||
{
|
||||
return m_triangles.size();
|
||||
}
|
||||
|
||||
const Math::Vector& CModelMesh::GetPosition() const
|
||||
{
|
||||
return m_position;
|
||||
}
|
||||
|
||||
void CModelMesh::SetPosition(const Math::Vector& position)
|
||||
{
|
||||
m_position = position;
|
||||
}
|
||||
|
||||
const Math::Vector& CModelMesh::GetRotation() const
|
||||
{
|
||||
return m_rotation;
|
||||
}
|
||||
|
||||
void CModelMesh::SetRotation(const Math::Vector& rotation)
|
||||
{
|
||||
m_rotation = rotation;
|
||||
}
|
||||
|
||||
const Math::Vector& CModelMesh::GetScale() const
|
||||
{
|
||||
return m_scale;
|
||||
}
|
||||
|
||||
void CModelMesh::SetScale(const Math::Vector& scale)
|
||||
{
|
||||
m_scale = scale;
|
||||
}
|
||||
|
||||
const std::string& CModelMesh::GetParent() const
|
||||
{
|
||||
return m_parent;
|
||||
}
|
||||
|
||||
void CModelMesh::SetParent(const std::string& parent)
|
||||
{
|
||||
m_parent = parent;
|
||||
}
|
||||
|
||||
} // namespace Gfx
|
|
@ -0,0 +1,57 @@
|
|||
#pragma once
|
||||
|
||||
#include "math/vector.h"
|
||||
|
||||
#include "graphics/model/model_triangle.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace Gfx {
|
||||
|
||||
struct ModelTriangle;
|
||||
|
||||
/**
|
||||
* \class CModelMesh
|
||||
* \brief Mesh data saved in model file
|
||||
*/
|
||||
class CModelMesh
|
||||
{
|
||||
public:
|
||||
//! Adds a new triangle
|
||||
void AddTriangle(const ModelTriangle& triangle);
|
||||
//! Sets the list of triangles
|
||||
void SetTriangles(std::vector<ModelTriangle> &&triangles);
|
||||
//! Returns the list of triangles
|
||||
const std::vector<ModelTriangle>& GetTriangles() const;
|
||||
//! Returns number of triangles
|
||||
int GetTriangleCount() const;
|
||||
|
||||
//! Returns the mesh position
|
||||
const Math::Vector& GetPosition() const;
|
||||
//! Sets the mesh rotation
|
||||
void SetPosition(const Math::Vector& position);
|
||||
|
||||
//! Returns the mesh rotation
|
||||
const Math::Vector& GetRotation() const;
|
||||
//! Sets the mesh rotation
|
||||
void SetRotation(const Math::Vector& rotation);
|
||||
|
||||
//! Returns the mesh scale
|
||||
const Math::Vector& GetScale() const;
|
||||
//! Sets the mesh scale
|
||||
void SetScale(const Math::Vector& scale);
|
||||
|
||||
//! Returns the name of parent mesh
|
||||
const std::string& GetParent() const;
|
||||
//! Sets the name of parent mesh
|
||||
void SetParent(const std::string& parent);
|
||||
|
||||
private:
|
||||
std::vector<ModelTriangle> m_triangles;
|
||||
Math::Vector m_position;
|
||||
Math::Vector m_rotation;
|
||||
Math::Vector m_scale;
|
||||
std::string m_parent;
|
||||
};
|
||||
|
||||
} // namespace Gfx
|
|
@ -0,0 +1,338 @@
|
|||
#include "graphics/model/model_output.h"
|
||||
|
||||
#include "common/ioutils.h"
|
||||
|
||||
#include "graphics/model/model_io_exception.h"
|
||||
#include "graphics/model/model_io_structs.h"
|
||||
|
||||
#include "graphics/model/model.h"
|
||||
|
||||
#include <fstream>
|
||||
|
||||
namespace Gfx {
|
||||
|
||||
// Private functions
|
||||
namespace ModelOutput
|
||||
{
|
||||
void WriteTextModel(const CModel& model, std::ostream &stream);
|
||||
|
||||
void WriteBinaryModel(const CModel& model, std::ostream &stream);
|
||||
|
||||
void WriteOldModel(const CModel& model, std::ostream &stream);
|
||||
|
||||
int ConvertToOldState(const ModelTriangle& triangle);
|
||||
|
||||
void WriteBinaryVertexTex2(VertexTex2 vertex, std::ostream &stream);
|
||||
void WriteBinaryMaterial(const Material& material, std::ostream &stream);
|
||||
|
||||
void WriteTextVertexTex2(const VertexTex2& vertex, std::ostream &stream);
|
||||
void WriteTextMaterial(const Material& material, std::ostream &stream);
|
||||
}
|
||||
|
||||
using namespace IOUtils;
|
||||
|
||||
void ModelOutput::Write(const CModel& model, std::ostream &stream, ModelFormat format)
|
||||
{
|
||||
stream.exceptions(std::ios_base::failbit | std::ios_base::badbit);
|
||||
|
||||
try
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case ModelFormat::Text:
|
||||
WriteTextModel(model, stream);
|
||||
break;
|
||||
|
||||
case ModelFormat::Binary:
|
||||
WriteBinaryModel(model, stream);
|
||||
break;
|
||||
|
||||
case ModelFormat::Old:
|
||||
WriteOldModel(model, stream);
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (const CModelIOException& e)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
throw CModelIOException(std::string("Error saving model data: ") + e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void ModelOutput::WriteTextModel(const CModel& model, std::ostream &stream)
|
||||
{
|
||||
const CModelMesh* mesh = model.GetMesh("main");
|
||||
if (mesh == nullptr)
|
||||
throw CModelIOException("No main mesh found in model");
|
||||
|
||||
ModelHeaderV1AndV2 header;
|
||||
|
||||
header.version = 2;
|
||||
header.totalTriangles = mesh->GetTriangleCount();
|
||||
|
||||
stream << "# Colobot text model" << std::endl;
|
||||
stream << std::endl;
|
||||
stream << "### HEAD" << std::endl;
|
||||
stream << "version " << header.version << std::endl;
|
||||
stream << "total_triangles " << header.totalTriangles << std::endl;
|
||||
stream << std::endl;
|
||||
stream << "### TRIANGLES" << std::endl;
|
||||
|
||||
for (const ModelTriangle& triangle : mesh->GetTriangles())
|
||||
{
|
||||
ModelTriangleV1AndV2 t;
|
||||
|
||||
t.p1 = triangle.p1;
|
||||
t.p2 = triangle.p2;
|
||||
t.p3 = triangle.p3;
|
||||
t.material.ambient = triangle.ambient;
|
||||
t.material.diffuse = triangle.diffuse;
|
||||
t.material.specular = triangle.specular;
|
||||
t.tex1Name = triangle.tex1Name;
|
||||
t.tex2Name = triangle.tex2Name;
|
||||
t.variableTex2 = triangle.variableTex2;
|
||||
t.state = ConvertToOldState(triangle);
|
||||
|
||||
stream << "p1 ";
|
||||
WriteTextVertexTex2(t.p1, stream);
|
||||
stream << "p2 ";
|
||||
WriteTextVertexTex2(t.p2, stream);
|
||||
stream << "p3 ";
|
||||
WriteTextVertexTex2(t.p3, stream);
|
||||
stream << "mat ";
|
||||
WriteTextMaterial(t.material, stream);
|
||||
|
||||
stream << "tex1 " << t.tex1Name << std::endl;
|
||||
stream << "tex2 " << t.tex2Name << std::endl;
|
||||
stream << "var_tex2 " << (t.variableTex2 ? 'Y' : 'N') << std::endl;
|
||||
stream << "state " << t.state << std::endl;
|
||||
|
||||
stream << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void ModelOutput::WriteBinaryModel(const CModel& model, std::ostream &stream)
|
||||
{
|
||||
const CModelMesh* mesh = model.GetMesh("main");
|
||||
if (mesh == nullptr)
|
||||
throw CModelIOException("No main mesh found in model");
|
||||
|
||||
ModelHeaderV1AndV2 header;
|
||||
|
||||
header.version = 2;
|
||||
header.totalTriangles = mesh->GetTriangleCount();
|
||||
|
||||
WriteBinary<4, int>(header.version, stream);
|
||||
WriteBinary<4, int>(header.totalTriangles, stream);
|
||||
|
||||
for (const ModelTriangle& triangle : mesh->GetTriangles())
|
||||
{
|
||||
ModelTriangleV1AndV2 t;
|
||||
|
||||
t.p1 = triangle.p1;
|
||||
t.p2 = triangle.p2;
|
||||
t.p3 = triangle.p3;
|
||||
t.material.ambient = triangle.ambient;
|
||||
t.material.diffuse = triangle.diffuse;
|
||||
t.material.specular = triangle.specular;
|
||||
t.tex1Name = triangle.tex1Name;
|
||||
t.tex2Name = triangle.tex2Name;
|
||||
t.variableTex2 = triangle.variableTex2;
|
||||
t.state = ConvertToOldState(triangle);
|
||||
|
||||
WriteBinaryVertexTex2(t.p1, stream);
|
||||
WriteBinaryVertexTex2(t.p2, stream);
|
||||
WriteBinaryVertexTex2(t.p3, stream);
|
||||
WriteBinaryMaterial(t.material, stream);
|
||||
WriteBinaryString<1>(t.tex1Name, stream);
|
||||
WriteBinaryString<1>(t.tex2Name, stream);
|
||||
WriteBinaryBool(t.variableTex2, stream);
|
||||
WriteBinary<4, int>(t.state, stream);
|
||||
}
|
||||
}
|
||||
|
||||
void ModelOutput::WriteOldModel(const CModel& model, std::ostream &stream)
|
||||
{
|
||||
const CModelMesh* mesh = model.GetMesh("main");
|
||||
if (mesh == nullptr)
|
||||
throw CModelIOException("No main mesh found in model");
|
||||
|
||||
OldModelHeader header;
|
||||
header.revision = 1;
|
||||
header.version = 2;
|
||||
header.totalTriangles = mesh->GetTriangleCount();
|
||||
|
||||
WriteBinary<4, int>(header.revision, stream);
|
||||
WriteBinary<4, int>(header.version, stream);
|
||||
WriteBinary<4, int>(header.totalTriangles, stream);
|
||||
for (int i = 0; i < 10; ++i)
|
||||
WriteBinary<4, int>(header.reserved[i], stream);
|
||||
|
||||
for (const ModelTriangle& triangle : mesh->GetTriangles())
|
||||
{
|
||||
OldModelTriangleV3 t;
|
||||
|
||||
t.used = true;
|
||||
|
||||
t.p1 = triangle.p1;
|
||||
t.p2 = triangle.p2;
|
||||
t.p3 = triangle.p3;
|
||||
|
||||
t.material.ambient = triangle.ambient;
|
||||
t.material.diffuse = triangle.diffuse;
|
||||
t.material.specular = triangle.specular;
|
||||
strncpy(t.texName, triangle.tex1Name.c_str(), 20);
|
||||
t.min = 0.0f;
|
||||
t.max = 1000000.0f;
|
||||
t.state = ConvertToOldState(triangle);
|
||||
|
||||
int no = 0;
|
||||
if (triangle.variableTex2)
|
||||
no = 1;
|
||||
else
|
||||
std::sscanf(triangle.tex2Name.c_str(), "dirty%d.png", &no);
|
||||
|
||||
t.texNum2 = no;
|
||||
|
||||
|
||||
WriteBinary<1, char>(t.used, stream);
|
||||
WriteBinary<1, char>(t.selected, stream);
|
||||
|
||||
/* padding */ WriteBinary<2, unsigned int>(0, stream);
|
||||
|
||||
WriteBinaryVertexTex2(t.p1, stream);
|
||||
WriteBinaryVertexTex2(t.p2, stream);
|
||||
WriteBinaryVertexTex2(t.p3, stream);
|
||||
|
||||
WriteBinaryMaterial(t.material, stream);
|
||||
stream.write(t.texName, 20);
|
||||
WriteBinaryFloat(t.min, stream);
|
||||
WriteBinaryFloat(t.max, stream);
|
||||
WriteBinary<4, long>(t.state, stream);
|
||||
WriteBinary<2, short>(t.texNum2, stream);
|
||||
|
||||
WriteBinary<2, short>(t.reserved2, stream);
|
||||
WriteBinary<2, short>(t.reserved3, stream);
|
||||
WriteBinary<2, short>(t.reserved4, stream);
|
||||
}
|
||||
}
|
||||
|
||||
int ModelOutput::ConvertToOldState(const ModelTriangle& triangle)
|
||||
{
|
||||
int state = 0;
|
||||
|
||||
switch (triangle.transparentMode)
|
||||
{
|
||||
case ModelTransparentMode::None:
|
||||
break;
|
||||
|
||||
case ModelTransparentMode::AlphaChannel:
|
||||
state |= static_cast<int>(ModelRenderState::Alpha);
|
||||
break;
|
||||
|
||||
case ModelTransparentMode::MapBlackToAlpha:
|
||||
state |= static_cast<int>(ModelRenderState::TTextureBlack);
|
||||
break;
|
||||
|
||||
case ModelTransparentMode::MapWhiteToAlpha:
|
||||
state |= static_cast<int>(ModelRenderState::TTextureWhite);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (triangle.specialMark)
|
||||
{
|
||||
case ModelSpecialMark::None:
|
||||
break;
|
||||
|
||||
case ModelSpecialMark::Part1:
|
||||
state |= static_cast<int>(ModelRenderState::Part1);
|
||||
break;
|
||||
|
||||
case ModelSpecialMark::Part2:
|
||||
state |= static_cast<int>(ModelRenderState::Part2);
|
||||
break;
|
||||
|
||||
case ModelSpecialMark::Part3:
|
||||
state |= static_cast<int>(ModelRenderState::Part3);
|
||||
break;
|
||||
}
|
||||
|
||||
if (triangle.doubleSided)
|
||||
state |= static_cast<int>(ModelRenderState::TwoFace);
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
void ModelOutput::WriteBinaryVertexTex2(VertexTex2 vertex, std::ostream &stream)
|
||||
{
|
||||
WriteBinaryFloat(vertex.coord.x, stream);
|
||||
WriteBinaryFloat(vertex.coord.y, stream);
|
||||
WriteBinaryFloat(vertex.coord.z, stream);
|
||||
WriteBinaryFloat(vertex.normal.x, stream);
|
||||
WriteBinaryFloat(vertex.normal.y, stream);
|
||||
WriteBinaryFloat(vertex.normal.z, stream);
|
||||
WriteBinaryFloat(vertex.texCoord.x, stream);
|
||||
WriteBinaryFloat(vertex.texCoord.y, stream);
|
||||
WriteBinaryFloat(vertex.texCoord2.x, stream);
|
||||
WriteBinaryFloat(vertex.texCoord2.y, stream);
|
||||
}
|
||||
|
||||
void ModelOutput::WriteBinaryMaterial(const Material& material, std::ostream &stream)
|
||||
{
|
||||
WriteBinaryFloat(material.diffuse.r, stream);
|
||||
WriteBinaryFloat(material.diffuse.g, stream);
|
||||
WriteBinaryFloat(material.diffuse.b, stream);
|
||||
WriteBinaryFloat(material.diffuse.a, stream);
|
||||
|
||||
WriteBinaryFloat(material.ambient.r, stream);
|
||||
WriteBinaryFloat(material.ambient.g, stream);
|
||||
WriteBinaryFloat(material.ambient.b, stream);
|
||||
WriteBinaryFloat(material.ambient.a, stream);
|
||||
|
||||
WriteBinaryFloat(material.specular.r, stream);
|
||||
WriteBinaryFloat(material.specular.g, stream);
|
||||
WriteBinaryFloat(material.specular.b, stream);
|
||||
WriteBinaryFloat(material.specular.a, stream);
|
||||
|
||||
/* emissive.r */ WriteBinaryFloat(0.0f, stream);
|
||||
/* emissive.g */ WriteBinaryFloat(0.0f, stream);
|
||||
/* emissive.b */ WriteBinaryFloat(0.0f, stream);
|
||||
/* emissive.a */ WriteBinaryFloat(0.0f, stream);
|
||||
|
||||
/* power */ WriteBinaryFloat(0.0f, stream);
|
||||
}
|
||||
|
||||
void ModelOutput::WriteTextVertexTex2(const VertexTex2& vertex, std::ostream &stream)
|
||||
{
|
||||
stream << "c " << vertex.coord.x << " " << vertex.coord.y << " " << vertex.coord.z;
|
||||
stream << " n " << vertex.normal.x << " " << vertex.normal.y << " " << vertex.normal.z;
|
||||
stream << " t1 " << vertex.texCoord.x << " " << vertex.texCoord.y;
|
||||
stream << " t2 " << vertex.texCoord2.x << " " << vertex.texCoord2.y;
|
||||
stream << std::endl;
|
||||
}
|
||||
|
||||
void ModelOutput::WriteTextMaterial(const Material& material, std::ostream &stream)
|
||||
{
|
||||
stream << "dif " << material.diffuse.r
|
||||
<< " " << material.diffuse.g
|
||||
<< " " << material.diffuse.b
|
||||
<< " " << material.diffuse.a;
|
||||
|
||||
stream << " amb " << material.ambient.r
|
||||
<< " " << material.ambient.g
|
||||
<< " " << material.ambient.b
|
||||
<< " " << material.ambient.a;
|
||||
|
||||
stream << " spc " << material.specular.r
|
||||
<< " " << material.specular.g << " "
|
||||
<< material.specular.b << " "
|
||||
<< material.specular.a;
|
||||
|
||||
stream << std::endl;
|
||||
}
|
||||
|
||||
|
||||
} // namespace Gfx
|
|
@ -0,0 +1,21 @@
|
|||
#pragma once
|
||||
|
||||
#include "graphics/model/model_format.h"
|
||||
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
|
||||
namespace Gfx {
|
||||
|
||||
class CModel;
|
||||
|
||||
namespace ModelOutput
|
||||
{
|
||||
//! Writes the given \a model to \a stream using \a format
|
||||
/**
|
||||
* @throws CModelIOException on read/write error
|
||||
*/
|
||||
void Write(const CModel& model, std::ostream& stream, ModelFormat format);
|
||||
}
|
||||
|
||||
} // namespace Gfx
|
|
@ -0,0 +1,15 @@
|
|||
#pragma once
|
||||
|
||||
namespace Gfx {
|
||||
|
||||
/**
|
||||
* \struct ModelShadowSpot
|
||||
* \brief Shadow spot data as saved in model file
|
||||
*/
|
||||
struct ModelShadowSpot
|
||||
{
|
||||
float radius = 0.0f;
|
||||
float intensity = 0.0f;
|
||||
};
|
||||
|
||||
} // namespace Gfx
|
|
@ -0,0 +1,68 @@
|
|||
#pragma once
|
||||
|
||||
#include "graphics/core/color.h"
|
||||
#include "graphics/core/vertex.h"
|
||||
|
||||
namespace Gfx {
|
||||
|
||||
/**
|
||||
* \enum ModelSpecialMark
|
||||
* \brief Special marking for some models
|
||||
*
|
||||
* TODO: refactor/remove in the future
|
||||
*/
|
||||
enum class ModelSpecialMark
|
||||
{
|
||||
None,
|
||||
Part1,
|
||||
Part2,
|
||||
Part3
|
||||
};
|
||||
|
||||
/**
|
||||
* \enum ModelTransparentMode
|
||||
* \brief Describes how to deal with texture transparency
|
||||
*
|
||||
* TODO: get rid of it in the future (use only alpha channel)
|
||||
*/
|
||||
enum class ModelTransparentMode
|
||||
{
|
||||
None, //!< no transparency
|
||||
AlphaChannel, //!< use alpha channel
|
||||
MapBlackToAlpha, //!< map black color to alpha
|
||||
MapWhiteToAlpha //!< map white color to alpha
|
||||
};
|
||||
|
||||
/**
|
||||
* \struct ModelTriangle
|
||||
* \brief A single triangle in mesh as saved in model file
|
||||
*/
|
||||
struct ModelTriangle
|
||||
{
|
||||
//! 1st vertex
|
||||
VertexTex2 p1;
|
||||
//! 2nd vertex
|
||||
VertexTex2 p2;
|
||||
//! 3rd vertex
|
||||
VertexTex2 p3;
|
||||
//! Diffuse color
|
||||
Color diffuse;
|
||||
//! Ambient color
|
||||
Color ambient;
|
||||
//! Specular color
|
||||
Color specular;
|
||||
//! Name of 1st texture
|
||||
std::string tex1Name;
|
||||
//! Name of 2nd texture
|
||||
std::string tex2Name;
|
||||
//! If true, 2nd texture will be taken from current engine setting
|
||||
bool variableTex2 = false;
|
||||
//! Whether to render as double-sided surface
|
||||
bool doubleSided = false;
|
||||
//! How to deal with texture transparency
|
||||
ModelTransparentMode transparentMode = ModelTransparentMode::None;
|
||||
//! Special marking
|
||||
ModelSpecialMark specialMark = ModelSpecialMark::None;
|
||||
};
|
||||
|
||||
} // namespace Gfx
|
|
@ -412,11 +412,11 @@ void CAutoPortico::UpdateTrackMapping(float left, float right)
|
|||
rank = m_object->GetObjectRank(0);
|
||||
|
||||
m_engine->TrackTextureMapping(rank, mat, Gfx::ENG_RSTATE_PART1, "objects/lemt.png", "",
|
||||
Gfx::LOD_Constant, Gfx::ENG_TEX_MAPPING_X,
|
||||
Gfx::ENG_TEX_MAPPING_X,
|
||||
right, 8.0f, 8.0f, 192.0f, 256.0f);
|
||||
|
||||
m_engine->TrackTextureMapping(rank, mat, Gfx::ENG_RSTATE_PART2, "objects/lemt.png", "",
|
||||
Gfx::LOD_Constant, Gfx::ENG_TEX_MAPPING_X,
|
||||
Gfx::ENG_TEX_MAPPING_X,
|
||||
left, 8.0f, 8.0f, 192.0f, 256.0f);
|
||||
}
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ public:
|
|||
void SetBrain(CBrain* brain);
|
||||
|
||||
virtual void DeleteObject(bool bAll=false) = 0;
|
||||
virtual void Create(Math::Vector pos, float angle, ObjectType type, float power, Gfx::CModelManager* modelManager) = 0;
|
||||
virtual void Create(Math::Vector pos, float angle, ObjectType type, float power, Gfx::COldModelManager* modelManager) = 0;
|
||||
virtual bool EventProcess(const Event &event);
|
||||
virtual Error SetAction(int action, float time=0.2f);
|
||||
virtual int GetAction();
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
#include "app/app.h"
|
||||
|
||||
#include "graphics/engine/modelmanager.h"
|
||||
#include "graphics/engine/oldmodelmanager.h"
|
||||
#include "graphics/engine/particle.h"
|
||||
|
||||
#include "physics/physics.h"
|
||||
|
@ -69,7 +69,7 @@ void CMotionAnt::DeleteObject(bool bAll)
|
|||
// Creates a vehicle poses some rolling on the floor.
|
||||
|
||||
void CMotionAnt::Create(Math::Vector pos, float angle, ObjectType type,
|
||||
float power, Gfx::CModelManager* modelManager)
|
||||
float power, Gfx::COldModelManager* modelManager)
|
||||
{
|
||||
int rank;
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ public:
|
|||
~CMotionAnt();
|
||||
|
||||
void DeleteObject(bool bAll=false);
|
||||
void Create(Math::Vector pos, float angle, ObjectType type, float power, Gfx::CModelManager* modelManager);
|
||||
void Create(Math::Vector pos, float angle, ObjectType type, float power, Gfx::COldModelManager* modelManager);
|
||||
bool EventProcess(const Event &event);
|
||||
|
||||
protected:
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
#include "app/app.h"
|
||||
|
||||
#include "graphics/engine/modelmanager.h"
|
||||
#include "graphics/engine/oldmodelmanager.h"
|
||||
|
||||
#include "physics/physics.h"
|
||||
|
||||
|
@ -67,7 +67,7 @@ void CMotionBee::DeleteObject(bool bAll)
|
|||
// Creates a vehicle traveling any lands on the ground.
|
||||
|
||||
void CMotionBee::Create(Math::Vector pos, float angle, ObjectType type,
|
||||
float power, Gfx::CModelManager* modelManager)
|
||||
float power, Gfx::COldModelManager* modelManager)
|
||||
{
|
||||
int rank;
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ public:
|
|||
~CMotionBee();
|
||||
|
||||
void DeleteObject(bool bAll=false);
|
||||
void Create(Math::Vector pos, float angle, ObjectType type, float power, Gfx::CModelManager* modelManager);
|
||||
void Create(Math::Vector pos, float angle, ObjectType type, float power, Gfx::COldModelManager* modelManager);
|
||||
bool EventProcess(const Event &event);
|
||||
|
||||
protected:
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
#include "object/motion/motiondummy.h"
|
||||
#include "physics/physics.h"
|
||||
#include "graphics/engine/modelmanager.h"
|
||||
#include "graphics/engine/oldmodelmanager.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
@ -48,7 +48,7 @@ void CMotionDummy::DeleteObject(bool bAll)
|
|||
// Creates a Dummy traveling any lands on the ground.
|
||||
|
||||
void CMotionDummy::Create(Math::Vector pos, float angle, ObjectType type,
|
||||
float power, Gfx::CModelManager*)
|
||||
float power, Gfx::COldModelManager*)
|
||||
{
|
||||
m_object->SetType(type);
|
||||
|
||||
|
|
|
@ -31,6 +31,6 @@ public:
|
|||
~CMotionDummy();
|
||||
|
||||
void DeleteObject(bool bAll=false);
|
||||
void Create(Math::Vector pos, float angle, ObjectType type, float power, Gfx::CModelManager* modelManager);
|
||||
void Create(Math::Vector pos, float angle, ObjectType type, float power, Gfx::COldModelManager* modelManager);
|
||||
};
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
#include "app/app.h"
|
||||
|
||||
#include "graphics/engine/modelmanager.h"
|
||||
#include "graphics/engine/oldmodelmanager.h"
|
||||
#include "graphics/engine/terrain.h"
|
||||
#include "graphics/engine/water.h"
|
||||
|
||||
|
@ -97,7 +97,7 @@ Error CMotionHuman::SetAction(int action, float time)
|
|||
// Creates cosmonaut on the ground.
|
||||
|
||||
void CMotionHuman::Create(Math::Vector pos, float angle, ObjectType type,
|
||||
float power, Gfx::CModelManager* modelManager)
|
||||
float power, Gfx::COldModelManager* modelManager)
|
||||
{
|
||||
char filename[100];
|
||||
int rank, option, face, glasses;
|
||||
|
|
|
@ -65,7 +65,7 @@ public:
|
|||
~CMotionHuman();
|
||||
|
||||
void DeleteObject(bool bAll=false);
|
||||
void Create(Math::Vector pos, float angle, ObjectType type, float power, Gfx::CModelManager* modelManager);
|
||||
void Create(Math::Vector pos, float angle, ObjectType type, float power, Gfx::COldModelManager* modelManager);
|
||||
bool EventProcess(const Event &event);
|
||||
Error SetAction(int action, float time=0.2f);
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
#include "app/app.h"
|
||||
|
||||
#include "graphics/engine/modelmanager.h"
|
||||
#include "graphics/engine/oldmodelmanager.h"
|
||||
|
||||
#include "physics/physics.h"
|
||||
|
||||
|
@ -68,7 +68,7 @@ void CMotionMother::DeleteObject(bool bAll)
|
|||
// Creates a vehicle traveling any lands on the ground.
|
||||
|
||||
void CMotionMother::Create(Math::Vector pos, float angle, ObjectType type,
|
||||
float power, Gfx::CModelManager* modelManager)
|
||||
float power, Gfx::COldModelManager* modelManager)
|
||||
{
|
||||
int rank;
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ public:
|
|||
~CMotionMother();
|
||||
|
||||
void DeleteObject(bool bAll=false);
|
||||
void Create(Math::Vector pos, float angle, ObjectType type, float power, Gfx::CModelManager* modelManager);
|
||||
void Create(Math::Vector pos, float angle, ObjectType type, float power, Gfx::COldModelManager* modelManager);
|
||||
bool EventProcess(const Event &event);
|
||||
|
||||
protected:
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
#include "app/app.h"
|
||||
|
||||
#include "graphics/engine/modelmanager.h"
|
||||
#include "graphics/engine/oldmodelmanager.h"
|
||||
#include "graphics/engine/particle.h"
|
||||
|
||||
#include "physics/physics.h"
|
||||
|
@ -69,7 +69,7 @@ void CMotionSpider::DeleteObject(bool bAll)
|
|||
// Creates a vehicle traveling any lands on the ground.
|
||||
|
||||
void CMotionSpider::Create(Math::Vector pos, float angle, ObjectType type,
|
||||
float power, Gfx::CModelManager* modelManager)
|
||||
float power, Gfx::COldModelManager* modelManager)
|
||||
{
|
||||
int rank, i, j, parent;
|
||||
char name[50];
|
||||
|
|
|
@ -51,7 +51,7 @@ public:
|
|||
~CMotionSpider();
|
||||
|
||||
void DeleteObject(bool bAll=false);
|
||||
void Create(Math::Vector pos, float angle, ObjectType type, float power, Gfx::CModelManager* modelManager);
|
||||
void Create(Math::Vector pos, float angle, ObjectType type, float power, Gfx::COldModelManager* modelManager);
|
||||
bool EventProcess(const Event &event);
|
||||
|
||||
protected:
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
#include "math/geometry.h"
|
||||
|
||||
#include "graphics/engine/modelmanager.h"
|
||||
#include "graphics/engine/oldmodelmanager.h"
|
||||
#include "graphics/engine/terrain.h"
|
||||
#include "graphics/engine/water.h"
|
||||
|
||||
|
@ -79,7 +79,7 @@ void CMotionToto::DeleteObject(bool bAll)
|
|||
// Creates a vehicle traveling any lands on the ground.
|
||||
|
||||
void CMotionToto::Create(Math::Vector pos, float angle, ObjectType type,
|
||||
float power, Gfx::CModelManager* modelManager)
|
||||
float power, Gfx::COldModelManager* modelManager)
|
||||
{
|
||||
int rank;
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ public:
|
|||
~CMotionToto();
|
||||
|
||||
void DeleteObject(bool bAll=false);
|
||||
void Create(Math::Vector pos, float angle, ObjectType type, float power, Gfx::CModelManager* modelManager);
|
||||
void Create(Math::Vector pos, float angle, ObjectType type, float power, Gfx::COldModelManager* modelManager);
|
||||
bool EventProcess(const Event &event);
|
||||
Error SetAction(int action, float time=0.2f);
|
||||
void SetLinkType(ObjectType type);
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
#include "app/app.h"
|
||||
|
||||
#include "graphics/engine/modelmanager.h"
|
||||
#include "graphics/engine/oldmodelmanager.h"
|
||||
#include "graphics/engine/particle.h"
|
||||
#include "graphics/engine/terrain.h"
|
||||
|
||||
|
@ -93,7 +93,7 @@ void CMotionVehicle::DeleteObject(bool bAll)
|
|||
// Creates a vehicle traveling any lands on the ground.
|
||||
|
||||
void CMotionVehicle::Create(Math::Vector pos, float angle, ObjectType type,
|
||||
float power, Gfx::CModelManager* modelManager)
|
||||
float power, Gfx::COldModelManager* modelManager)
|
||||
{
|
||||
int rank, i, j, parent;
|
||||
Gfx::Color color;
|
||||
|
@ -1881,25 +1881,22 @@ void CMotionVehicle::UpdateTrackMapping(float left, float right, ObjectType type
|
|||
if (type == OBJECT_MOBILEdr)
|
||||
{
|
||||
m_engine->TrackTextureMapping(rRank, mat, Gfx::ENG_RSTATE_PART1, "objects/drawer.png", "",
|
||||
Gfx::LOD_Constant, Gfx::ENG_TEX_MAPPING_X,
|
||||
Gfx::ENG_TEX_MAPPING_X,
|
||||
right, 1.0f, 8.0f, 192.0f, 256.0f);
|
||||
|
||||
m_engine->TrackTextureMapping(lRank, mat, Gfx::ENG_RSTATE_PART2, "objects/drawer.png", "",
|
||||
Gfx::LOD_Constant, Gfx::ENG_TEX_MAPPING_X,
|
||||
Gfx::ENG_TEX_MAPPING_X,
|
||||
left, 1.0f, 8.0f, 192.0f, 256.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
m_engine->TrackTextureMapping(rRank, mat, Gfx::ENG_RSTATE_PART1, "objects/lemt.png", "",
|
||||
(i == 0) ? Gfx::LOD_High : Gfx::LOD_Medium, Gfx::ENG_TEX_MAPPING_X,
|
||||
right, 1.0f, 8.0f, 192.0f, 256.0f);
|
||||
Gfx::ENG_TEX_MAPPING_X,
|
||||
right, 1.0f, 8.0f, 192.0f, 256.0f);
|
||||
|
||||
m_engine->TrackTextureMapping(lRank, mat, Gfx::ENG_RSTATE_PART2, "objects/lemt.png", "",
|
||||
(i == 0) ? Gfx::LOD_High : Gfx::LOD_Medium, Gfx::ENG_TEX_MAPPING_X,
|
||||
left, 1.0f, 8.0f, 192.0f, 256.0f);
|
||||
}
|
||||
m_engine->TrackTextureMapping(lRank, mat, Gfx::ENG_RSTATE_PART2, "lemt.png", "",
|
||||
Gfx::ENG_TEX_MAPPING_X,
|
||||
left, 1.0f, 8.0f, 192.0f, 256.0f);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ public:
|
|||
~CMotionVehicle();
|
||||
|
||||
void DeleteObject(bool bAll=false);
|
||||
void Create(Math::Vector pos, float angle, ObjectType type, float power, Gfx::CModelManager* modelManager);
|
||||
void Create(Math::Vector pos, float angle, ObjectType type, float power, Gfx::COldModelManager* modelManager);
|
||||
bool EventProcess(const Event &event);
|
||||
|
||||
bool GetTraceDown();
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
#include "app/app.h"
|
||||
|
||||
#include "graphics/engine/modelmanager.h"
|
||||
#include "graphics/engine/oldmodelmanager.h"
|
||||
#include "graphics/engine/particle.h"
|
||||
#include "graphics/engine/terrain.h"
|
||||
|
||||
|
@ -81,7 +81,7 @@ void CMotionWorm::DeleteObject(bool bAll)
|
|||
// Creates a vehicle traveling any lands on the ground.
|
||||
|
||||
void CMotionWorm::Create(Math::Vector pos, float angle, ObjectType type,
|
||||
float power, Gfx::CModelManager* modelManager)
|
||||
float power, Gfx::COldModelManager* modelManager)
|
||||
{
|
||||
int rank, i;
|
||||
float px;
|
||||
|
|
|
@ -33,7 +33,7 @@ public:
|
|||
~CMotionWorm();
|
||||
|
||||
void DeleteObject(bool bAll=false);
|
||||
void Create(Math::Vector pos, float angle, ObjectType type, float power, Gfx::CModelManager* modelManager);
|
||||
void Create(Math::Vector pos, float angle, ObjectType type, float power, Gfx::COldModelManager* modelManager);
|
||||
bool EventProcess(const Event &event);
|
||||
|
||||
bool SetParam(int rank, float value);
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#include "object/object_factory.h"
|
||||
|
||||
#include "graphics/engine/engine.h"
|
||||
#include "graphics/engine/modelmanager.h"
|
||||
#include "graphics/engine/oldmodelmanager.h"
|
||||
#include "graphics/engine/terrain.h"
|
||||
#include "graphics/engine/lightning.h"
|
||||
|
||||
|
@ -71,7 +71,7 @@ using COldObjectUPtr = std::unique_ptr<COldObject>;
|
|||
|
||||
CObjectFactory::CObjectFactory(Gfx::CEngine* engine,
|
||||
Gfx::CTerrain* terrain,
|
||||
Gfx::CModelManager* modelManager,
|
||||
Gfx::COldModelManager* modelManager,
|
||||
Gfx::CParticle* particle,
|
||||
CRobotMain* main)
|
||||
: m_engine(engine)
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
|
||||
namespace Gfx {
|
||||
class CEngine;
|
||||
class CModelManager;
|
||||
class COldModelManager;
|
||||
class CParticle;
|
||||
class CTerrain;
|
||||
} // namespace Gfx
|
||||
|
@ -49,7 +49,7 @@ class CObjectFactory
|
|||
public:
|
||||
CObjectFactory(Gfx::CEngine* engine,
|
||||
Gfx::CTerrain* terrain,
|
||||
Gfx::CModelManager* modelManager,
|
||||
Gfx::COldModelManager* modelManager,
|
||||
Gfx::CParticle* particle,
|
||||
CRobotMain* main);
|
||||
|
||||
|
@ -75,7 +75,7 @@ private:
|
|||
private:
|
||||
Gfx::CEngine* m_engine;
|
||||
Gfx::CTerrain* m_terrain;
|
||||
Gfx::CModelManager* m_modelManager;
|
||||
Gfx::COldModelManager* m_modelManager;
|
||||
Gfx::CParticle* m_particle;
|
||||
CRobotMain* m_main;
|
||||
};
|
||||
|
|
|
@ -38,7 +38,7 @@ template<> CObjectManager* CSingleton<CObjectManager>::m_instance = nullptr;
|
|||
|
||||
CObjectManager::CObjectManager(Gfx::CEngine* engine,
|
||||
Gfx::CTerrain* terrain,
|
||||
Gfx::CModelManager* modelManager,
|
||||
Gfx::COldModelManager* modelManager,
|
||||
Gfx::CParticle* particle,
|
||||
CRobotMain* main)
|
||||
: m_objectFactory(new CObjectFactory(engine, terrain, modelManager, particle, main))
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
|
||||
namespace Gfx {
|
||||
class CEngine;
|
||||
class CModelManager;
|
||||
class COldModelManager;
|
||||
class CParticle;
|
||||
class CTerrain;
|
||||
} // namespace Gfx
|
||||
|
@ -122,7 +122,7 @@ class CObjectManager : public CSingleton<CObjectManager>
|
|||
public:
|
||||
CObjectManager(Gfx::CEngine* engine,
|
||||
Gfx::CTerrain* terrain,
|
||||
Gfx::CModelManager* modelManager,
|
||||
Gfx::COldModelManager* modelManager,
|
||||
Gfx::CParticle* particle,
|
||||
CRobotMain* main);
|
||||
virtual ~CObjectManager();
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
|
||||
#include "graphics/engine/lightman.h"
|
||||
#include "graphics/engine/lightning.h"
|
||||
#include "graphics/engine/modelmanager.h"
|
||||
#include "graphics/engine/particle.h"
|
||||
#include "graphics/engine/pyro_manager.h"
|
||||
#include "graphics/engine/terrain.h"
|
||||
|
@ -2129,15 +2128,10 @@ void COldObject::UpdateEnergyMapping()
|
|||
float au = (s-i)/(b-a);
|
||||
float bu = s-b*(s-i)/(b-a);
|
||||
|
||||
Gfx::LODLevel lodLevels[3] = { Gfx::LOD_High, Gfx::LOD_Medium, Gfx::LOD_Low };
|
||||
|
||||
for (int j = 0; j < 3; j++)
|
||||
{
|
||||
m_engine->ChangeTextureMapping(m_objectPart[0].object,
|
||||
mat, Gfx::ENG_RSTATE_PART3, "objects/lemt.png", "",
|
||||
lodLevels[j], Gfx::ENG_TEX_MAPPING_1Y,
|
||||
au, bu, 1.0f, 0.0f);
|
||||
}
|
||||
m_engine->ChangeTextureMapping(m_objectPart[0].object,
|
||||
mat, Gfx::ENG_RSTATE_PART3, "objects/lemt.png", "",
|
||||
Gfx::ENG_TEX_MAPPING_1Y,
|
||||
au, bu, 1.0f, 0.0f);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@
|
|||
#include "graphics/engine/engine.h"
|
||||
#include "graphics/engine/lightman.h"
|
||||
#include "graphics/engine/lightning.h"
|
||||
#include "graphics/engine/modelmanager.h"
|
||||
#include "graphics/engine/oldmodelmanager.h"
|
||||
#include "graphics/engine/particle.h"
|
||||
#include "graphics/engine/planet.h"
|
||||
#include "graphics/engine/pyro_manager.h"
|
||||
|
|
|
@ -381,7 +381,7 @@ protected:
|
|||
Gfx::CCloud* m_cloud;
|
||||
Gfx::CLightning* m_lightning;
|
||||
Gfx::CPlanet* m_planet;
|
||||
Gfx::CModelManager* m_modelManager;
|
||||
Gfx::COldModelManager* m_modelManager;
|
||||
Gfx::CLightManager* m_lightMan;
|
||||
Gfx::CTerrain* m_terrain;
|
||||
Gfx::CCamera* m_camera;
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
#include "common/regex_utils.h"
|
||||
|
||||
#include "graphics/engine/modelmanager.h"
|
||||
#include "graphics/engine/oldmodelmanager.h"
|
||||
|
||||
#include "object/object_create_params.h"
|
||||
#include "object/level/parserline.h"
|
||||
|
@ -46,7 +46,7 @@ CExchangePost::CExchangePost(int id)
|
|||
|
||||
std::unique_ptr<CExchangePost> CExchangePost::Create(
|
||||
const ObjectCreateParams& params,
|
||||
Gfx::CModelManager* modelManager,
|
||||
Gfx::COldModelManager* modelManager,
|
||||
Gfx::CEngine* engine)
|
||||
{
|
||||
std::unique_ptr<CExchangePost> obj{new CExchangePost(params.id)};
|
||||
|
|
|
@ -37,7 +37,7 @@ struct ExchangePostInfo
|
|||
struct ObjectCreateParams;
|
||||
|
||||
namespace Gfx {
|
||||
class CModelManager;
|
||||
class COldModelManager;
|
||||
class CEngine;
|
||||
}
|
||||
|
||||
|
@ -48,7 +48,7 @@ public:
|
|||
|
||||
static std::unique_ptr<CExchangePost> Create(
|
||||
const ObjectCreateParams& params,
|
||||
Gfx::CModelManager* modelManager,
|
||||
Gfx::COldModelManager* modelManager,
|
||||
Gfx::CEngine* engine);
|
||||
|
||||
static int GetMaximumInfoListSize();
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
set(CONVERT_MODEL_SOURCES
|
||||
../common/logger.cpp
|
||||
../common/stringutils.cpp
|
||||
../graphics/engine/modelfile.cpp
|
||||
convert_model.cpp
|
||||
../common/logger.cpp
|
||||
../graphics/model/model.cpp
|
||||
../graphics/model/model_mesh.cpp
|
||||
../graphics/model/model_input.cpp
|
||||
../graphics/model/model_output.cpp
|
||||
convert_model.cpp
|
||||
)
|
||||
|
||||
include_directories(. ..)
|
||||
|
||||
include_directories(SYSTEM ${SDL_INCLUDE_DIR})
|
||||
|
||||
add_definitions(-DMODELFILE_NO_ENGINE)
|
||||
|
||||
add_executable(convert_model ${CONVERT_MODEL_SOURCES})
|
||||
|
||||
|
|
|
@ -17,11 +17,17 @@
|
|||
* along with this program. If not, see http://gnu.org/licenses
|
||||
*/
|
||||
#include "common/logger.h"
|
||||
#include "graphics/engine/modelfile.h"
|
||||
|
||||
#include "graphics/model/model_input.h"
|
||||
#include "graphics/model/model_output.h"
|
||||
#include "graphics/model/model_io_exception.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
|
||||
using namespace Gfx;
|
||||
|
||||
|
||||
bool EndsWith(std::string const &fullString, std::string const &ending)
|
||||
{
|
||||
|
@ -151,18 +157,6 @@ bool ParseArgs(int argc, char *argv[])
|
|||
return true;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& stream, Gfx::LODLevel lodLevel)
|
||||
{
|
||||
switch (lodLevel)
|
||||
{
|
||||
case Gfx::LOD_Constant: stream << "constant"; break;
|
||||
case Gfx::LOD_High: stream << "high"; break;
|
||||
case Gfx::LOD_Medium: stream << "medium"; break;
|
||||
case Gfx::LOD_Low: stream << "low"; break;
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void PrintStats(const std::map<T, int>& stats, int total)
|
||||
{
|
||||
|
@ -172,6 +166,57 @@ void PrintStats(const std::map<T, int>& stats, int total)
|
|||
}
|
||||
}
|
||||
|
||||
void DumpInfo(const CModel& model)
|
||||
{
|
||||
const CModelMesh* mesh = model.GetMesh("main");
|
||||
if (mesh == nullptr)
|
||||
{
|
||||
std::cerr << "Main mesh not found!" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
Math::Vector bboxMin( Math::HUGE_NUM, Math::HUGE_NUM, Math::HUGE_NUM);
|
||||
Math::Vector bboxMax(-Math::HUGE_NUM, -Math::HUGE_NUM, -Math::HUGE_NUM);
|
||||
|
||||
std::map<std::string, int> texs1, texs2;
|
||||
std::map<int, int> states;
|
||||
int variableTexs2 = 0;
|
||||
|
||||
for (const ModelTriangle& t : mesh->GetTriangles())
|
||||
{
|
||||
bboxMin.x = Math::Min(t.p1.coord.x, t.p2.coord.x, t.p3.coord.x, bboxMin.x);
|
||||
bboxMin.y = Math::Min(t.p1.coord.y, t.p2.coord.y, t.p3.coord.y, bboxMin.y);
|
||||
bboxMin.z = Math::Min(t.p1.coord.z, t.p2.coord.z, t.p3.coord.z, bboxMin.z);
|
||||
|
||||
bboxMax.x = Math::Max(t.p1.coord.x, t.p2.coord.x, t.p3.coord.x, bboxMax.x);
|
||||
bboxMax.y = Math::Max(t.p1.coord.y, t.p2.coord.y, t.p3.coord.y, bboxMax.y);
|
||||
bboxMax.z = Math::Max(t.p1.coord.z, t.p2.coord.z, t.p3.coord.z, bboxMax.z);
|
||||
|
||||
texs1[t.tex1Name] += 1;
|
||||
if (! t.tex2Name.empty())
|
||||
texs2[t.tex2Name] += 1;
|
||||
if (t.variableTex2)
|
||||
variableTexs2 += 1;
|
||||
}
|
||||
|
||||
int total = mesh->GetTriangleCount();
|
||||
|
||||
std::cerr << "---- Info ----" << std::endl;
|
||||
std::cerr << "Total triangles: " << total;
|
||||
std::cerr << std::endl;
|
||||
std::cerr << "Bounding box:" << std::endl;
|
||||
std::cerr << " bboxMin: [" << bboxMin.x << ", " << bboxMin.y << ", " << bboxMin.z << "]" << std::endl;
|
||||
std::cerr << " bboxMax: [" << bboxMax.x << ", " << bboxMax.y << ", " << bboxMax.z << "]" << std::endl;
|
||||
std::cerr << std::endl;
|
||||
std::cerr << "Textures:" << std::endl;
|
||||
std::cerr << " tex1:" << std::endl;
|
||||
PrintStats(texs1, total);
|
||||
std::cerr << " tex2:" << std::endl;
|
||||
PrintStats(texs2, total);
|
||||
std::cerr << " variable tex2: " << variableTexs2 << " / " << total << std::endl;
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
CLogger logger;
|
||||
|
@ -186,112 +231,71 @@ int main(int argc, char *argv[])
|
|||
if (ARGS.usage)
|
||||
return 0;
|
||||
|
||||
Gfx::CModelFile model;
|
||||
|
||||
bool ok = true;
|
||||
ModelFormat inputFormat = ModelFormat::Old;
|
||||
|
||||
if (ARGS.inputFormat == "old")
|
||||
{
|
||||
ok = model.ReadModel(ARGS.inputFile);
|
||||
}
|
||||
inputFormat = ModelFormat::Old;
|
||||
else if (ARGS.inputFormat == "new_bin")
|
||||
{
|
||||
ok = model.ReadBinaryModel(ARGS.inputFile);
|
||||
}
|
||||
inputFormat = ModelFormat::Binary;
|
||||
else if (ARGS.inputFormat == "new_txt")
|
||||
{
|
||||
ok = model.ReadTextModel(ARGS.inputFile);
|
||||
}
|
||||
inputFormat = ModelFormat::Text;
|
||||
else
|
||||
{
|
||||
std::cerr << "Invalid input format" << std::endl;
|
||||
std::cerr << "Invalid input format: " << ARGS.inputFormat << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!ok)
|
||||
CModel model;
|
||||
|
||||
try
|
||||
{
|
||||
std::cerr << "Reading input model failed" << std::endl;
|
||||
std::ifstream stream;
|
||||
stream.open(ARGS.inputFile, std::ios_base::in | std::ios_base::binary);
|
||||
if (!stream.good())
|
||||
throw CModelIOException(std::string("Could not open file: ") + ARGS.inputFile);
|
||||
|
||||
model = ModelInput::Read(stream, inputFormat);
|
||||
}
|
||||
catch (const CModelIOException& e)
|
||||
{
|
||||
std::cerr << "Reading input model failed with error:" << std::endl;
|
||||
std::cerr << e.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ARGS.dumpInfo)
|
||||
{
|
||||
const std::vector<Gfx::ModelTriangle>& triangles = model.GetTriangles();
|
||||
|
||||
Math::Vector bboxMin( Math::HUGE_NUM, Math::HUGE_NUM, Math::HUGE_NUM);
|
||||
Math::Vector bboxMax(-Math::HUGE_NUM, -Math::HUGE_NUM, -Math::HUGE_NUM);
|
||||
|
||||
std::map<std::string, int> texs1, texs2;
|
||||
std::map<int, int> states;
|
||||
std::map<Gfx::LODLevel, int> lodLevels;
|
||||
int variableTexs2 = 0;
|
||||
|
||||
for (int i = 0; i < static_cast<int>( triangles.size() ); ++i)
|
||||
{
|
||||
const Gfx::ModelTriangle& t = triangles[i];
|
||||
|
||||
bboxMin.x = Math::Min(t.p1.coord.x, t.p2.coord.x, t.p3.coord.x, bboxMin.x);
|
||||
bboxMin.y = Math::Min(t.p1.coord.y, t.p2.coord.y, t.p3.coord.y, bboxMin.y);
|
||||
bboxMin.z = Math::Min(t.p1.coord.z, t.p2.coord.z, t.p3.coord.z, bboxMin.z);
|
||||
|
||||
bboxMax.x = Math::Max(t.p1.coord.x, t.p2.coord.x, t.p3.coord.x, bboxMax.x);
|
||||
bboxMax.y = Math::Max(t.p1.coord.y, t.p2.coord.y, t.p3.coord.y, bboxMax.y);
|
||||
bboxMax.z = Math::Max(t.p1.coord.z, t.p2.coord.z, t.p3.coord.z, bboxMax.z);
|
||||
|
||||
texs1[t.tex1Name] += 1;
|
||||
if (! t.tex2Name.empty())
|
||||
texs2[t.tex2Name] += 1;
|
||||
if (t.variableTex2)
|
||||
variableTexs2 += 1;
|
||||
states[t.state] += 1;
|
||||
|
||||
lodLevels[t.lodLevel] += 1;
|
||||
}
|
||||
|
||||
std::cerr << "---- Info ----" << std::endl;
|
||||
std::cerr << "Total triangles: " << triangles.size();
|
||||
std::cerr << std::endl;
|
||||
std::cerr << "Bounding box:" << std::endl;
|
||||
std::cerr << " bboxMin: [" << bboxMin.x << ", " << bboxMin.y << ", " << bboxMin.z << "]" << std::endl;
|
||||
std::cerr << " bboxMax: [" << bboxMax.x << ", " << bboxMax.y << ", " << bboxMax.z << "]" << std::endl;
|
||||
std::cerr << std::endl;
|
||||
std::cerr << "Textures:" << std::endl;
|
||||
std::cerr << " tex1:" << std::endl;
|
||||
PrintStats(texs1, triangles.size());
|
||||
std::cerr << " tex2:" << std::endl;
|
||||
PrintStats(texs2, triangles.size());
|
||||
std::cerr << " variable tex2: " << variableTexs2 << " / " << triangles.size() << std::endl;
|
||||
std::cerr << std::endl;
|
||||
std::cerr << "States:" << std::endl;
|
||||
PrintStats(states, triangles.size());
|
||||
std::cerr << std::endl;
|
||||
std::cerr << "LOD:" << std::endl;
|
||||
PrintStats(lodLevels, triangles.size());
|
||||
DumpInfo(model);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ModelFormat outputFormat = ModelFormat::Old;
|
||||
|
||||
if (ARGS.outputFormat == "old")
|
||||
{
|
||||
ok = model.WriteModel(ARGS.outputFile);
|
||||
}
|
||||
outputFormat = ModelFormat::Old;
|
||||
else if (ARGS.outputFormat == "new_bin")
|
||||
{
|
||||
ok = model.WriteBinaryModel(ARGS.outputFile);
|
||||
}
|
||||
outputFormat = ModelFormat::Binary;
|
||||
else if (ARGS.outputFormat == "new_txt")
|
||||
{
|
||||
ok = model.WriteTextModel(ARGS.outputFile);
|
||||
}
|
||||
outputFormat = ModelFormat::Text;
|
||||
else
|
||||
{
|
||||
std::cerr << "Invalid output format" << std::endl;
|
||||
std::cerr << "Invalid output format: " << ARGS.outputFormat << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!ok)
|
||||
try
|
||||
{
|
||||
std::cerr << "Writing output model failed" << std::endl;
|
||||
std::ofstream stream;
|
||||
stream.open(ARGS.outputFile, std::ios_base::out | std::ios_base::binary);
|
||||
if (!stream.good())
|
||||
throw CModelIOException(std::string("Could not open file: ") + ARGS.inputFile);
|
||||
ModelOutput::Write(model, stream, outputFormat);
|
||||
}
|
||||
catch (const CModelIOException& e)
|
||||
{
|
||||
std::cerr << "Writing output model failed with error:" << std::endl;
|
||||
std::cerr << e.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue