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 enums
master
Piotr Dziwinski 2015-07-09 18:45:02 +02:00
parent 9b232ee3f5
commit 93e950584a
59 changed files with 2132 additions and 1975 deletions

2
data

@ -1 +1 @@
Subproject commit 73bb8f9ac0f8af3e810455af2ab2dd5113af03eb
Subproject commit c1da1d3ca64d8b6450023d9a6f095b5e8a80da63

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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