diff options
Diffstat (limited to 'src/graphics/engine')
-rw-r--r-- | src/graphics/engine/engine.cpp | 1758 | ||||
-rw-r--r-- | src/graphics/engine/engine.h | 341 | ||||
-rw-r--r-- | src/graphics/engine/modelfile.cpp | 136 | ||||
-rw-r--r-- | src/graphics/engine/modelfile.h | 27 | ||||
-rw-r--r-- | src/graphics/engine/modelmanager.cpp | 213 | ||||
-rw-r--r-- | src/graphics/engine/modelmanager.h | 97 | ||||
-rw-r--r-- | src/graphics/engine/pyro.cpp | 3 | ||||
-rw-r--r-- | src/graphics/engine/terrain.cpp | 29 | ||||
-rw-r--r-- | src/graphics/engine/terrain.h | 2 | ||||
-rw-r--r-- | src/graphics/engine/test/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/graphics/engine/test/modelfile_test.cpp | 12 |
11 files changed, 1362 insertions, 1257 deletions
diff --git a/src/graphics/engine/engine.cpp b/src/graphics/engine/engine.cpp index de5f2d4..73cd73a 100644 --- a/src/graphics/engine/engine.cpp +++ b/src/graphics/engine/engine.cpp @@ -47,56 +47,6 @@ // Graphics module namespace namespace Gfx { - -// Initial size of various vectors -const int OBJECT_PREALLOCATE_COUNT = 1200; -const int SHADOW_PREALLOCATE_COUNT = 500; -const int GROUNDSPOT_PREALLOCATE_COUNT = 100; - -const int LEVEL1_PREALLOCATE_COUNT = 50; -const int LEVEL2_PREALLOCATE_COUNT = 100; -const int LEVEL3_PREALLOCATE_COUNT = 5; -const int LEVEL4_PREALLOCATE_COUNT = 100; -const int LEVEL4_VERTEX_PREALLOCATE_COUNT = 200; - - -EngineObjLevel1::EngineObjLevel1(bool used, const std::string& tex1Name, const std::string& tex2Name) -{ - this->used = used; - this->tex1Name = tex1Name; - this->tex2Name = tex2Name; - - next.reserve(LEVEL2_PREALLOCATE_COUNT); -} - -EngineObjLevel2::EngineObjLevel2(bool used, int objRank) -{ - this->used = used; - this->objRank = objRank; - - next.reserve(LEVEL3_PREALLOCATE_COUNT); -} - -EngineObjLevel3::EngineObjLevel3(bool used, float min, float max) -{ - this->used = used; - this->min = min; - this->max = max; - - next.reserve(LEVEL4_PREALLOCATE_COUNT); -} - -EngineObjLevel4::EngineObjLevel4(bool used, EngineTriangleType type, const Material& material, int state) -{ - this->used = used; - this->type = type; - this->material = material; - this->state = state; - this->staticBufferId = 0; - - vertices.reserve(LEVEL4_VERTEX_PREALLOCATE_COUNT); -} - CEngine::CEngine(CInstanceManager *iMan, CApplication *app) { m_iMan = iMan; @@ -183,7 +133,7 @@ CEngine::CEngine(CInstanceManager *iMan, CApplication *app) m_alphaMode = 1; m_updateGeometry = false; - m_updateStaticObjects = false; + m_updateStaticBuffers = false; m_interfaceMode = false; @@ -220,11 +170,6 @@ CEngine::CEngine(CInstanceManager *iMan, CApplication *app) m_terrainTexParams.mipmap = false; m_terrainTexParams.minFilter = TEX_MIN_FILTER_LINEAR; m_terrainTexParams.magFilter = TEX_MAG_FILTER_LINEAR; - - m_objectTree.reserve(LEVEL1_PREALLOCATE_COUNT); - m_objects.reserve(OBJECT_PREALLOCATE_COUNT); - m_shadows.reserve(SHADOW_PREALLOCATE_COUNT); - m_groundSpots.reserve(GROUNDSPOT_PREALLOCATE_COUNT); } CEngine::~CEngine() @@ -387,7 +332,7 @@ void CEngine::FrameUpdate() ComputeDistance(); UpdateGeometry(); - UpdateStaticObjects(); + UpdateStaticBuffers(); m_highlightTime = m_app->GetAbsTime(); @@ -495,7 +440,7 @@ Math::Point CEngine::WindowToInterfaceSize(Math::IntPoint size) Math::IntPoint CEngine::InterfaceToWindowSize(Math::Point size) { return Math::IntPoint(static_cast<int>(size.x * m_size.x), - static_cast<int>(size.y * m_size.y)); + static_cast<int>(size.y * m_size.y)); } void CEngine::AddStatisticTriangle(int count) @@ -514,263 +459,40 @@ int CEngine::GetStatisticTriangle() Object management *******************************************************/ - - -int CEngine::CreateObject() -{ - int i = 0; - for ( ; i < static_cast<int>( m_objects.size() ); i++) - { - if (! m_objects[i].used) - { - m_objects[i].LoadDefault(); - break; - } - } - - if (i == static_cast<int>( m_objects.size() )) - m_objects.push_back(EngineObject()); - - - m_objects[i].used = true; - - Math::Matrix mat; - mat.LoadIdentity(); - SetObjectTransform(i, mat); - - m_objects[i].drawWorld = true; - m_objects[i].distance = 0.0f; - m_objects[i].bboxMin = Math::Vector(0.0f, 0.0f, 0.0f); - m_objects[i].bboxMax = Math::Vector(0.0f, 0.0f, 0.0f); - m_objects[i].shadowRank = -1; - - return i; -} - -void CEngine::FlushObject() -{ - m_objectTree.clear(); - m_objects.clear(); - - m_shadows.clear(); - - FlushGroundSpot(); -} - -bool CEngine::DeleteObject(int objRank) -{ - if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) ) - return false; - - // Delete object's triangles - for (int l1 = 0; l1 < static_cast<int>( m_objectTree.size() ); l1++) - { - EngineObjLevel1& p1 = m_objectTree[l1]; - if (! p1.used) continue; - - for (int l2 = 0; l2 < static_cast<int>( p1.next.size() ); l2++) - { - EngineObjLevel2& p2 = p1.next[l2]; - if (! p2.used) continue; - - if (p2.objRank != objRank) continue; - - if (m_objects[objRank].staticBuffer) - { - for (int l3 = 0; l3 < static_cast<int>( p2.next.size() ); l3++) - { - EngineObjLevel3& p3 = p2.next[l3]; - if (! p3.used) continue; - - for (int l4 = 0; l4 < static_cast<int>( p3.next.size() ); l4++) - { - EngineObjLevel4& p4 = p3.next[l4]; - - m_device->DestroyStaticObject(p4.staticBufferId); - } - } - } - - - p2.used = false; - p2.next.clear(); - } - } - - // Mark object as deleted - m_objects[objRank].used = false; - - // Delete associated shadows - DeleteShadow(objRank); - - return true; -} - -bool CEngine::SetObjectType(int objRank, EngineObjectType type) -{ - if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) ) - return false; - - m_objects[objRank].type = type; - return true; -} - -EngineObjectType CEngine::GetObjectType(int objRank) -{ - if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) ) - return ENG_OBJTYPE_NULL; - - return m_objects[objRank].type; -} - - -bool CEngine::SetObjectTransform(int objRank, const Math::Matrix& transform) -{ - if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) ) - return false; - - m_objects[objRank].transform = transform; - return true; -} - -bool CEngine::GetObjectTransform(int objRank, Math::Matrix& transform) -{ - if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) ) - return false; - - transform = m_objects[objRank].transform; - return true; -} - -void CEngine::SetObjectStatic(int objRank, bool staticBuffer) -{ - if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) ) - return; - - m_objects[objRank].staticBuffer = staticBuffer; -} - -bool CEngine::GetObjectStatic(int objRank) -{ - if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) ) - return false; - - return m_objects[objRank].staticBuffer; -} - -bool CEngine::SetObjectDrawWorld(int objRank, bool draw) -{ - if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) ) - return false; - - m_objects[objRank].drawWorld = draw; - return true; -} - -bool CEngine::SetObjectDrawFront(int objRank, bool draw) -{ - if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) ) - return false; - - m_objects[objRank].drawFront = draw; - return true; -} - -bool CEngine::SetObjectTransparency(int objRank, float value) -{ - if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) ) - return false; - - m_objects[objRank].transparency = value; - return true; -} - -bool CEngine::GetObjectBBox(int objRank, Math::Vector& min, Math::Vector& max) -{ - if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) ) - return 0; - - min = m_objects[objRank].bboxMin; - max = m_objects[objRank].bboxMax; - return true; -} - - -int CEngine::GetObjectTotalTriangles(int objRank) -{ - if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) ) - return 0; - - return m_objects[objRank].totalTriangles; -} - - -EngineObjLevel1& CEngine::AddLevel1(const std::string& tex1Name, const std::string& tex2Name) -{ - bool unusedPresent = false; - for (int i = 0; i < static_cast<int>( m_objectTree.size() ); i++) - { - if (! m_objectTree[i].used) - { - unusedPresent = true; - continue; - } - - if (m_objectTree[i].tex1Name == tex1Name && m_objectTree[i].tex2Name == tex2Name) - return m_objectTree[i]; - } - - if (unusedPresent) - { - for (int i = 0; i < static_cast<int>( m_objectTree.size() ); i++) - { - if (! m_objectTree[i].used) - { - m_objectTree[i].used = true; - m_objectTree[i].tex1Name = tex1Name; - m_objectTree[i].tex2Name = tex2Name; - return m_objectTree[i]; - } - } - } - - m_objectTree.push_back(EngineObjLevel1(true, tex1Name, tex2Name)); - return m_objectTree.back(); -} - -EngineObjLevel2& CEngine::AddLevel2(EngineObjLevel1& p1, int objRank) +EngineBaseObjTexTier& CEngine::AddLevel2(int baseObjRank, const std::string& tex1Name, const std::string& tex2Name) { bool unusedPresent = false; - for (int i = 0; i < static_cast<int>( p1.next.size() ); i++) + for (int i = 0; i < static_cast<int>( m_baseObjects[baseObjRank].next.size() ); i++) { - if (! p1.next[i].used) + if (! m_baseObjects[baseObjRank].next[i].used) { unusedPresent = true; continue; } - if (p1.next[i].objRank == objRank) - return p1.next[i]; + if (m_baseObjects[baseObjRank].next[i].tex1Name == tex1Name && m_baseObjects[baseObjRank].next[i].tex2Name == tex2Name) + return m_baseObjects[baseObjRank].next[i]; } if (unusedPresent) { - for (int i = 0; i < static_cast<int>( p1.next.size() ); i++) + for (int i = 0; i < static_cast<int>( m_baseObjects[baseObjRank].next.size() ); i++) { - if (! p1.next[i].used) + if (! m_baseObjects[baseObjRank].next[i].used) { - p1.next[i].used = true; - p1.next[i].objRank = objRank; - return p1.next[i]; + m_baseObjects[baseObjRank].next[i].used = true; + m_baseObjects[baseObjRank].next[i].tex1Name = tex1Name; + m_baseObjects[baseObjRank].next[i].tex2Name = tex2Name; + return m_baseObjects[baseObjRank].next[i]; } } } - p1.next.push_back(EngineObjLevel2(true, objRank)); - return p1.next.back(); + m_baseObjects[baseObjRank].next.push_back(EngineBaseObjTexTier(true, tex1Name, tex2Name)); + return m_baseObjects[baseObjRank].next.back(); } -EngineObjLevel3& CEngine::AddLevel3(EngineObjLevel2& p2, float min, float max) +EngineBaseObjLODTier& CEngine::AddLevel3(EngineBaseObjTexTier& p2, float min, float max) { bool unusedPresent = false; for (int i = 0; i < static_cast<int>( p2.next.size() ); i++) @@ -799,12 +521,12 @@ EngineObjLevel3& CEngine::AddLevel3(EngineObjLevel2& p2, float min, float max) } } - p2.next.push_back(EngineObjLevel3(true, min, max)); + p2.next.push_back(EngineBaseObjLODTier(true, min, max)); return p2.next.back(); } -EngineObjLevel4& CEngine::AddLevel4(EngineObjLevel3& p3, EngineTriangleType type, - const Material& material, int state) +EngineBaseObjDataTier& CEngine::AddLevel4(EngineBaseObjLODTier& p3, EngineTriangleType type, + const Material& material, int state) { bool unusedPresent = false; for (int i = 0; i < static_cast<int>( p3.next.size() ); i++) @@ -834,100 +556,96 @@ EngineObjLevel4& CEngine::AddLevel4(EngineObjLevel3& p3, EngineTriangleType type } } - p3.next.push_back(EngineObjLevel4(true, type, material, state)); + p3.next.push_back(EngineBaseObjDataTier(true, type, material, state)); return p3.next.back(); } -bool CEngine::AddTriangles(int objRank, const std::vector<VertexTex2>& vertices, - const Material& material, int state, - std::string tex1Name, std::string tex2Name, - float min, float max, bool globalUpdate) +int CEngine::CreateBaseObject() { - if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) ) + int i = 0; + for ( ; i < static_cast<int>( m_baseObjects.size() ); i++) { - GetLogger()->Error("AddTriangle(): invalid object rank %d\n", objRank); - return false; + if (! m_baseObjects[i].used) + { + m_baseObjects[i].LoadDefault(); + break; + } } - m_lastSize = m_size; - m_lastObjectDetail = m_objectDetail; - m_lastClippingDistance = m_clippingDistance; + if (i == static_cast<int>( m_baseObjects.size() )) + m_baseObjects.push_back(EngineBaseObject()); + else + m_baseObjects[i].LoadDefault(); - EngineObjLevel1& p1 = AddLevel1(tex1Name, tex2Name); - EngineObjLevel2& p2 = AddLevel2(p1, objRank); - EngineObjLevel3& p3 = AddLevel3(p2, min, max); - EngineObjLevel4& p4 = AddLevel4(p3, ENG_TRIANGLE_TYPE_TRIANGLES, material, state); - p4.vertices.insert(p4.vertices.end(), vertices.begin(), vertices.end()); + m_baseObjects[i].used = true; - if (m_objects[objRank].staticBuffer) - { - if (p4.staticBufferId != 0) - { - m_device->DestroyStaticObject(p4.staticBufferId); - p4.staticBufferId = 0; - } + return i; +} - m_updateStaticObjects = true; - } +void CEngine::DeleteBaseObject(int baseObjRank) +{ + assert(baseObjRank < -1 || baseObjRank >= static_cast<int>( m_baseObjects.size() )); - if (globalUpdate) - { - m_updateGeometry = true; - } - else + for (int l2 = 0; l2 < static_cast<int>( m_baseObjects[baseObjRank].next.size() ); l2++) { - for (int i = 0; i < static_cast<int>( vertices.size() ); i++) + EngineBaseObjTexTier& p2 = m_baseObjects[baseObjRank].next[l2]; + if (! p2.used) + continue; + + for (int l3 = 0; l3 < static_cast<int>( p2.next.size() ); l3++) { - m_objects[objRank].bboxMin.x = Math::Min(vertices[i].coord.x, m_objects[objRank].bboxMin.x); - m_objects[objRank].bboxMin.y = Math::Min(vertices[i].coord.y, m_objects[objRank].bboxMin.y); - m_objects[objRank].bboxMin.z = Math::Min(vertices[i].coord.z, m_objects[objRank].bboxMin.z); - m_objects[objRank].bboxMax.x = Math::Max(vertices[i].coord.x, m_objects[objRank].bboxMax.x); - m_objects[objRank].bboxMax.y = Math::Max(vertices[i].coord.y, m_objects[objRank].bboxMax.y); - m_objects[objRank].bboxMax.z = Math::Max(vertices[i].coord.z, m_objects[objRank].bboxMax.z); + EngineBaseObjLODTier& p3 = p2.next[l3]; + if (! p3.used) + continue; + + 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; + } } - m_objects[objRank].radius = Math::Max(m_objects[objRank].bboxMin.Length(), - m_objects[objRank].bboxMax.Length()); + p2.used = false; + p2.next.clear(); } +} + +void CEngine::DeleteAllBaseObjects() +{ + m_baseObjects.clear(); +} - m_objects[objRank].totalTriangles += vertices.size() / 3; +void CEngine::CopyBaseObject(int sourceBaseObjRank, int destBaseObjRank) +{ + assert(sourceBaseObjRank >= 0 && sourceBaseObjRank < static_cast<int>( m_baseObjects.size() )); + assert(destBaseObjRank >= 0 && destBaseObjRank < static_cast<int>( m_baseObjects.size() )); - return true; + m_baseObjects[destBaseObjRank] = m_baseObjects[sourceBaseObjRank]; } -bool CEngine::AddSurface(int objRank, const std::vector<VertexTex2>& vertices, - const Material& material, int state, - std::string tex1Name, std::string tex2Name, - float min, float max, bool globalUpdate) +void CEngine::AddBaseObjTriangles(int baseObjRank, const std::vector<VertexTex2>& vertices, + EngineTriangleType triangleType, + const Material& material, int state, + std::string tex1Name, std::string tex2Name, + float min, float max, bool globalUpdate) { - if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) ) - { - GetLogger()->Error("AddSurface(): invalid object rank %d\n", objRank); - return false; - } + assert(baseObjRank >= 0 && baseObjRank < static_cast<int>( m_baseObjects.size() )); m_lastSize = m_size; m_lastObjectDetail = m_objectDetail; m_lastClippingDistance = m_clippingDistance; - EngineObjLevel1& p1 = AddLevel1(tex1Name, tex2Name); - EngineObjLevel2& p2 = AddLevel2(p1, objRank); - EngineObjLevel3& p3 = AddLevel3(p2, min, max); - EngineObjLevel4& p4 = AddLevel4(p3, ENG_TRIANGLE_TYPE_SURFACE, material, state); + EngineBaseObjTexTier& p2 = AddLevel2(baseObjRank, tex1Name, tex2Name); + EngineBaseObjLODTier& p3 = AddLevel3(p2, min, max); + EngineBaseObjDataTier& p4 = AddLevel4(p3, triangleType, material, state); p4.vertices.insert(p4.vertices.end(), vertices.begin(), vertices.end()); - if (m_objects[objRank].staticBuffer) - { - if (p4.staticBufferId != 0) - { - m_device->DestroyStaticObject(p4.staticBufferId); - p4.staticBufferId = 0; - } - - m_updateStaticObjects = true; - } + p4.updateStaticBuffer = true; + m_updateStaticBuffers = true; if (globalUpdate) { @@ -937,58 +655,41 @@ bool CEngine::AddSurface(int objRank, const std::vector<VertexTex2>& vertices, { for (int i = 0; i < static_cast<int>( vertices.size() ); i++) { - m_objects[objRank].bboxMin.x = Math::Min(vertices[i].coord.x, m_objects[objRank].bboxMin.x); - m_objects[objRank].bboxMin.y = Math::Min(vertices[i].coord.y, m_objects[objRank].bboxMin.y); - m_objects[objRank].bboxMin.z = Math::Min(vertices[i].coord.z, m_objects[objRank].bboxMin.z); - m_objects[objRank].bboxMax.x = Math::Max(vertices[i].coord.x, m_objects[objRank].bboxMax.x); - m_objects[objRank].bboxMax.y = Math::Max(vertices[i].coord.y, m_objects[objRank].bboxMax.y); - m_objects[objRank].bboxMax.z = Math::Max(vertices[i].coord.z, m_objects[objRank].bboxMax.z); + m_baseObjects[baseObjRank].bboxMin.x = Math::Min(vertices[i].coord.x, m_baseObjects[baseObjRank].bboxMin.x); + m_baseObjects[baseObjRank].bboxMin.y = Math::Min(vertices[i].coord.y, m_baseObjects[baseObjRank].bboxMin.y); + m_baseObjects[baseObjRank].bboxMin.z = Math::Min(vertices[i].coord.z, m_baseObjects[baseObjRank].bboxMin.z); + m_baseObjects[baseObjRank].bboxMax.x = Math::Max(vertices[i].coord.x, m_baseObjects[baseObjRank].bboxMax.x); + m_baseObjects[baseObjRank].bboxMax.y = Math::Max(vertices[i].coord.y, m_baseObjects[baseObjRank].bboxMax.y); + m_baseObjects[baseObjRank].bboxMax.z = Math::Max(vertices[i].coord.z, m_baseObjects[baseObjRank].bboxMax.z); } - m_objects[objRank].radius = Math::Max(m_objects[objRank].bboxMin.Length(), - m_objects[objRank].bboxMax.Length()); + m_baseObjects[baseObjRank].radius = Math::Max(m_baseObjects[baseObjRank].bboxMin.Length(), + m_baseObjects[baseObjRank].bboxMax.Length()); } - m_objects[objRank].totalTriangles += vertices.size() - 2; - - return true; + if (triangleType == ENG_TRIANGLE_TYPE_TRIANGLES) + m_baseObjects[baseObjRank].totalTriangles += vertices.size() / 3; + else + m_baseObjects[baseObjRank].totalTriangles += vertices.size() - 2; } -bool CEngine::AddQuick(int objRank, const EngineObjLevel4& buffer, - std::string tex1Name, std::string tex2Name, - float min, float max, bool globalUpdate) +void CEngine::AddBaseObjQuick(int baseObjRank, const EngineBaseObjDataTier& buffer, + std::string tex1Name, std::string tex2Name, + float min, float max, bool globalUpdate) { - if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) ) - { - GetLogger()->Error("AddQuick(): invalid object rank %d\n", objRank); - return false; - } + assert(baseObjRank >= 0 && baseObjRank < static_cast<int>( m_baseObjects.size() )); - EngineObjLevel1& p1 = AddLevel1(tex1Name, tex2Name); - EngineObjLevel2& p2 = AddLevel2(p1, objRank); - EngineObjLevel3& p3 = AddLevel3(p2, min, max); + EngineBaseObjTexTier& p2 = AddLevel2(baseObjRank, tex1Name, tex2Name); + EngineBaseObjLODTier& p3 = AddLevel3(p2, min, max); p3.next.push_back(buffer); - EngineObjLevel4& p4 = p3.next.back(); - p4.used = true; // ensure that it is used - - if (m_objects[objRank].staticBuffer) - { - if (p4.staticBufferId != 0) - { - m_device->DestroyStaticObject(p4.staticBufferId); - p4.staticBufferId = 0; - } + EngineBaseObjDataTier& p4 = p3.next.back(); - PrimitiveType type; - if (p4.type == ENG_TRIANGLE_TYPE_TRIANGLES) - type = PRIMITIVE_TRIANGLES; - else - type = PRIMITIVE_TRIANGLE_STRIP; + p4.used = true; - p4.staticBufferId = m_device->CreateStaticObject(type, &p4.vertices[0], p4.vertices.size()); - } + p4.updateStaticBuffer = true; + m_updateStaticBuffers = true; if (globalUpdate) { @@ -998,68 +699,197 @@ bool CEngine::AddQuick(int objRank, const EngineObjLevel4& buffer, { for (int i = 0; i < static_cast<int>( p4.vertices.size() ); i++) { - m_objects[objRank].bboxMin.x = Math::Min(p4.vertices[i].coord.x, m_objects[objRank].bboxMin.x); - m_objects[objRank].bboxMin.y = Math::Min(p4.vertices[i].coord.y, m_objects[objRank].bboxMin.y); - m_objects[objRank].bboxMin.z = Math::Min(p4.vertices[i].coord.z, m_objects[objRank].bboxMin.z); - m_objects[objRank].bboxMax.x = Math::Max(p4.vertices[i].coord.x, m_objects[objRank].bboxMax.x); - m_objects[objRank].bboxMax.y = Math::Max(p4.vertices[i].coord.y, m_objects[objRank].bboxMax.y); - m_objects[objRank].bboxMax.z = Math::Max(p4.vertices[i].coord.z, m_objects[objRank].bboxMax.z); + m_baseObjects[baseObjRank].bboxMin.x = Math::Min(p4.vertices[i].coord.x, m_baseObjects[baseObjRank].bboxMin.x); + m_baseObjects[baseObjRank].bboxMin.y = Math::Min(p4.vertices[i].coord.y, m_baseObjects[baseObjRank].bboxMin.y); + m_baseObjects[baseObjRank].bboxMin.z = Math::Min(p4.vertices[i].coord.z, m_baseObjects[baseObjRank].bboxMin.z); + m_baseObjects[baseObjRank].bboxMax.x = Math::Max(p4.vertices[i].coord.x, m_baseObjects[baseObjRank].bboxMax.x); + m_baseObjects[baseObjRank].bboxMax.y = Math::Max(p4.vertices[i].coord.y, m_baseObjects[baseObjRank].bboxMax.y); + m_baseObjects[baseObjRank].bboxMax.z = Math::Max(p4.vertices[i].coord.z, m_baseObjects[baseObjRank].bboxMax.z); } - m_objects[objRank].radius = Math::Max(m_objects[objRank].bboxMin.Length(), - m_objects[objRank].bboxMax.Length()); + m_baseObjects[baseObjRank].radius = Math::Max(m_baseObjects[baseObjRank].bboxMin.Length(), + m_baseObjects[baseObjRank].bboxMax.Length()); } if (p4.type == ENG_TRIANGLE_TYPE_TRIANGLES) - m_objects[objRank].totalTriangles += p4.vertices.size() / 3; + m_baseObjects[baseObjRank].totalTriangles += p4.vertices.size() / 3; else if (p4.type == ENG_TRIANGLE_TYPE_SURFACE) - m_objects[objRank].totalTriangles += p4.vertices.size() - 2; - - return true; + m_baseObjects[baseObjRank].totalTriangles += p4.vertices.size() - 2; } -EngineObjLevel4* CEngine::FindTriangles(int objRank, const Material& material, - int state, std::string tex1Name, - std::string tex2Name, float min, float max) + +int CEngine::CreateObject() { - if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) ) + int i = 0; + for ( ; i < static_cast<int>( m_objects.size() ); i++) { - GetLogger()->Error("FindTriangles(): invalid object rank %d\n", objRank); - return nullptr; + if (! m_objects[i].used) + { + m_objects[i].LoadDefault(); + break; + } } - for (int l1 = 0; l1 < static_cast<int>( m_objectTree.size() ); l1++) + if (i == static_cast<int>( m_objects.size() )) + m_objects.push_back(EngineObject()); + + + m_objects[i].used = true; + + Math::Matrix mat; + mat.LoadIdentity(); + SetObjectTransform(i, mat); + + m_objects[i].drawWorld = true; + m_objects[i].distance = 0.0f; + m_objects[i].shadowRank = -1; + + return i; +} + +void CEngine::DeleteAllObjects() +{ + m_objects.clear(); + m_shadows.clear(); + + DeleteAllGroundSpots(); +} + +void CEngine::DeleteObject(int objRank) +{ + assert(objRank >= 0 && objRank < static_cast<int>( m_objects.size() )); + + // Mark object as deleted + m_objects[objRank].used = false; + + // Delete associated shadows + DeleteShadow(objRank); +} + +void CEngine::SetObjectBaseRank(int objRank, int baseObjRank) +{ + assert(objRank >= 0 && objRank < static_cast<int>( m_objects.size() )); + + m_objects[objRank].baseObjRank = baseObjRank; +} + +int CEngine::GetObjectBaseRank(int objRank) +{ + assert(objRank >= 0 && objRank < static_cast<int>( m_objects.size() )); + + return m_objects[objRank].baseObjRank; +} + +void CEngine::SetObjectType(int objRank, EngineObjectType type) +{ + assert(objRank >= 0 && objRank < static_cast<int>( m_objects.size() )); + + m_objects[objRank].type = type; +} + +EngineObjectType CEngine::GetObjectType(int objRank) +{ + assert(objRank >= 0 && objRank < static_cast<int>( m_objects.size() )); + + return m_objects[objRank].type; +} + + +void CEngine::SetObjectTransform(int objRank, const Math::Matrix& transform) +{ + assert(objRank >= 0 && objRank < static_cast<int>( m_objects.size() )); + + m_objects[objRank].transform = transform; +} + +void CEngine::GetObjectTransform(int objRank, Math::Matrix& transform) +{ + assert(objRank >= 0 && objRank < static_cast<int>( m_objects.size() )); + + transform = m_objects[objRank].transform; +} + +void CEngine::SetObjectDrawWorld(int objRank, bool draw) +{ + assert(objRank >= 0 && objRank < static_cast<int>( m_objects.size() )); + + m_objects[objRank].drawWorld = draw; +} + +void CEngine::SetObjectDrawFront(int objRank, bool draw) +{ + assert(objRank >= 0 && objRank < static_cast<int>( m_objects.size() )); + + m_objects[objRank].drawFront = draw; +} + +void CEngine::SetObjectTransparency(int objRank, float value) +{ + assert(objRank >= 0 && objRank < static_cast<int>( m_objects.size() )); + + m_objects[objRank].transparency = value; +} + +void CEngine::GetObjectBBox(int objRank, Math::Vector& min, Math::Vector& max) +{ + assert(objRank >= 0 && objRank < static_cast<int>( m_objects.size() )); + + int baseObjRank = m_objects[objRank].baseObjRank; + assert(baseObjRank >= 0 && baseObjRank < static_cast<int>(m_baseObjects.size())); + + min = m_baseObjects[baseObjRank].bboxMin; + max = m_baseObjects[baseObjRank].bboxMax; +} + + +int CEngine::GetObjectTotalTriangles(int objRank) +{ + assert(objRank >= 0 && objRank < static_cast<int>( m_objects.size() )); + + int baseObjRank = m_objects[objRank].baseObjRank; + assert(baseObjRank >= 0 && baseObjRank < static_cast<int>( m_baseObjects.size() )); + + return m_baseObjects[baseObjRank].totalTriangles; +} + +EngineBaseObjDataTier* CEngine::FindTriangles(int objRank, const Material& material, + int state, std::string tex1Name, + std::string tex2Name, float min, float max) +{ + assert(objRank >= 0 && objRank < static_cast<int>( m_objects.size() )); + + int baseObjRank = m_objects[objRank].baseObjRank; + assert(baseObjRank >= 0 && baseObjRank < static_cast<int>( m_baseObjects.size() )); + + for (int l2 = 0; l2 < static_cast<int>( m_baseObjects[baseObjRank].next.size() ); l2++) { - EngineObjLevel1& p1 = m_objectTree[l1]; - if (! p1.used) continue; + EngineBaseObjTexTier& p2 = m_baseObjects[baseObjRank].next[l2]; + if (! p2.used) + continue; - if (p1.tex1Name != tex1Name) continue; + if (p2.tex1Name != tex1Name) + continue; - for (int l2 = 0; l2 < static_cast<int>( p1.next.size() ); l2++) + for (int l3 = 0; l3 < static_cast<int>( p2.next.size() ); l3++) { - EngineObjLevel2& p2 = p1.next[l2]; - if (! p2.used) continue; + EngineBaseObjLODTier& p3 = p2.next[l3]; + if (! p3.used) + continue; - if (p2.objRank != objRank) continue; + if (p3.min != min || p3.max != max) + continue; - for (int l3 = 0; l3 < static_cast<int>( p2.next.size() ); l3++) + for (int l4 = 0; l4 < static_cast<int>( p3.next.size() ); l4++) { - EngineObjLevel3& p3 = p2.next[l3]; - if (! p3.used) continue; - - if (p3.min != min || p3.max != max) continue; - - for (int l4 = 0; l4 < static_cast<int>( p3.next.size() ); l4++) - { - EngineObjLevel4& p4 = p3.next[l4]; - if (! p4.used) continue; + EngineBaseObjDataTier& p4 = p3.next[l4]; + if (! p4.used) + continue; - if ( (p4.state & (~(ENG_RSTATE_DUAL_BLACK|ENG_RSTATE_DUAL_WHITE))) != state || - p4.material != material ) - continue; + if ( (p4.state & (~(ENG_RSTATE_DUAL_BLACK|ENG_RSTATE_DUAL_WHITE))) != state || + p4.material != material ) + continue; - return &p4; - } + return &p4; } } } @@ -1068,91 +898,86 @@ EngineObjLevel4* CEngine::FindTriangles(int objRank, const Material& material, } int CEngine::GetPartialTriangles(int objRank, float min, float max, float percent, int maxCount, - std::vector<EngineTriangle>& triangles) + std::vector<EngineTriangle>& triangles) { - if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) ) - { - GetLogger()->Error("GetPartialTriangles(): invalid object rank %d\n", objRank); - return 0; - } + assert(objRank >= 0 && objRank < static_cast<int>( m_objects.size() )); - int total = m_objects[objRank].totalTriangles; + int baseObjRank = m_objects[objRank].baseObjRank; + assert(baseObjRank >= 0 && baseObjRank < static_cast<int>( m_baseObjects.size() )); + + int total = m_baseObjects[baseObjRank].totalTriangles; int expectedCount = static_cast<int>(percent * total); triangles.reserve(Math::Min(maxCount, expectedCount)); int actualCount = 0; - for (int l1 = 0; l1 < static_cast<int>( m_objectTree.size() ); l1++) + for (int l2 = 0; l2 < static_cast<int>( m_baseObjects[baseObjRank].next.size() ); l2++) { - EngineObjLevel1& p1 = m_objectTree[l1]; - if (! p1.used) continue; + EngineBaseObjTexTier& p2 = m_baseObjects[baseObjRank].next[l2]; + if (! p2.used) + continue; - for (int l2 = 0; l2 < static_cast<int>( p1.next.size() ); l2++) + for (int l3 = 0; l3 < static_cast<int>( p2.next.size() ); l3++) { - EngineObjLevel2& p2 = p1.next[l2]; - if (! p2.used) continue; + EngineBaseObjLODTier& p3 = p2.next[l3]; + if (! p3.used) + continue; - if (p2.objRank != objRank) continue; + if (p3.min != min || p3.max != max) + continue; - for (int l3 = 0; l3 < static_cast<int>( p2.next.size() ); l3++) + for (int l4 = 0; l4 < static_cast<int>( p3.next.size() ); l4++) { - EngineObjLevel3& p3 = p2.next[l3]; - if (! p3.used) continue; - - if (p3.min != min || p3.max != max) continue; + EngineBaseObjDataTier& p4 = p3.next[l4]; + if (! p4.used) + continue; - for (int l4 = 0; l4 < static_cast<int>( p3.next.size() ); l4++) + if (p4.type == ENG_TRIANGLE_TYPE_TRIANGLES) { - EngineObjLevel4& p4 = p3.next[l4]; - if (! p4.used) continue; - - if (p4.type == ENG_TRIANGLE_TYPE_TRIANGLES) + for (int i = 0; i < static_cast<int>( p4.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 = p1.tex1Name; - t.tex2Name = p1.tex2Name; + 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; - triangles.push_back(t); + triangles.push_back(t); - ++actualCount; - } + ++actualCount; } - else if (p4.type == ENG_TRIANGLE_TYPE_SURFACE) + } + else if (p4.type == ENG_TRIANGLE_TYPE_SURFACE) + { + for (int i = 0; i < static_cast<int>( p4.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 = p1.tex1Name; - t.tex2Name = p1.tex2Name; + 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; - triangles.push_back(t); + triangles.push_back(t); - ++actualCount; - } + ++actualCount; } } } @@ -1179,20 +1004,22 @@ void CEngine::ChangeLOD() float oldTerrain = m_terrainVision * m_lastClippingDistance; float newTerrain = m_terrainVision * m_clippingDistance; - for (int l1 = 0; l1 < static_cast<int>( m_objectTree.size() ); l1++) + for (int baseObjRank = 0; baseObjRank < static_cast<int>( m_baseObjects.size() ); baseObjRank++) { - EngineObjLevel1& p1 = m_objectTree[l1]; - if (! p1.used) continue; + if (! m_baseObjects[baseObjRank].used) + continue; - for (int l2 = 0; l2 < static_cast<int>( p1.next.size() ); l2++) + for (int l2 = 0; l2 < static_cast<int>( m_baseObjects[baseObjRank].next.size() ); l2++) { - EngineObjLevel2& p2 = p1.next[l2]; - if (! p2.used) continue; + EngineBaseObjTexTier& p2 = m_baseObjects[baseObjRank].next[l2]; + if (! p2.used) + continue; for (int l3 = 0; l3 < static_cast<int>( p2.next.size() ); l3++) { - EngineObjLevel3& p3 = p2.next[l3]; - if (! p3.used) continue; + EngineBaseObjLODTier& p3 = p2.next[l3]; + if (! p3.used) + continue; if ( Math::IsEqual(p3.min, 0.0f ) && Math::IsEqual(p3.max, oldLimit[0]) ) @@ -1224,43 +1051,40 @@ void CEngine::ChangeLOD() m_lastClippingDistance = m_clippingDistance; } -bool CEngine::ChangeSecondTexture(int objRank, const std::string& tex2Name) +void CEngine::ChangeSecondTexture(int objRank, const std::string& tex2Name) { - for (int l1 = 0; l1 < static_cast<int>( m_objectTree.size() ); l1++) - { - EngineObjLevel1& p1 = m_objectTree[l1]; - if (! p1.used) continue; - - if (p1.tex2Name == tex2Name) continue; // already new - - for (int l2 = 0; l2 < static_cast<int>( p1.next.size() ); l2++) - { - EngineObjLevel2& p2 = p1.next[l2]; - if (! p2.used) continue; - - if (p2.objRank != objRank) continue; + assert(objRank >= 0 && objRank < static_cast<int>( m_objects.size() )); - EngineObjLevel1& newP1 = AddLevel1(p1.tex1Name, tex2Name); + int baseObjRank = m_objects[objRank].baseObjRank; + assert(baseObjRank >= 0 && baseObjRank < static_cast<int>( m_baseObjects.size() )); + + EngineBaseObject& p1 = m_baseObjects[baseObjRank]; - newP1.next.push_back(EngineObjLevel2(true, objRank)); + for (int l2 = 0; l2 < static_cast<int>( p1.next.size() ); l2++) + { + EngineBaseObjTexTier& p2 = p1.next[l2]; + if (! p2.used) + continue; - EngineObjLevel2& newP2 = newP1.next.back(); - newP2.next.swap(p2.next); + if (p2.tex2Name == tex2Name) + continue; // already new - p2.used = false; - } + EngineBaseObjTexTier& newP2 = AddLevel2(baseObjRank, p2.tex1Name, tex2Name); + newP2.next.swap(p2.next); + p2.used = false; } - return true; } -bool CEngine::ChangeTextureMapping(int objRank, const Material& mat, int state, - const std::string& tex1Name, const std::string& tex2Name, - float min, float max, EngineTextureMapping mode, - float au, float bu, float av, float bv) +void CEngine::ChangeTextureMapping(int objRank, const Material& mat, int state, + const std::string& tex1Name, const std::string& tex2Name, + float min, float max, EngineTextureMapping mode, + float au, float bu, float av, float bv) { - EngineObjLevel4* p4 = FindTriangles(objRank, mat, state, tex1Name, tex2Name, min, max); + assert(objRank >= 0 && objRank < static_cast<int>( m_objects.size() )); + + EngineBaseObjDataTier* p4 = FindTriangles(objRank, mat, state, tex1Name, tex2Name, min, max); if (p4 == nullptr) - return false; + return; int nb = p4->vertices.size(); @@ -1310,21 +1134,25 @@ bool CEngine::ChangeTextureMapping(int objRank, const Material& mat, int state, } } - return true; + UpdateStaticBuffer(*p4); } -bool CEngine::TrackTextureMapping(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, float min, float max, EngineTextureMapping mode, float pos, float factor, float tl, float ts, float tt) { - EngineObjLevel4* triangles = FindTriangles(objRank, mat, state, tex1Name, tex2Name, min, max); - if (triangles == nullptr) return false; + assert(objRank >= 0 && objRank < static_cast<int>( m_objects.size() )); + + EngineBaseObjDataTier* p4 = FindTriangles(objRank, mat, state, tex1Name, tex2Name, min, max); + if (p4 == nullptr) + return; - int tNum = triangles->vertices.size(); - if (tNum < 12 || tNum % 6 != 0) return false; + int tNum = p4->vertices.size(); + if (tNum < 12 || tNum % 6 != 0) + return; - std::vector<Gfx::VertexTex2>& vs = triangles->vertices; + std::vector<Gfx::VertexTex2>& vs = p4->vertices; while (pos < 0.0f) pos += 1.0f; // never negative! @@ -1402,17 +1230,17 @@ bool CEngine::TrackTextureMapping(int objRank, const Material& mat, int state, tBase += 6; } - return true; + UpdateStaticBuffer(*p4); } -bool CEngine::CreateShadow(int objRank) +void CEngine::CreateShadow(int objRank) { - if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) ) - return false; + assert(objRank >= 0 && objRank < static_cast<int>( m_objects.size() )); // Already allocated? - if (m_objects[objRank].shadowRank != -1) return true; + if (m_objects[objRank].shadowRank != -1) + return; int index = 0; for ( ; index < static_cast<int>( m_shadows.size() ); index++) @@ -1424,146 +1252,147 @@ bool CEngine::CreateShadow(int objRank) } } - m_shadows.push_back(EngineShadow()); + if (index == static_cast<int>( m_shadows.size() )) + m_shadows.push_back(EngineShadow()); m_shadows[index].used = true; m_shadows[index].objRank = objRank; m_shadows[index].height = 0.0f; m_objects[objRank].shadowRank = index; - - return true; } void CEngine::DeleteShadow(int objRank) { - if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) ) - return; + assert(objRank >= 0 && objRank < static_cast<int>( m_objects.size() )); - int i = m_objects[objRank].shadowRank; - if (i == -1) + int shadowRank = m_objects[objRank].shadowRank; + if (shadowRank == -1) return; - m_shadows[i].used = false; - m_shadows[i].objRank = -1; + assert(shadowRank >= 0 && shadowRank < static_cast<int>( m_shadows.size() )); + + m_shadows[shadowRank].used = false; + m_shadows[shadowRank].objRank = -1; m_objects[objRank].shadowRank = -1; } -bool CEngine::SetObjectShadowHide(int objRank, bool hide) +void CEngine::SetObjectShadowHide(int objRank, bool hide) { - if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) ) - return false; + assert(objRank >= 0 && objRank < static_cast<int>( m_objects.size() )); - int i = m_objects[objRank].shadowRank; - if (i == -1) - return false; + int shadowRank = m_objects[objRank].shadowRank; + if (shadowRank == -1) + return; - m_shadows[i].hide = hide; - return true; + assert(shadowRank >= 0 && shadowRank < static_cast<int>( m_shadows.size() )); + + m_shadows[shadowRank].hide = hide; } -bool CEngine::SetObjectShadowType(int objRank, EngineShadowType type) +void CEngine::SetObjectShadowType(int objRank, EngineShadowType type) { - if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) ) - return false; + assert(objRank >= 0 && objRank < static_cast<int>( m_objects.size() )); - int i = m_objects[objRank].shadowRank; - if (i == -1) - return false; + int shadowRank = m_objects[objRank].shadowRank; + if (shadowRank == -1) + return; - m_shadows[i].type = type; - return true; + assert(shadowRank >= 0 && shadowRank < static_cast<int>( m_shadows.size() )); + + m_shadows[shadowRank].type = type; } -bool CEngine::SetObjectShadowPos(int objRank, const Math::Vector& pos) +void CEngine::SetObjectShadowPos(int objRank, const Math::Vector& pos) { - if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) ) - return false; + assert(objRank >= 0 && objRank < static_cast<int>( m_objects.size() )); - int i = m_objects[objRank].shadowRank; - if (i == -1) - return false; + int shadowRank = m_objects[objRank].shadowRank; + if (shadowRank == -1) + return; - m_shadows[i].pos = pos; - return true; + assert(shadowRank >= 0 && shadowRank < static_cast<int>( m_shadows.size() )); + + m_shadows[shadowRank].pos = pos; } -bool CEngine::SetObjectShadowNormal(int objRank, const Math::Vector& normal) +void CEngine::SetObjectShadowNormal(int objRank, const Math::Vector& normal) { - if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) ) - return false; + assert(objRank >= 0 && objRank < static_cast<int>( m_objects.size() )); - int i = m_objects[objRank].shadowRank; - if (i == -1) - return false; + int shadowRank = m_objects[objRank].shadowRank; + if (shadowRank == -1) + return; - m_shadows[i].normal = normal; - return true; + assert(shadowRank >= 0 && shadowRank < static_cast<int>( m_shadows.size() )); + + m_shadows[shadowRank].normal = normal; } -bool CEngine::SetObjectShadowAngle(int objRank, float angle) +void CEngine::SetObjectShadowAngle(int objRank, float angle) { - if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) ) - return false; + assert(objRank >= 0 && objRank < static_cast<int>( m_objects.size() )); - int i = m_objects[objRank].shadowRank; - if (i == -1) - return false; + int shadowRank = m_objects[objRank].shadowRank; + if (shadowRank == -1) + return; - m_shadows[i].angle = angle; - return true; + assert(shadowRank >= 0 && shadowRank < static_cast<int>( m_shadows.size() )); + + m_shadows[shadowRank].angle = angle; } -bool CEngine::SetObjectShadowRadius(int objRank, float radius) +void CEngine::SetObjectShadowRadius(int objRank, float radius) { - if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) ) - return false; + assert(objRank >= 0 && objRank < static_cast<int>( m_objects.size() )); - int i = m_objects[objRank].shadowRank; - if (i == -1) - return false; + int shadowRank = m_objects[objRank].shadowRank; + if (shadowRank == -1) + return; - m_shadows[i].radius = radius; - return true; + assert(shadowRank >= 0 && shadowRank < static_cast<int>( m_shadows.size() )); + + m_shadows[shadowRank].radius = radius; } -bool CEngine::SetObjectShadowIntensity(int objRank, float intensity) +void CEngine::SetObjectShadowIntensity(int objRank, float intensity) { - if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) ) - return false; + assert(objRank >= 0 && objRank < static_cast<int>( m_objects.size() )); - int i = m_objects[objRank].shadowRank; - if (i == -1) - return false; + int shadowRank = m_objects[objRank].shadowRank; + if (shadowRank == -1) + return; - m_shadows[i].intensity = intensity; - return true; + assert(shadowRank >= 0 && shadowRank < static_cast<int>( m_shadows.size() )); + + m_shadows[shadowRank].intensity = intensity; } -bool CEngine::SetObjectShadowHeight(int objRank, float height) +void CEngine::SetObjectShadowHeight(int objRank, float height) { - if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) ) - return false; + assert(objRank >= 0 && objRank < static_cast<int>( m_objects.size() )); - int i = m_objects[objRank].shadowRank; - if (i == -1) - return false; + int shadowRank = m_objects[objRank].shadowRank; + if (shadowRank == -1) + return; - m_shadows[i].height = height; - return true; + assert(shadowRank >= 0 && shadowRank < static_cast<int>( m_shadows.size() )); + + m_shadows[shadowRank].height = height; } float CEngine::GetObjectShadowRadius(int objRank) { - if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) ) - return 0.0f; + assert(objRank >= 0 && objRank < static_cast<int>( m_objects.size() )); - int i = m_objects[objRank].shadowRank; - if (i == -1) + int shadowRank = m_objects[objRank].shadowRank; + if (shadowRank == -1) return 0.0f; - return m_shadows[i].radius; + assert(shadowRank >= 0 && shadowRank < static_cast<int>( m_shadows.size() )); + + return m_shadows[shadowRank].radius; } bool CEngine::GetHighlight(Math::Point &p1, Math::Point &p2) @@ -1585,21 +1414,26 @@ void CEngine::SetHighlightRank(int *rankList) bool CEngine::GetBBox2D(int objRank, Math::Point &min, Math::Point &max) { + assert(objRank >= 0 && objRank < static_cast<int>( m_objects.size() )); + min.x = 1000000.0f; min.y = 1000000.0f; max.x = -1000000.0f; max.y = -1000000.0f; + int baseObjRank = m_objects[objRank].baseObjRank; + assert(baseObjRank >= 0 && baseObjRank < static_cast<int>( m_baseObjects.size() )); + for (int i = 0; i < 8; i++) { Math::Vector p; - if ( i & (1<<0) ) p.x = m_objects[objRank].bboxMin.x; - else p.x = m_objects[objRank].bboxMax.x; - if ( i & (1<<1) ) p.y = m_objects[objRank].bboxMin.y; - else p.y = m_objects[objRank].bboxMax.y; - if ( i & (1<<2) ) p.z = m_objects[objRank].bboxMin.z; - else p.z = m_objects[objRank].bboxMax.z; + if ( i & (1<<0) ) p.x = m_baseObjects[baseObjRank].bboxMin.x; + else p.x = m_baseObjects[baseObjRank].bboxMax.x; + if ( i & (1<<1) ) p.y = m_baseObjects[baseObjRank].bboxMin.y; + else p.y = m_baseObjects[baseObjRank].bboxMax.y; + if ( i & (1<<2) ) p.z = m_baseObjects[baseObjRank].bboxMin.z; + else p.z = m_baseObjects[baseObjRank].bboxMax.z; Math::Vector pp; if (TransformPoint(pp, objRank, p)) @@ -1611,15 +1445,16 @@ bool CEngine::GetBBox2D(int objRank, Math::Point &min, Math::Point &max) } } - if ( min.x == 1000000.0f || - min.y == 1000000.0f || - max.x == -1000000.0f || - max.y == -1000000.0f ) return false; + if (min.x == 1000000.0f || + min.y == 1000000.0f || + max.x == -1000000.0f || + max.y == -1000000.0f) + return false; return true; } -void CEngine::FlushGroundSpot() +void CEngine::DeleteAllGroundSpots() { m_groundSpots.clear(); m_firstGroundSpot = true; @@ -1664,54 +1499,46 @@ int CEngine::CreateGroundSpot() void CEngine::DeleteGroundSpot(int rank) { + assert(rank >= 0 && rank < static_cast<int>( m_groundSpots.size() )); + m_groundSpots[rank].used = false; m_groundSpots[rank].pos = Math::Vector(0.0f, 0.0f, 0.0f); } -bool CEngine::SetObjectGroundSpotPos(int rank, const Math::Vector& pos) +void CEngine::SetObjectGroundSpotPos(int rank, const Math::Vector& pos) { - if ( rank < 0 || rank >= static_cast<int>( m_groundSpots.size() ) ) - return 0.0f; + assert(rank >= 0 && rank < static_cast<int>( m_groundSpots.size() )); m_groundSpots[rank].pos = pos; - return true; } -bool CEngine::SetObjectGroundSpotRadius(int rank, float radius) +void CEngine::SetObjectGroundSpotRadius(int rank, float radius) { - if ( rank < 0 || rank >= static_cast<int>( m_groundSpots.size() ) ) - return 0.0f; + assert(rank >= 0 && rank < static_cast<int>( m_groundSpots.size() )); m_groundSpots[rank].radius = radius; - return true; } -bool CEngine::SetObjectGroundSpotColor(int rank, const Color& color) +void CEngine::SetObjectGroundSpotColor(int rank, const Color& color) { - if ( rank < 0 || rank >= static_cast<int>( m_groundSpots.size() ) ) - return 0.0f; + assert(rank >= 0 && rank < static_cast<int>( m_groundSpots.size() )); m_groundSpots[rank].color = color; - return true; } -bool CEngine::SetObjectGroundSpotMinMax(int rank, float min, float max) +void CEngine::SetObjectGroundSpotMinMax(int rank, float min, float max) { - if ( rank < 0 || rank >= static_cast<int>( m_groundSpots.size() ) ) - return 0.0f; + assert(rank >= 0 && rank < static_cast<int>( m_groundSpots.size() )); m_groundSpots[rank].min = min; m_groundSpots[rank].max = max; - return true; } -bool CEngine::SetObjectGroundSpotSmooth(int rank, float smooth) +void CEngine::SetObjectGroundSpotSmooth(int rank, float smooth) { - if ( rank < 0 || rank >= static_cast<int>( m_groundSpots.size() ) ) - return 0.0f; + assert(rank >= 0 && rank < static_cast<int>( m_groundSpots.size() )); m_groundSpots[rank].smooth = smooth; - return true; } void CEngine::CreateGroundMark(Math::Vector pos, float radius, @@ -1758,51 +1585,45 @@ void CEngine::UpdateGeometry() if (! m_updateGeometry) return; - for (int i = 0; i < static_cast<int>( m_objects.size() ); i++) + for (int baseObjRank = 0; baseObjRank < static_cast<int>( m_baseObjects.size() ); baseObjRank++) { - m_objects[i].bboxMin.x = 0; - m_objects[i].bboxMin.y = 0; - m_objects[i].bboxMin.z = 0; - m_objects[i].bboxMax.x = 0; - m_objects[i].bboxMax.y = 0; - m_objects[i].bboxMax.z = 0; - m_objects[i].radius = 0; - } + EngineBaseObject &p1 = m_baseObjects[baseObjRank]; + if (! p1.used) + continue; - for (int l1 = 0; l1 < static_cast<int>( m_objectTree.size() ); l1++) - { - EngineObjLevel1& p1 = m_objectTree[l1]; - if (! p1.used) continue; + p1.bboxMin.LoadZero(); + p1.bboxMax.LoadZero(); + p1.radius = 0; for (int l2 = 0; l2 < static_cast<int>( p1.next.size() ); l2++) { - EngineObjLevel2& p2 = p1.next[l2]; - if (! p2.used) continue; + EngineBaseObjTexTier& p2 = p1.next[l2]; + if (! p2.used) + continue; for (int l3 = 0; l3 < static_cast<int>( p2.next.size() ); l3++) { - EngineObjLevel3& p3 = p2.next[l3]; - if (! p3.used) continue; + EngineBaseObjLODTier& p3 = p2.next[l3]; + if (! p3.used) + continue; for (int l4 = 0; l4 < static_cast<int>( p3.next.size() ); l4++) { - EngineObjLevel4& p4 = p3.next[l4]; - if (! p4.used) continue; - - int objRank = p2.objRank; + EngineBaseObjDataTier& p4 = p3.next[l4]; + if (! p4.used) + continue; for (int i = 0; i < static_cast<int>( p4.vertices.size() ); i++) { - m_objects[objRank].bboxMin.x = Math::Min(p4.vertices[i].coord.x, m_objects[objRank].bboxMin.x); - m_objects[objRank].bboxMin.y = Math::Min(p4.vertices[i].coord.y, m_objects[objRank].bboxMin.y); - m_objects[objRank].bboxMin.z = Math::Min(p4.vertices[i].coord.z, m_objects[objRank].bboxMin.z); - m_objects[objRank].bboxMax.x = Math::Max(p4.vertices[i].coord.x, m_objects[objRank].bboxMax.x); - m_objects[objRank].bboxMax.y = Math::Max(p4.vertices[i].coord.y, m_objects[objRank].bboxMax.y); - m_objects[objRank].bboxMax.z = Math::Max(p4.vertices[i].coord.z, m_objects[objRank].bboxMax.z); + 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); } - m_objects[objRank].radius = Math::Max(m_objects[objRank].bboxMin.Length(), - m_objects[objRank].bboxMax.Length()); + p1.radius = Math::Max(p1.bboxMin.Length(), p1.bboxMax.Length()); } } } @@ -1811,46 +1632,57 @@ void CEngine::UpdateGeometry() m_updateGeometry = false; } -void CEngine::UpdateStaticObjects() +void CEngine::UpdateStaticBuffer(EngineBaseObjDataTier& p4) +{ + PrimitiveType type; + if (p4.type == ENG_TRIANGLE_TYPE_TRIANGLES) + type = PRIMITIVE_TRIANGLES; + else + type = PRIMITIVE_TRIANGLE_STRIP; + + if (p4.staticBufferId == 0) + p4.staticBufferId = m_device->CreateStaticBuffer(type, &p4.vertices[0], p4.vertices.size()); + else + m_device->UpdateStaticBuffer(p4.staticBufferId, type, &p4.vertices[0], p4.vertices.size()); + + p4.updateStaticBuffer = false; +} + +void CEngine::UpdateStaticBuffers() { - if (!m_updateStaticObjects) + if (!m_updateStaticBuffers) return; - for (int l1 = 0; l1 < static_cast<int>( m_objectTree.size() ); l1++) + m_updateStaticBuffers = false; + + for (int baseObjRank = 0; baseObjRank < static_cast<int>( m_baseObjects.size() ); baseObjRank++) { - EngineObjLevel1& p1 = m_objectTree[l1]; - if (! p1.used) continue; + EngineBaseObject& p1 = m_baseObjects[baseObjRank]; + if (! p1.used) + continue; for (int l2 = 0; l2 < static_cast<int>( p1.next.size() ); l2++) { - EngineObjLevel2& p2 = p1.next[l2]; - if (! p2.used) continue; - - int objRank = p2.objRank; - - if (!m_objects[objRank].staticBuffer) + EngineBaseObjTexTier& p2 = p1.next[l2]; + if (! p2.used) continue; for (int l3 = 0; l3 < static_cast<int>( p2.next.size() ); l3++) { - EngineObjLevel3& p3 = p2.next[l3]; - if (! p3.used) continue; + EngineBaseObjLODTier& p3 = p2.next[l3]; + if (! p3.used) + continue; for (int l4 = 0; l4 < static_cast<int>( p3.next.size() ); l4++) { - EngineObjLevel4& p4 = p3.next[l4]; - if (! p4.used) continue; - - if (p4.staticBufferId != 0) + EngineBaseObjDataTier& p4 = p3.next[l4]; + if (! p4.used) continue; - PrimitiveType type; - if (p4.type == ENG_TRIANGLE_TYPE_TRIANGLES) - type = PRIMITIVE_TRIANGLES; - else - type = PRIMITIVE_TRIANGLE_STRIP; + if (! p4.updateStaticBuffer) + continue; - p4.staticBufferId = m_device->CreateStaticObject(type, &p4.vertices[0], p4.vertices.size()); + UpdateStaticBuffer(p4); } } } @@ -1861,11 +1693,16 @@ void CEngine::Update() { ComputeDistance(); UpdateGeometry(); - UpdateStaticObjects(); + UpdateStaticBuffers(); } bool CEngine::DetectBBox(int objRank, Math::Point mouse) { + assert(objRank >= 0 && objRank < static_cast<int>(m_objects.size())); + + int baseObjRank = m_objects[objRank].baseObjRank; + assert(baseObjRank >= 0 && baseObjRank < static_cast<int>(m_baseObjects.size())); + Math::Point min, max; min.x = 1000000.0f; min.y = 1000000.0f; @@ -1876,12 +1713,12 @@ bool CEngine::DetectBBox(int objRank, Math::Point mouse) { Math::Vector p; - if ( i & (1<<0) ) p.x = m_objects[objRank].bboxMin.x; - else p.x = m_objects[objRank].bboxMax.x; - if ( i & (1<<1) ) p.y = m_objects[objRank].bboxMin.y; - else p.y = m_objects[objRank].bboxMax.y; - if ( i & (1<<2) ) p.z = m_objects[objRank].bboxMin.z; - else p.z = m_objects[objRank].bboxMax.z; + if ( i & (1<<0) ) p.x = m_baseObjects[baseObjRank].bboxMin.x; + else p.x = m_baseObjects[baseObjRank].bboxMax.x; + if ( i & (1<<1) ) p.y = m_baseObjects[baseObjRank].bboxMin.y; + else p.y = m_baseObjects[baseObjRank].bboxMax.y; + if ( i & (1<<2) ) p.z = m_baseObjects[baseObjRank].bboxMin.z; + else p.z = m_baseObjects[baseObjRank].bboxMax.z; Math::Vector pp; if ( TransformPoint(pp, objRank, p) ) @@ -1904,41 +1741,54 @@ int CEngine::DetectObject(Math::Point mouse) float min = 1000000.0f; int nearest = -1; - for (int l1 = 0; l1 < static_cast<int>( m_objectTree.size() ); l1++) + for (int objRank = 0; objRank < static_cast<int>( m_objects.size() ); objRank++) { - EngineObjLevel1& p1 = m_objectTree[l1]; - if (! p1.used) continue; + if (! m_objects[objRank].used) + continue; - for (int l2 = 0; l2 < static_cast<int>( p1.next.size() ); l2++) - { - EngineObjLevel2& p2 = p1.next[l2]; - if (! p2.used) continue; + if (m_objects[objRank].type == ENG_OBJTYPE_TERRAIN) + continue; + + if (! DetectBBox(objRank, mouse)) + continue; + + int baseObjRank = m_objects[objRank].baseObjRank; + assert(baseObjRank >= 0 && baseObjRank < static_cast<int>(m_baseObjects.size())); - if (m_objects[p2.objRank].type == ENG_OBJTYPE_TERRAIN) continue; + EngineBaseObject& p1 = m_baseObjects[baseObjRank]; + if (! p1.used) + continue; - if (! DetectBBox(p2.objRank, mouse)) continue; + for (int l2 = 0; l2 < static_cast<int>( p1.next.size() ); l2++) + { + EngineBaseObjTexTier& p2 = p1.next[l2]; + if (! p2.used) + continue; for (int l3 = 0; l3 < static_cast<int>( p2.next.size() ); l3++) { - EngineObjLevel3& p3 = p2.next[l3]; - if (! p3.used) continue; + EngineBaseObjLODTier& p3 = p2.next[l3]; + if (! p3.used) + continue; - if (p3.min != 0.0f) continue; // LOD B or C? + if (p3.min != 0.0f) + continue; // LOD B or C? for (int l4 = 0; l4 < static_cast<int>( p3.next.size() ); l4++) { - EngineObjLevel4& p4 = p3.next[l4]; - if (! p4.used) continue; + EngineBaseObjDataTier& p4 = p3.next[l4]; + if (! p4.used) + continue; if (p4.type == ENG_TRIANGLE_TYPE_TRIANGLES) { for (int i = 0; i < static_cast<int>( p4.vertices.size() ); i += 3) { float dist = 0.0f; - if (DetectTriangle(mouse, &p4.vertices[i], p2.objRank, dist) && dist < min) + if (DetectTriangle(mouse, &p4.vertices[i], objRank, dist) && dist < min) { min = dist; - nearest = p2.objRank; + nearest = objRank; } } } @@ -1947,10 +1797,10 @@ int CEngine::DetectObject(Math::Point mouse) for (int i = 0; i < static_cast<int>( p4.vertices.size() ) - 2; i += 1) { float dist = 0.0f; - if (DetectTriangle(mouse, &p4.vertices[i], p2.objRank, dist) && dist < min) + if (DetectTriangle(mouse, &p4.vertices[i], objRank, dist) && dist < min) { min = dist; - nearest = p2.objRank; + nearest = objRank; } } } @@ -1964,6 +1814,8 @@ int CEngine::DetectObject(Math::Point mouse) bool CEngine::DetectTriangle(Math::Point mouse, VertexTex2* triangle, int objRank, float& dist) { + assert(objRank >= 0 && objRank < static_cast<int>(m_objects.size())); + Math::Vector p2D[3], p3D; for (int i = 0; i < 3; i++) @@ -1976,18 +1828,25 @@ bool CEngine::DetectTriangle(Math::Point mouse, VertexTex2* triangle, int objRan return false; } - if ( mouse.x < p2D[0].x && - mouse.x < p2D[1].x && - mouse.x < p2D[2].x ) return false; - if ( mouse.x > p2D[0].x && - mouse.x > p2D[1].x && - mouse.x > p2D[2].x ) return false; - if ( mouse.y < p2D[0].y && - mouse.y < p2D[1].y && - mouse.y < p2D[2].y ) return false; - if ( mouse.y > p2D[0].y && - mouse.y > p2D[1].y && - mouse.y > p2D[2].y ) return false; + if (mouse.x < p2D[0].x && + mouse.x < p2D[1].x && + mouse.x < p2D[2].x) + return false; + + if (mouse.x > p2D[0].x && + mouse.x > p2D[1].x && + mouse.x > p2D[2].x) + return false; + + if (mouse.y < p2D[0].y && + mouse.y < p2D[1].y && + mouse.y < p2D[2].y) + return false; + + if (mouse.y > p2D[0].y && + mouse.y > p2D[1].y && + mouse.y > p2D[2].y) + return false; Math::Point a, b, c; a.x = p2D[0].x; @@ -2007,7 +1866,12 @@ bool CEngine::DetectTriangle(Math::Point mouse, VertexTex2* triangle, int objRan //! Use only after world transform already set bool CEngine::IsVisible(int objRank) { - float radius = m_objects[objRank].radius; + assert(objRank >= 0 && objRank < static_cast<int>(m_objects.size())); + + int baseObjRank = m_objects[objRank].baseObjRank; + assert(baseObjRank >= 0 && baseObjRank < static_cast<int>(m_baseObjects.size())); + + float radius = m_baseObjects[baseObjRank].radius; Math::Vector center(0.0f, 0.0f, 0.0f); if (m_device->ComputeSphereVisibility(center, radius) == Gfx::FRUSTUM_PLANE_ALL) { @@ -2016,15 +1880,18 @@ bool CEngine::IsVisible(int objRank) } m_objects[objRank].visible = false; - return true; + return false; } bool CEngine::TransformPoint(Math::Vector& p2D, int objRank, Math::Vector p3D) { + assert(objRank >= 0 && objRank < static_cast<int>(m_objects.size())); + p3D = Math::Transform(m_objects[objRank].transform, p3D); p3D = Math::Transform(m_matView, p3D); - if (p3D.z < 2.0f) return false; // behind? + if (p3D.z < 2.0f) + return false; // behind? p2D.x = (p3D.x/p3D.z)*m_matProj.Get(1,1); p2D.y = (p3D.y/p3D.z)*m_matProj.Get(2,2); @@ -2387,42 +2254,49 @@ bool CEngine::LoadAllTextures() bool ok = true; - for (int l1 = 0; l1 < static_cast<int>( m_objectTree.size() ); l1++) + for (int objRank = 0; objRank < static_cast<int>( m_objects.size() ); objRank++) { - EngineObjLevel1& p1 = m_objectTree[l1]; - if (! p1.used) continue; + if (! m_objects[objRank].used) + continue; bool terrain = false; + if (m_objects[objRank].type == ENG_OBJTYPE_TERRAIN) + terrain = true; - for (int l2 = 0; l2 < static_cast<int>( p1.next.size() ); l2++) - { - EngineObjLevel2& p2 = p1.next[l2]; - if (! p2.used) continue; + int baseObjRank = m_objects[objRank].baseObjRank; + assert(baseObjRank >= 0 && baseObjRank < static_cast<int>( m_baseObjects.size() )); - if (m_objects[p2.objRank].type == ENG_OBJTYPE_TERRAIN) - terrain = true; - } + EngineBaseObject& p1 = m_baseObjects[baseObjRank]; + if (! p1.used) + continue; - if (! p1.tex1Name.empty()) + for (int l2 = 0; l2 < static_cast<int>( p1.next.size() ); l2++) { - if (terrain) - p1.tex1 = LoadTexture(p1.tex1Name, m_terrainTexParams); - else - p1.tex1 = LoadTexture(p1.tex1Name); + EngineBaseObjTexTier& p2 = p1.next[l2]; + if (! p2.used) + continue; - if (! p1.tex1.Valid()) - ok = false; - } + if (! p2.tex1Name.empty()) + { + if (terrain) + p2.tex1 = LoadTexture(p2.tex1Name, m_terrainTexParams); + else + p2.tex1 = LoadTexture(p2.tex1Name); - if (! p1.tex2Name.empty()) - { - if (terrain) - p1.tex2 = LoadTexture(p1.tex2Name, m_terrainTexParams); - else - p1.tex2 = LoadTexture(p1.tex2Name); + if (! p2.tex1.Valid()) + ok = false; + } + + if (! p2.tex2Name.empty()) + { + if (terrain) + p2.tex2 = LoadTexture(p2.tex2Name, m_terrainTexParams); + else + p2.tex2 = LoadTexture(p2.tex2Name); - if (! p1.tex2.Valid()) - ok = false; + if (! p2.tex2.Valid()) + ok = false; + } } } @@ -2438,7 +2312,8 @@ bool IsExcludeColor(Math::Point *exclude, int x, int y) if ( x >= static_cast<int>(exclude[i+0].x*256.0f) && x < static_cast<int>(exclude[i+1].x*256.0f) && y >= static_cast<int>(exclude[i+0].y*256.0f) && - y < static_cast<int>(exclude[i+1].y*256.0f) ) return true; // exclude + y < static_cast<int>(exclude[i+1].y*256.0f) ) + return true; // exclude i += 2; } @@ -2454,12 +2329,13 @@ bool CEngine::ChangeTextureColor(const std::string& texName, Math::Point ts, Math::Point ti, Math::Point *exclude, float shift, bool hsv) { - if ( colorRef1.r == colorNew1.r && - colorRef1.g == colorNew1.g && - colorRef1.b == colorNew1.b && - colorRef2.r == colorNew2.r && - colorRef2.g == colorNew2.g && - colorRef2.b == colorNew2.b ) return true; + if (colorRef1.r == colorNew1.r && + colorRef1.g == colorNew1.g && + colorRef1.b == colorNew1.b && + colorRef2.r == colorNew2.r && + colorRef2.g == colorNew2.g && + colorRef2.b == colorNew2.b) + return true; DeleteTexture(texName); @@ -2494,7 +2370,8 @@ bool CEngine::ChangeTextureColor(const std::string& texName, { for (int x = sx; x < ex; x++) { - if (exclude != nullptr && IsExcludeColor(exclude, x,y) ) continue; + if (exclude != nullptr && IsExcludeColor(exclude, x,y) ) + continue; Color color = img.GetPixel(Math::IntPoint(x, y)); @@ -3124,7 +3001,8 @@ void CEngine::ApplyChange() viewport, and renders the scene. */ void CEngine::Render() { - if (! m_render) return; + if (! m_render) + return; m_statisticTriangle = 0; m_lastState = -1; @@ -3187,35 +3065,44 @@ void CEngine::Draw3DScene() { m_lightMan->UpdateDeviceLights(ENG_OBJTYPE_TERRAIN); - for (int l1 = 0; l1 < static_cast<int>( m_objectTree.size() ); l1++) + for (int objRank = 0; objRank < static_cast<int>(m_objects.size()); objRank++) { - EngineObjLevel1& p1 = m_objectTree[l1]; - if (! p1.used) continue; + if (! m_objects[objRank].used) + continue; - // Should be loaded by now - SetTexture(p1.tex1, 0); - SetTexture(p1.tex2, 1); + if (m_objects[objRank].type != ENG_OBJTYPE_TERRAIN) + continue; - for (int l2 = 0; l2 < static_cast<int>( p1.next.size() ); l2++) - { - EngineObjLevel2& p2 = p1.next[l2]; - if (! p2.used) continue; + if (! m_objects[objRank].drawWorld) + continue; - int objRank = p2.objRank; - if (m_objects[objRank].type != ENG_OBJTYPE_TERRAIN) - continue; - if (! m_objects[objRank].drawWorld) - continue; + m_device->SetTransform(TRANSFORM_WORLD, m_objects[objRank].transform); - m_device->SetTransform(TRANSFORM_WORLD, m_objects[objRank].transform); + if (! IsVisible(objRank)) + continue; + + int baseObjRank = m_objects[objRank].baseObjRank; + assert(baseObjRank >= 0 && baseObjRank < static_cast<int>( m_baseObjects.size() )); + + EngineBaseObject& p1 = m_baseObjects[baseObjRank]; + if (! p1.used) + continue; - if (! IsVisible(objRank)) + for (int l2 = 0; l2 < static_cast<int>( p1.next.size() ); l2++) + { + EngineBaseObjTexTier& p2 = p1.next[l2]; + if (! p2.used) continue; + // Should be loaded by now + SetTexture(p2.tex1, 0); + SetTexture(p2.tex2, 1); + for (int l3 = 0; l3 < static_cast<int>( p2.next.size() ); l3++) { - EngineObjLevel3& p3 = p2.next[l3]; - if (! p3.used) continue; + EngineBaseObjLODTier& p3 = p2.next[l3]; + if (! p3.used) + continue; if ( m_objects[objRank].distance < p3.min || m_objects[objRank].distance >= p3.max ) @@ -3223,13 +3110,14 @@ void CEngine::Draw3DScene() for (int l4 = 0; l4 < static_cast<int>( p3.next.size() ); l4++) { - EngineObjLevel4& p4 = p3.next[l4]; - if (! p4.used) continue; + EngineBaseObjDataTier& p4 = p3.next[l4]; + if (! p4.used) + continue; SetMaterial(p4.material); SetState(p4.state); - DrawObject(p4, m_objects[objRank].staticBuffer); + DrawObject(p4); } } } @@ -3247,47 +3135,56 @@ void CEngine::Draw3DScene() bool transparent = false; - for (int l1 = 0; l1 < static_cast<int>( m_objectTree.size() ); l1++) + for (int objRank = 0; objRank < static_cast<int>(m_objects.size()); objRank++) { - EngineObjLevel1& p1 = m_objectTree[l1]; - if (! p1.used) continue; + if (! m_objects[objRank].used) + continue; - // Should be loaded by now - SetTexture(p1.tex1, 0); - SetTexture(p1.tex2, 1); + if (m_objects[objRank].type == ENG_OBJTYPE_TERRAIN) + continue; - for (int l2 = 0; l2 < static_cast<int>( p1.next.size() ); l2++) - { - EngineObjLevel2& p2 = p1.next[l2]; - if (! p2.used) continue; + if (! m_objects[objRank].drawWorld) + continue; - int objRank = p2.objRank; + m_device->SetTransform(TRANSFORM_WORLD, m_objects[objRank].transform); - if (m_shadowVisible && m_objects[objRank].type == ENG_OBJTYPE_TERRAIN) - continue; + if (! IsVisible(objRank)) + continue; - if (! m_objects[objRank].drawWorld) - continue; + int baseObjRank = m_objects[objRank].baseObjRank; + assert(baseObjRank >= 0 && baseObjRank < static_cast<int>( m_baseObjects.size() )); - m_device->SetTransform(TRANSFORM_WORLD, m_objects[objRank].transform); + EngineBaseObject& p1 = m_baseObjects[baseObjRank]; + if (! p1.used) + continue; - if (! IsVisible(objRank)) + m_lightMan->UpdateDeviceLights(m_objects[objRank].type); + + for (int l2 = 0; l2 < static_cast<int>( p1.next.size() ); l2++) + { + EngineBaseObjTexTier& p2 = p1.next[l2]; + if (! p2.used) continue; - m_lightMan->UpdateDeviceLights(m_objects[objRank].type); + // Should be loaded by now + SetTexture(p2.tex1, 0); + SetTexture(p2.tex2, 1); for (int l3 = 0; l3 < static_cast<int>( p2.next.size() ); l3++) { - EngineObjLevel3& p3 = p2.next[l3]; - if (! p3.used) continue; + EngineBaseObjLODTier& p3 = p2.next[l3]; + if (! p3.used) + continue; if ( m_objects[objRank].distance < p3.min || - m_objects[objRank].distance >= p3.max ) continue; + m_objects[objRank].distance >= p3.max ) + continue; for (int l4 = 0; l4 < static_cast<int>( p3.next.size() ); l4++) { - EngineObjLevel4& p4 = p3.next[l4]; - if (! p4.used) continue; + EngineBaseObjDataTier& p4 = p3.next[l4]; + if (! p4.used) + continue; if (m_objects[objRank].transparency != 0.0f) // transparent ? { @@ -3298,7 +3195,7 @@ void CEngine::Draw3DScene() SetMaterial(p4.material); SetState(p4.state); - DrawObject(p4, m_objects[objRank].staticBuffer); + DrawObject(p4); } } } @@ -3311,47 +3208,56 @@ void CEngine::Draw3DScene() int tState = ENG_RSTATE_TTEXTURE_BLACK | ENG_RSTATE_2FACE; Color tColor = Color(68.0f / 255.0f, 68.0f / 255.0f, 68.0f / 255.0f, 68.0f / 255.0f); - for (int l1 = 0; l1 < static_cast<int>( m_objectTree.size() ); l1++) + for (int objRank = 0; objRank < static_cast<int>(m_objects.size()); objRank++) { - EngineObjLevel1& p1 = m_objectTree[l1]; - if (! p1.used) continue; + if (! m_objects[objRank].used) + continue; - // Should be loaded by now - SetTexture(p1.tex1, 0); - SetTexture(p1.tex2, 1); + if (m_objects[objRank].type == ENG_OBJTYPE_TERRAIN) + continue; - for (int l2 = 0; l2 < static_cast<int>( p1.next.size() ); l2++) - { - EngineObjLevel2& p2 = p1.next[l2]; - if (! p2.used) continue; + if (! m_objects[objRank].drawWorld) + continue; - int objRank = p2.objRank; + m_device->SetTransform(TRANSFORM_WORLD, m_objects[objRank].transform); - if (m_shadowVisible && m_objects[objRank].type == ENG_OBJTYPE_TERRAIN) - continue; + if (! IsVisible(objRank)) + continue; - if (! m_objects[objRank].drawWorld) - continue; + int baseObjRank = m_objects[objRank].baseObjRank; + assert(baseObjRank >= 0 && baseObjRank < static_cast<int>( m_baseObjects.size() )); + + EngineBaseObject& p1 = m_baseObjects[baseObjRank]; + if (! p1.used) + continue; - m_device->SetTransform(TRANSFORM_WORLD, m_objects[objRank].transform); + m_lightMan->UpdateDeviceLights(m_objects[objRank].type); - if (! IsVisible(objRank)) + for (int l2 = 0; l2 < static_cast<int>( p1.next.size() ); l2++) + { + EngineBaseObjTexTier& p2 = p1.next[l2]; + if (! p2.used) continue; - m_lightMan->UpdateDeviceLights(m_objects[objRank].type); + // Should be loaded by now + SetTexture(p2.tex1, 0); + SetTexture(p2.tex2, 1); for (int l3 = 0; l3 < static_cast<int>( p2.next.size() ); l3++) { - EngineObjLevel3& p3 = p2.next[l3]; - if (! p3.used) continue; + EngineBaseObjLODTier& p3 = p2.next[l3]; + if (! p3.used) + continue; - if ( m_objects[objRank].distance < p3.min || - m_objects[objRank].distance >= p3.max ) continue; + if (m_objects[objRank].distance < p3.min || + m_objects[objRank].distance >= p3.max) + continue; for (int l4 = 0; l4 < static_cast<int>( p3.next.size() ); l4++) { - EngineObjLevel4& p4 = p3.next[l4]; - if (! p4.used) continue; + EngineBaseObjDataTier& p4 = p3.next[l4]; + if (! p4.used) + continue; if (m_objects[objRank].transparency == 0.0f) continue; @@ -3359,7 +3265,7 @@ void CEngine::Draw3DScene() SetMaterial(p4.material); SetState(tState, tColor); - DrawObject(p4, m_objects[objRank].staticBuffer); + DrawObject(p4); } } } @@ -3388,28 +3294,28 @@ void CEngine::Draw3DScene() if (! m_overFront) DrawOverColor(); // draws the foreground color } -void CEngine::DrawObject(const EngineObjLevel4& obj, bool staticBuffer) +void CEngine::DrawObject(const EngineBaseObjDataTier& p4) { - if (staticBuffer) + if (p4.staticBufferId != 0) { - m_device->DrawStaticObject(obj.staticBufferId); + m_device->DrawStaticBuffer(p4.staticBufferId); - if (obj.type == ENG_TRIANGLE_TYPE_TRIANGLES) - m_statisticTriangle += obj.vertices.size() / 3; + if (p4.type == ENG_TRIANGLE_TYPE_TRIANGLES) + m_statisticTriangle += p4.vertices.size() / 3; else - m_statisticTriangle += obj.vertices.size() - 2; + m_statisticTriangle += p4.vertices.size() - 2; } else { - if (obj.type == ENG_TRIANGLE_TYPE_TRIANGLES) + if (p4.type == ENG_TRIANGLE_TYPE_TRIANGLES) { - m_device->DrawPrimitive(PRIMITIVE_TRIANGLES, &obj.vertices[0], obj.vertices.size()); - m_statisticTriangle += obj.vertices.size() / 3; + m_device->DrawPrimitive(PRIMITIVE_TRIANGLES, &p4.vertices[0], p4.vertices.size()); + m_statisticTriangle += p4.vertices.size() / 3; } else { - m_device->DrawPrimitive(PRIMITIVE_TRIANGLE_STRIP, &obj.vertices[0], obj.vertices.size() ); - m_statisticTriangle += obj.vertices.size() - 2; + m_device->DrawPrimitive(PRIMITIVE_TRIANGLE_STRIP, &p4.vertices[0], p4.vertices.size() ); + m_statisticTriangle += p4.vertices.size() - 2; } } } @@ -3459,52 +3365,60 @@ void CEngine::DrawInterface() m_device->SetTransform(TRANSFORM_VIEW, m_matView); - for (int l1 = 0; l1 < static_cast<int>( m_objectTree.size() ); l1++) + for (int objRank = 0; objRank < static_cast<int>(m_objects.size()); objRank++) { - EngineObjLevel1& p1 = m_objectTree[l1]; - if (! p1.used) continue; + if (! m_objects[objRank].used) + continue; - // Should be loaded by now - SetTexture(p1.tex1, 0); - SetTexture(p1.tex2, 1); + if (m_shadowVisible && m_objects[objRank].type == ENG_OBJTYPE_TERRAIN) + continue; - for (int l2 = 0; l2 < static_cast<int>( p1.next.size() ); l2++) - { - EngineObjLevel2& p2 = p1.next[l2]; - if (! p2.used) continue; + if (! m_objects[objRank].drawFront) + continue; - int objRank = p2.objRank; + m_device->SetTransform(TRANSFORM_WORLD, m_objects[objRank].transform); - if (m_shadowVisible && m_objects[objRank].type == ENG_OBJTYPE_TERRAIN) - continue; + if (! IsVisible(objRank)) + continue; - if (! m_objects[objRank].drawFront) - continue; + int baseObjRank = m_objects[objRank].baseObjRank; + assert(baseObjRank >= 0 && baseObjRank < static_cast<int>( m_baseObjects.size() )); - m_device->SetTransform(TRANSFORM_WORLD, m_objects[objRank].transform); + EngineBaseObject& p1 = m_baseObjects[baseObjRank]; + if (! p1.used) + continue; - if (! IsVisible(objRank)) + m_lightMan->UpdateDeviceLights(m_objects[objRank].type); + + for (int l2 = 0; l2 < static_cast<int>( p1.next.size() ); l2++) + { + EngineBaseObjTexTier& p2 = p1.next[l2]; + if (! p2.used) continue; - m_lightMan->UpdateDeviceLights(m_objects[objRank].type); + SetTexture(p2.tex1, 0); + SetTexture(p2.tex2, 1); for (int l3 = 0; l3 < static_cast<int>( p2.next.size() ); l3++) { - EngineObjLevel3& p3 = p2.next[l3]; - if (! p3.used) continue; + EngineBaseObjLODTier& p3 = p2.next[l3]; + if (! p3.used) + continue; - if ( m_objects[objRank].distance < p3.min || - m_objects[objRank].distance >= p3.max ) continue; + if (m_objects[objRank].distance < p3.min || + m_objects[objRank].distance >= p3.max) + continue; for (int l4 = 0; l4 < static_cast<int>( p3.next.size() ); l4++) { - EngineObjLevel4& p4 = p3.next[l4]; - if (! p4.used) continue; + EngineBaseObjDataTier& p4 = p3.next[l4]; + if (! p4.used) + continue; SetMaterial(p4.material); SetState(p4.state); - DrawObject(p4, m_objects[objRank].staticBuffer); + DrawObject(p4); } } } @@ -3537,7 +3451,8 @@ void CEngine::UpdateGroundSpotTextures() m_groundMark.drawPos.x == m_groundMark.pos.x && m_groundMark.drawPos.z == m_groundMark.pos.z && m_groundMark.drawRadius == m_groundMark.radius && - m_groundMark.drawIntensity == m_groundMark.intensity) return; + m_groundMark.drawIntensity == m_groundMark.intensity) + return; for (int s = 0; s < 16; s++) { @@ -3612,11 +3527,12 @@ void CEngine::UpdateGroundSpotTextures() // Draw the new shadows. for (int i = 0; i < static_cast<int>( m_groundSpots.size() ); i++) { - if ( m_groundSpots[i].used == false || - m_groundSpots[i].radius == 0.0f ) continue; + if (m_groundSpots[i].used == false || + m_groundSpots[i].radius == 0.0f) + continue; - if ( m_groundSpots[i].min == 0.0f && - m_groundSpots[i].max == 0.0f ) + if (m_groundSpots[i].min == 0.0f && + m_groundSpots[i].max == 0.0f) { dot = static_cast<int>(m_groundSpots[i].radius/2.0f); @@ -3635,8 +3551,9 @@ void CEngine::UpdateGroundSpotTextures() px = cx-Math::Mod(cx, 1.0f); py = cy-Math::Mod(cy, 1.0f); // multiple of 1 - if ( px+dot < min.x || py+dot < min.y || - px-dot > max.x || py-dot > max.y ) continue; + if (px+dot < min.x || py+dot < min.y || + px-dot > max.x || py-dot > max.y) + continue; for (int iy = -dot; iy <= dot; iy++) { @@ -3645,8 +3562,9 @@ void CEngine::UpdateGroundSpotTextures() float ppx = px+ix; float ppy = py+iy; - if ( ppx < min.x || ppy < min.y || - ppx >= max.x || ppy >= max.y ) continue; + if (ppx < min.x || ppy < min.y || + ppx >= max.x || ppy >= max.y) + continue; float intensity; if (dot == 0) @@ -3678,8 +3596,9 @@ void CEngine::UpdateGroundSpotTextures() pos.y = 0.0f; float level = m_terrain->GetFloorLevel(pos, true); - if ( level < m_groundSpots[i].min || - level > m_groundSpots[i].max ) continue; + if (level < m_groundSpots[i].min || + level > m_groundSpots[i].max) + continue; float intensity; if (level > (m_groundSpots[i].max+m_groundSpots[i].min)/2.0f) @@ -3727,13 +3646,16 @@ void CEngine::UpdateGroundSpotTextures() float ppy = py+iy; if (ppx < min.x || ppy < min.y || - ppx >= max.x || ppy >= max.y) continue; + ppx >= max.x || ppy >= max.y) + continue; ppx -= min.x; // on the texture ppy -= min.y; float intensity = 1.0f - Math::Point(ix, iy).Length() / dot; - if (intensity <= 0.0f) continue; + if (intensity <= 0.0f) + continue; + intensity *= m_groundMark.intensity; int j = (ix+dot) + (iy+dot) * m_groundMark.dx; @@ -3825,11 +3747,13 @@ void CEngine::DrawShadow() float lastIntensity = -1.0f; for (int i = 0; i < static_cast<int>( m_shadows.size() ); i++) { - if (m_shadows[i].hide) continue; + if (m_shadows[i].hide) + continue; Math::Vector pos = m_shadows[i].pos; // pos = center of the shadow on the ground - if (m_eyePt.y == pos.y) continue; // camera at the same level? + if (m_eyePt.y == pos.y) + continue; // camera at the same level? float d = 0.0f; float D = 0.0f; @@ -3845,7 +3769,9 @@ void CEngine::DrawShadow() if ( h > 4.0f ) h = 4.0f; D = Math::Distance(m_eyePt, pos); - if ( D >= endDeepView ) continue; + if (D >= endDeepView) + continue; + d = D*h/height; pos.x += (m_eyePt.x-pos.x)*d/D; @@ -3861,7 +3787,9 @@ void CEngine::DrawShadow() if ( h > 4.0f ) h = 4.0f; D = Math::Distance(m_eyePt, pos); - if ( D >= endDeepView ) continue; + if (D >= endDeepView) + continue; + d = D*h/height; pos.x += (m_eyePt.x-pos.x)*d/D; @@ -3969,7 +3897,8 @@ void CEngine::DrawShadow() if ( D > startDeepView ) intensity *= 1.0f-(D-startDeepView)/(endDeepView-startDeepView); - if (intensity == 0.0f) continue; + if (intensity == 0.0f) + continue; if (lastIntensity != intensity) // intensity changed? { @@ -4091,7 +4020,8 @@ void CEngine::DrawBackgroundImage() void CEngine::DrawPlanet() { - if (! m_planet->PlanetExist()) return; + if (! m_planet->PlanetExist()) + return; m_device->SetRenderState(RENDER_STATE_DEPTH_WRITE, false); m_device->SetRenderState(RENDER_STATE_LIGHTING, false); @@ -4106,7 +4036,8 @@ void CEngine::DrawPlanet() void CEngine::DrawForegroundImage() { - if (m_foregroundName.empty()) return; + if (m_foregroundName.empty()) + return; Math::Vector n = Math::Vector(0.0f, 0.0f, -1.0f); // normal @@ -4141,8 +4072,9 @@ void CEngine::DrawForegroundImage() void CEngine::DrawOverColor() { - if ( (m_overColor == Color(0.0f, 0.0f, 0.0f, 0.0f) && m_overMode == ENG_RSTATE_TCOLOR_BLACK) || - (m_overColor == Color(1.0f, 1.0f, 1.0f, 1.0f) && m_overMode == ENG_RSTATE_TCOLOR_WHITE) ) return; + if ((m_overColor == Color(0.0f, 0.0f, 0.0f, 0.0f) && m_overMode == ENG_RSTATE_TCOLOR_BLACK) || + (m_overColor == Color(1.0f, 1.0f, 1.0f, 1.0f) && m_overMode == ENG_RSTATE_TCOLOR_WHITE)) + return; Math::Point p1(0.0f, 0.0f); Math::Point p2(1.0f, 1.0f); diff --git a/src/graphics/engine/engine.h b/src/graphics/engine/engine.h index de57e4d..ad934a6 100644 --- a/src/graphics/engine/engine.h +++ b/src/graphics/engine/engine.h @@ -151,7 +151,7 @@ struct EngineTriangle //! 2nd texture std::string tex2Name; - EngineTriangle() + inline EngineTriangle() { state = ENG_RSTATE_NORMAL; } @@ -178,6 +178,97 @@ enum EngineObjectType ENG_OBJTYPE_METAL = 6 }; + +/** + * \struct EngineBaseObjDataTier + * \brief Tier 4 of object tree (data) + */ +struct EngineBaseObjDataTier +{ + bool used; + EngineTriangleType type; + Material material; + int state; + std::vector<VertexTex2> vertices; + unsigned int staticBufferId; + bool updateStaticBuffer; + + inline EngineBaseObjDataTier(bool used = false, + EngineTriangleType type = ENG_TRIANGLE_TYPE_TRIANGLES, + const Material& material = Material(), + int state = ENG_RSTATE_NORMAL) + : used(used), type(type), material(material), state(state), staticBufferId(0), updateStaticBuffer(false) {} +}; + +/** + * \struct EngineBaseObjLODTier + * \brief Tier 3 of base object tree (LOD) + */ +struct EngineBaseObjLODTier +{ + bool used; + float min; + float max; + std::vector<EngineBaseObjDataTier> next; + + inline EngineBaseObjLODTier(bool used = false, float min = 0.0f, float max = 0.0f) + : used(used), min(min), max(max) {} +}; + +/** + * \struct EngineBaseObjTexTier + * \brief Tier 2 of base object tree (textures) + */ +struct EngineBaseObjTexTier +{ + bool used; + std::string tex1Name; + Texture tex1; + std::string tex2Name; + Texture tex2; + std::vector<EngineBaseObjLODTier> next; + + inline EngineBaseObjTexTier(bool used = false, const std::string& tex1Name = "", + const std::string& tex2Name = "") + : used(used), tex1Name(tex1Name), tex2Name(tex2Name) {} +}; + +/** + * \struct BaseEngineObject + * \brief Base (template) object - geometry for engine objects + * + * This is also the tier 1 of base object tree. + */ +struct EngineBaseObject +{ + //! If true, base object is valid in objects vector + bool used; + //! Number of triangles + int totalTriangles; + //! Bounding box min (origin 0,0,0 always included) + Math::Vector bboxMin; + //! bounding box max (origin 0,0,0 always included) + Math::Vector bboxMax; + //! Radius of the sphere at the origin + float radius; + //! Next tier (LOD) + std::vector<EngineBaseObjTexTier> next; + + inline EngineBaseObject() + { + LoadDefault(); + } + + inline void LoadDefault() + { + used = false; + totalTriangles = 0; + bboxMax.LoadZero(); + bboxMin.LoadZero(); + radius = 0.0f; + } +}; + /** * \struct EngineObject * \brief Object drawn by the graphics engine @@ -186,35 +277,27 @@ struct EngineObject { //! If true, object is valid in objects vector bool used; + //! Rank of associated base engine object + int baseObjRank; //! If true, the object is drawn bool visible; //! If true, object is behind the 2D interface bool drawWorld; //! If true, the shape is before the 2D interface bool drawFront; - //! Number of triangles - int totalTriangles; //! Type of object EngineObjectType type; - //! Whether the object is stored and rendered as static buffer - bool staticBuffer; //! Transformation matrix Math::Matrix transform; //! Distance to object from eye point float distance; - //! Bounding box min (origin 0,0,0 always included) - Math::Vector bboxMin; - //! bounding box max (origin 0,0,0 always included) - Math::Vector bboxMax; - //! Radius of the sphere at the origin - float radius; //! Rank of the associated shadow int shadowRank; //! Transparency of the object [0, 1] float transparency; //! Calls LoadDefault() - EngineObject() + inline EngineObject() { LoadDefault(); } @@ -223,90 +306,18 @@ struct EngineObject inline void LoadDefault() { used = false; + baseObjRank = -1; visible = false; drawWorld = false; drawFront = false; - totalTriangles = 0; - staticBuffer = false; type = ENG_OBJTYPE_NULL; transform.LoadIdentity(); - bboxMax.LoadZero(); - bboxMin.LoadZero(); distance = 0.0f; - radius = 0.0f; shadowRank = -1; transparency = 0.0f; } }; -struct EngineObjLevel1; -struct EngineObjLevel2; -struct EngineObjLevel3; -struct EngineObjLevel4; - -/** - * \struct EngineObjLevel4 - * \brief Tier 4 of object tree - */ -struct EngineObjLevel4 -{ - bool used; - EngineTriangleType type; - Material material; - int state; - std::vector<VertexTex2> vertices; - unsigned int staticBufferId; - - EngineObjLevel4(bool used = false, - EngineTriangleType type = ENG_TRIANGLE_TYPE_TRIANGLES, - const Material& material = Material(), - int state = ENG_RSTATE_NORMAL); -}; - -/** - * \struct EngineObjLevel3 - * \brief Tier 3 of object tree - */ -struct EngineObjLevel3 -{ - bool used; - float min; - float max; - std::vector<EngineObjLevel4> next; - - EngineObjLevel3(bool used = false, float min = 0.0f, float max = 0.0f); -}; - -/** - * \struct EngineObjLevel2 - * \brief Tier 2 of object tree - */ -struct EngineObjLevel2 -{ - bool used; - int objRank; - std::vector<EngineObjLevel3> next; - - EngineObjLevel2(bool used = false, int objRank = -1); -}; - -/** - * \struct EngineObjLevel1 - * \brief Tier 1 of object tree - */ -struct EngineObjLevel1 -{ - bool used; - std::string tex1Name; - Texture tex1; - std::string tex2Name; - Texture tex2; - std::vector<EngineObjLevel2> next; - - EngineObjLevel1(bool used = false, const std::string& tex1Name = "", - const std::string& tex2Name = ""); -}; - /** * \struct EngineShadowType * \brief Type of shadow drawn by the graphics engine @@ -346,12 +357,12 @@ struct EngineShadow //! Height from the ground float height; - EngineShadow() + inline EngineShadow() { LoadDefault(); } - void LoadDefault() + inline void LoadDefault() { used = false; hide = false; @@ -388,12 +399,12 @@ struct EngineGroundSpot //! Radius of the shadow drawn float drawRadius; - EngineGroundSpot() + inline EngineGroundSpot() { LoadDefault(); } - void LoadDefault() + inline void LoadDefault() { used = false; color = Color(); @@ -452,12 +463,12 @@ struct EngineGroundMark //! Pointer to the table char* table; - EngineGroundMark() + inline EngineGroundMark() { LoadDefault(); } - void LoadDefault() + inline void LoadDefault() { draw = false; phase = ENG_GR_MARK_PHASE_NULL; @@ -549,10 +560,10 @@ struct EngineMouse //! Hot point Math::Point hotPoint; - EngineMouse(int icon1 = -1, int icon2 = -1, int iconShadow = -1, - EngineRenderState mode1 = ENG_RSTATE_NORMAL, - EngineRenderState mode2 = ENG_RSTATE_NORMAL, - Math::Point hotPoint = Math::Point()) + inline EngineMouse(int icon1 = -1, int icon2 = -1, int iconShadow = -1, + EngineRenderState mode1 = ENG_RSTATE_NORMAL, + EngineRenderState mode2 = ENG_RSTATE_NORMAL, + Math::Point hotPoint = Math::Point()) { this->icon1 = icon1; this->icon2 = icon2; @@ -745,64 +756,73 @@ public: /* *************** Object management *************** */ + // Base objects + + //! Creates a base object and returns its rank + int CreateBaseObject(); + //! Deletes a base object + void DeleteBaseObject(int baseObjRank); + //! Deletes all base objects + void DeleteAllBaseObjects(); + + //! Copies geometry between two base objects + void CopyBaseObject(int sourceBaseObjRank, int destBaseObjRank); + + //! Adds triangles to given object with the specified params + void AddBaseObjTriangles(int baseObjRank, const std::vector<VertexTex2>& vertices, + EngineTriangleType triangleType, + const Material& material, int state, + std::string tex1Name, std::string tex2Name, + float min, float max, bool globalUpdate); + + //! Adds a tier 4 engine object directly + void AddBaseObjQuick(int baseObjRank, const EngineBaseObjDataTier& buffer, + std::string tex1Name, std::string tex2Name, + float min, float max, bool globalUpdate); + + // Objects + //! Creates a new object and returns its rank int CreateObject(); //! Deletes all objects, shadows and ground spots - void FlushObject(); + void DeleteAllObjects(); //! Deletes the given object - bool DeleteObject(int objRank); + void DeleteObject(int objRank); //@{ - //! Management of engine object type - bool SetObjectType(int objRank, EngineObjectType type); - EngineObjectType GetObjectType(int objRank); + //! Management of the base object rank for engine object + void SetObjectBaseRank(int objRank, int baseObjRank); + int GetObjectBaseRank(int objRank); //@} //@{ - //! Management of object transform - bool SetObjectTransform(int objRank, const Math::Matrix& transform); - bool GetObjectTransform(int objRank, Math::Matrix& transform); + //! Management of engine object type + void SetObjectType(int objRank, EngineObjectType type); + EngineObjectType GetObjectType(int objRank); //@} //@{ - //! Management of object static drawing flag - void SetObjectStatic(int objRank, bool staticBuffer); - bool GetObjectStatic(int objRank); + //! Management of object transform + void SetObjectTransform(int objRank, const Math::Matrix& transform); + void GetObjectTransform(int objRank, Math::Matrix& transform); //@} //! Sets drawWorld for given object - bool SetObjectDrawWorld(int objRank, bool draw); + void SetObjectDrawWorld(int objRank, bool draw); //! Sets drawFront for given object - bool SetObjectDrawFront(int objRank, bool draw); + void SetObjectDrawFront(int objRank, bool draw); //! Sets the transparency level for given object - bool SetObjectTransparency(int objRank, float value); + void SetObjectTransparency(int objRank, float value); //! Returns the bounding box for an object - bool GetObjectBBox(int objRank, Math::Vector& min, Math::Vector& max); + void GetObjectBBox(int objRank, Math::Vector& min, Math::Vector& max); //! Returns the total number of triangles of given object int GetObjectTotalTriangles(int objRank); - //! Adds triangles to given object with the specified params - bool AddTriangles(int objRank, const std::vector<VertexTex2>& vertices, - const Material& material, int state, - std::string tex1Name, std::string tex2Name, - float min, float max, bool globalUpdate); - - //! Adds a surface to given object with the specified params - bool AddSurface(int objRank, const std::vector<VertexTex2>& vertices, - const Material& material, int state, - std::string tex1Name, std::string tex2Name, - float min, float max, bool globalUpdate); - - //! Adds a tier 4 engine object directly - bool AddQuick(int objRank, const EngineObjLevel4& buffer, - std::string tex1Name, std::string tex2Name, - float min, float max, bool globalUpdate); - //! Returns the first found tier 4 engine object for the given params or nullptr if not found - EngineObjLevel4* FindTriangles(int objRank, const Material& material, + EngineBaseObjDataTier* FindTriangles(int objRank, const Material& material, int state, std::string tex1Name, std::string tex2Name, float min, float max); @@ -814,16 +834,16 @@ public: void ChangeLOD(); //! Changes the 2nd texure for given object - bool ChangeSecondTexture(int objRank, const std::string& tex2Name); + void ChangeSecondTexture(int objRank, const std::string& tex2Name); //! Changes (recalculates) texture mapping for given object - bool ChangeTextureMapping(int objRank, const Material& mat, int state, + void ChangeTextureMapping(int objRank, const Material& mat, int state, const std::string& tex1Name, const std::string& tex2Name, float min, float max, EngineTextureMapping mode, float au, float bu, float av, float bv); //! Changes texture mapping for robot tracks - bool TrackTextureMapping(int objRank, const Material& mat, int state, + void TrackTextureMapping(int objRank, const Material& mat, int state, const std::string& tex1Name, const std::string& tex2Name, float min, float max, EngineTextureMapping mode, float pos, float factor, float tl, float ts, float tt); @@ -833,20 +853,20 @@ public: int DetectObject(Math::Point mouse); //! Creates a shadow for the given object - bool CreateShadow(int objRank); + void CreateShadow(int objRank); //! Deletes the shadow for given object void DeleteShadow(int objRank); //@{ //! Management of different shadow params - bool SetObjectShadowHide(int objRank, bool hide); - bool SetObjectShadowType(int objRank, EngineShadowType type); - bool SetObjectShadowPos(int objRank, const Math::Vector& pos); - bool SetObjectShadowNormal(int objRank, const Math::Vector& normal); - bool SetObjectShadowAngle(int objRank, float angle); - bool SetObjectShadowRadius(int objRank, float radius); - bool SetObjectShadowIntensity(int objRank, float intensity); - bool SetObjectShadowHeight(int objRank, float height); + void SetObjectShadowHide(int objRank, bool hide); + void SetObjectShadowType(int objRank, EngineShadowType type); + void SetObjectShadowPos(int objRank, const Math::Vector& pos); + void SetObjectShadowNormal(int objRank, const Math::Vector& normal); + void SetObjectShadowAngle(int objRank, float angle); + void SetObjectShadowRadius(int objRank, float radius); + void SetObjectShadowIntensity(int objRank, float intensity); + void SetObjectShadowHeight(int objRank, float height); float GetObjectShadowRadius(int objRank); //@} @@ -856,7 +876,7 @@ public: bool GetHighlight(Math::Point& p1, Math::Point& p2); //! Deletes all ground spots - void FlushGroundSpot(); + void DeleteAllGroundSpots(); //! Creates a new ground spot and returns its rank int CreateGroundSpot(); //! Deletes the given ground spot @@ -864,11 +884,11 @@ public: //@{ //! Management of different ground spot params - bool SetObjectGroundSpotPos(int rank, const Math::Vector& pos); - bool SetObjectGroundSpotRadius(int rank, float radius); - bool SetObjectGroundSpotColor(int rank, const Color& color); - bool SetObjectGroundSpotMinMax(int rank, float min, float max); - bool SetObjectGroundSpotSmooth(int rank, float smooth); + void SetObjectGroundSpotPos(int rank, const Math::Vector& pos); + void SetObjectGroundSpotRadius(int rank, float radius); + void SetObjectGroundSpotColor(int rank, const Color& color); + void SetObjectGroundSpotMinMax(int rank, float min, float max); + void SetObjectGroundSpotSmooth(int rank, float smooth); //@} //! Creates the ground mark with the given params @@ -1162,7 +1182,7 @@ protected: //! Prepares the interface for 3D scene void Draw3DScene(); //! Draw 3D object - void DrawObject(const EngineObjLevel4& obj, bool staticBuffer); + void DrawObject(const EngineBaseObjDataTier& p4); //! Draws the user interface over the scene void DrawInterface(); @@ -1192,15 +1212,13 @@ protected: //! Draw statistic texts void DrawStats(); - //! Creates new tier 1 object - EngineObjLevel1& AddLevel1(const std::string& tex1Name, const std::string& tex2Name); - //! Creates a new tier 2 object - EngineObjLevel2& AddLevel2(EngineObjLevel1 &p1, int objRank); - //! Creates a new tier 3 object - EngineObjLevel3& AddLevel3(EngineObjLevel2 &p2, float min, float max); - //! Creates a new tier 4 object - EngineObjLevel4& AddLevel4(EngineObjLevel3 &p3, EngineTriangleType type, - const Material& mat, int state); + //! Creates a new tier 2 object (texture) + EngineBaseObjTexTier& AddLevel2(int baseObjRank, const std::string& tex1Name, const std::string& tex2Name); + //! Creates a new tier 3 object (LOD) + EngineBaseObjLODTier& AddLevel3(EngineBaseObjTexTier &p2, float min, float max); + //! Creates a new tier 4 object (data) + EngineBaseObjDataTier& AddLevel4(EngineBaseObjLODTier &p3, EngineTriangleType type, + const Material& mat, int state); //! Create texture and add it to cache Texture CreateTexture(const std::string &texName, const TextureCreateParams ¶ms, CImage* image = nullptr); @@ -1227,8 +1245,11 @@ protected: //! Updates geometric parameters of objects (bounding box and radius) void UpdateGeometry(); + //! Updates a given static buffer + void UpdateStaticBuffer(EngineBaseObjDataTier& p4); + //! Updates static buffers of changed objects - void UpdateStaticObjects(); + void UpdateStaticBuffers(); protected: CInstanceManager* m_iMan; @@ -1282,8 +1303,8 @@ protected: //! Previous size of viewport window Math::IntPoint m_lastSize; - //! Root of tree object structure (level 1 list) - std::vector<EngineObjLevel1> m_objectTree; + //! Base objects (also level 1 tier list) + std::vector<EngineBaseObject> m_baseObjects; //! Object parameters std::vector<EngineObject> m_objects; //! Shadow list @@ -1308,7 +1329,7 @@ protected: Color m_waterAddColor; int m_statisticTriangle; bool m_updateGeometry; - bool m_updateStaticObjects; + bool m_updateStaticBuffers; int m_alphaMode; bool m_groundSpotVisible; bool m_shadowVisible; diff --git a/src/graphics/engine/modelfile.cpp b/src/graphics/engine/modelfile.cpp index a9972fe..a942b08 100644 --- a/src/graphics/engine/modelfile.cpp +++ b/src/graphics/engine/modelfile.cpp @@ -34,22 +34,10 @@ #include <sstream> -/* - * NOTE: #ifndef checking for MODELFILE_NO_ENGINE - * is provided in this module to conditionally - * disable dependence on CEngine. - */ - - // Graphics module namespace namespace Gfx { -//! How big the triangle vector is by default -const int TRIANGLE_PREALLOCATE_COUNT = 2000; - - - bool ReadBinaryVertex(std::istream& stream, Vertex& vertex) { vertex.coord.x = IOUtils::ReadBinaryFloat(stream); @@ -322,15 +310,8 @@ bool ReadLineString(std::istream& stream, const std::string& prefix, std::string } -CModelFile::CModelFile(CInstanceManager* iMan) +CModelFile::CModelFile() { - m_iMan = iMan; - -#ifndef MODELFILE_NO_ENGINE - m_engine = static_cast<CEngine*>(m_iMan->SearchInstance(CLASS_ENGINE)); -#endif - - m_triangles.reserve(TRIANGLE_PREALLOCATE_COUNT); } CModelFile::~CModelFile() @@ -1155,99 +1136,6 @@ bool CModelFile::WriteBinaryModel(std::ostream& stream) Other stuff *******************************************************/ -#ifndef MODELFILE_NO_ENGINE - - -/** - * TODO: move the function to CEngine or new class (CModelManager?) - * and make models shared static objects. - */ - -bool CModelFile::CreateEngineObject(int objRank) -{ - std::vector<VertexTex2> vs(3, VertexTex2()); - - m_engine->SetObjectStatic(objRank, true); // TODO: make optional in the future - - float limit[2]; - limit[0] = m_engine->GetLimitLOD(0); // frontier AB as config - limit[1] = m_engine->GetLimitLOD(1); // frontier BC as config - - for (int i = 0; i < static_cast<int>( m_triangles.size() ); i++) - { - float min = m_triangles[i].min; - float max = m_triangles[i].max; - - // Standard frontiers -> config - if (min == 0.0f && max == 100.0f) // resolution A ? - { - max = limit[0]; - } - else if (min == 100.0f && max == 200.0f) // resolution B ? - { - min = limit[0]; - max = limit[1]; - } - else if (min == 200.0f && max == 1000000.0f) // resolution C ? - { - min = limit[1]; - } - - int state = m_triangles[i].state; - std::string tex2Name = m_triangles[i].tex2Name; - - if (m_triangles[i].variableTex2) - { - int texNum = m_engine->GetSecondTexture(); - - if (texNum >= 1 && texNum <= 10) - state |= ENG_RSTATE_DUAL_BLACK; - - if (texNum >= 11 && texNum <= 20) - state |= ENG_RSTATE_DUAL_WHITE; - - char name[20] = { 0 }; - sprintf(name, "dirty%.2d.png", texNum); - tex2Name = name; - } - - vs[0] = m_triangles[i].p1; - vs[1] = m_triangles[i].p2; - vs[2] = m_triangles[i].p3; - - bool ok = m_engine->AddTriangles(objRank, vs, - m_triangles[i].material, - state, - m_triangles[i].tex1Name, - tex2Name, - min, max, false); - if (!ok) - return false; - } - - return true; -} - -#endif - -void CModelFile::Mirror() -{ - for (int i = 0; i < static_cast<int>( m_triangles.size() ); i++) - { - VertexTex2 t = m_triangles[i].p1; - m_triangles[i].p1 = m_triangles[i].p2; - m_triangles[i].p2 = t; - - m_triangles[i].p1.coord.z = -m_triangles[i].p1.coord.z; - m_triangles[i].p2.coord.z = -m_triangles[i].p2.coord.z; - m_triangles[i].p3.coord.z = -m_triangles[i].p3.coord.z; - - m_triangles[i].p1.normal.z = -m_triangles[i].p1.normal.z; - m_triangles[i].p2.normal.z = -m_triangles[i].p2.normal.z; - m_triangles[i].p3.normal.z = -m_triangles[i].p3.normal.z; - } -} - const std::vector<ModelTriangle>& CModelFile::GetTriangles() { return m_triangles; @@ -1258,28 +1146,6 @@ int CModelFile::GetTriangleCount() return m_triangles.size(); } -float CModelFile::GetHeight(Math::Vector pos) -{ - float limit = 5.0f; - - for (int i = 0; i < static_cast<int>( m_triangles.size() ); i++) - { - if ( fabs(pos.x - m_triangles[i].p1.coord.x) < limit && - fabs(pos.z - m_triangles[i].p1.coord.z) < limit ) - return m_triangles[i].p1.coord.y; - - if ( fabs(pos.x - m_triangles[i].p2.coord.x) < limit && - fabs(pos.z - m_triangles[i].p2.coord.z) < limit ) - return m_triangles[i].p2.coord.y; - - if ( fabs(pos.x - m_triangles[i].p3.coord.x) < limit && - fabs(pos.z - m_triangles[i].p3.coord.z) < limit ) - return m_triangles[i].p3.coord.y; - } - - return 0.0f; -} - void CModelFile::CreateTriangle(Math::Vector p1, Math::Vector p2, Math::Vector p3, float min, float max) { ModelTriangle triangle; diff --git a/src/graphics/engine/modelfile.h b/src/graphics/engine/modelfile.h index 6c573b8..b2b5d87 100644 --- a/src/graphics/engine/modelfile.h +++ b/src/graphics/engine/modelfile.h @@ -33,14 +33,10 @@ #include <iostream> -class CInstanceManager; - // Graphics module namespace namespace Gfx { -class CEngine; - /** \struct ModelTriangle @@ -79,14 +75,15 @@ struct ModelTriangle /** - \class CModelFile - \brief Model file reader/writer - - Allows reading and writing model objects. Models are collections of ModelTriangle structs. */ + * \class CModelFile + * \brief Model file reader/writer + * + * Allows reading and writing model objects. Models are collections of ModelTriangle structs. + */ class CModelFile { public: - CModelFile(CInstanceManager* iMan); + CModelFile(); ~CModelFile(); //! Reads a model in text format from file @@ -128,23 +125,11 @@ public: //! Returns the triangle vector const std::vector<ModelTriangle>& GetTriangles(); - //! Returns the height of model -- closest point to X and Z coords of \a pos - float GetHeight(Math::Vector pos); - - //! Mirrors the model along the Z axis - void Mirror(); - - //! Creates an object in the graphics engine from the model - bool CreateEngineObject(int objRank); - protected: //! Adds a triangle to the list void CreateTriangle(Math::Vector p1, Math::Vector p2, Math::Vector p3, float min, float max); protected: - CInstanceManager* m_iMan; - CEngine* m_engine; - //! Model triangles std::vector<ModelTriangle> m_triangles; }; diff --git a/src/graphics/engine/modelmanager.cpp b/src/graphics/engine/modelmanager.cpp new file mode 100644 index 0000000..afaa718 --- /dev/null +++ b/src/graphics/engine/modelmanager.cpp @@ -0,0 +1,213 @@ +#include "graphics/engine/modelmanager.h" + +#include "app/app.h" + +#include "common/logger.h" + +#include "graphics/engine/engine.h" + +#include <cstdio> + +namespace Gfx { + +template<> CModelManager* CSingleton<CModelManager>::mInstance = nullptr; + +CModelManager::CModelManager(CEngine* engine) +{ + m_engine = engine; +} + +CModelManager::~CModelManager() +{ +} + +bool CModelManager::LoadModel(const std::string& fileName, bool mirrored) +{ + GetLogger()->Info("Loading model '%s'\n", fileName.c_str()); + + CModelFile modelFile; + + std::string filePath = CApplication::GetInstance().GetDataFilePath(DIR_MODEL, fileName); + + if (!modelFile.ReadModel(filePath)) + { + GetLogger()->Error("Loading model '%s' failed\n", filePath.c_str()); + return false; + } + + ModelInfo modelInfo; + modelInfo.baseObjRank = m_engine->CreateBaseObject(); + modelInfo.triangles = modelFile.GetTriangles(); + + if (mirrored) + Mirror(modelInfo.triangles); + + FileInfo fileInfo(fileName, mirrored); + m_models[fileInfo] = modelInfo; + + std::vector<VertexTex2> vs(3, VertexTex2()); + + float limit[2]; + limit[0] = m_engine->GetLimitLOD(0); // frontier AB as config + limit[1] = m_engine->GetLimitLOD(1); // frontier BC as config + + for (int i = 0; i < static_cast<int>( modelInfo.triangles.size() ); i++) + { + float min = modelInfo.triangles[i].min; + float max = modelInfo.triangles[i].max; + + // Standard frontiers -> config + if (min == 0.0f && max == 100.0f) // resolution A ? + { + max = limit[0]; + } + else if (min == 100.0f && max == 200.0f) // resolution B ? + { + min = limit[0]; + max = limit[1]; + } + else if (min == 200.0f && max == 1000000.0f) // resolution C ? + { + min = limit[1]; + } + + int state = modelInfo.triangles[i].state; + std::string tex2Name = modelInfo.triangles[i].tex2Name; + + if (modelInfo.triangles[i].variableTex2) + { + int texNum = m_engine->GetSecondTexture(); + + if (texNum >= 1 && texNum <= 10) + state |= ENG_RSTATE_DUAL_BLACK; + + if (texNum >= 11 && texNum <= 20) + state |= ENG_RSTATE_DUAL_WHITE; + + char name[20] = { 0 }; + sprintf(name, "dirty%.2d.png", texNum); + tex2Name = name; + } + + vs[0] = modelInfo.triangles[i].p1; + vs[1] = modelInfo.triangles[i].p2; + vs[2] = modelInfo.triangles[i].p3; + + m_engine->AddBaseObjTriangles(modelInfo.baseObjRank, vs, ENG_TRIANGLE_TYPE_TRIANGLES, + modelInfo.triangles[i].material, state, + modelInfo.triangles[i].tex1Name, tex2Name, + min, max, false); + } + + return true; +} + +bool CModelManager::AddModelReference(const std::string& fileName, bool mirrored, int objRank) +{ + auto it = m_models.find(FileInfo(fileName, mirrored)); + if (it == m_models.end()) + { + if (!LoadModel(fileName, mirrored)) + return false; + + it = m_models.find(FileInfo(fileName, mirrored)); + } + + m_engine->SetObjectBaseRank(objRank, (*it).second.baseObjRank); + + return true; +} + +bool CModelManager::AddModelCopy(const std::string& fileName, bool mirrored, int objRank) +{ + auto it = m_models.find(FileInfo(fileName, mirrored)); + if (it == m_models.end()) + { + if (!LoadModel(fileName, mirrored)) + return false; + + it = m_models.find(FileInfo(fileName, mirrored)); + } + + int copyBaseObjRank = m_engine->CreateBaseObject(); + m_engine->CopyBaseObject((*it).second.baseObjRank, copyBaseObjRank); + m_engine->SetObjectBaseRank(objRank, copyBaseObjRank); + + return true; +} + +bool CModelManager::IsModelLoaded(const std::string& fileName, bool mirrored) +{ + return m_models.count(FileInfo(fileName, mirrored)) > 0; +} + +int CModelManager::GetModelBaseObjRank(const std::string& fileName, bool mirrored) +{ + auto it = m_models.find(FileInfo(fileName, mirrored)); + if (it == m_models.end()) + return -1; + + return (*it).second.baseObjRank; +} + +void CModelManager::UnloadModel(const std::string& fileName, bool mirrored) +{ + auto it = m_models.find(FileInfo(fileName, mirrored)); + if (it == m_models.end()) + return; + + m_engine->DeleteBaseObject((*it).second.baseObjRank); + + m_models.erase(it); +} + +void CModelManager::UnloadAllModels() +{ + for (auto& mf : m_models) + m_engine->DeleteBaseObject(mf.second.baseObjRank); + + m_models.clear(); +} + +void CModelManager::Mirror(std::vector<ModelTriangle>& triangles) +{ + for (int i = 0; i < static_cast<int>( triangles.size() ); i++) + { + VertexTex2 t = triangles[i].p1; + triangles[i].p1 = triangles[i].p2; + triangles[i].p2 = t; + + triangles[i].p1.coord.z = -triangles[i].p1.coord.z; + triangles[i].p2.coord.z = -triangles[i].p2.coord.z; + triangles[i].p3.coord.z = -triangles[i].p3.coord.z; + + triangles[i].p1.normal.z = -triangles[i].p1.normal.z; + triangles[i].p2.normal.z = -triangles[i].p2.normal.z; + triangles[i].p3.normal.z = -triangles[i].p3.normal.z; + } +} + +float CModelManager::GetHeight(std::vector<ModelTriangle>& triangles, Math::Vector pos) +{ + const float limit = 5.0f; + + for (int i = 0; i < static_cast<int>( triangles.size() ); i++) + { + 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; + + 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; + + 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; + } + + return 0.0f; +} + + +} diff --git a/src/graphics/engine/modelmanager.h b/src/graphics/engine/modelmanager.h new file mode 100644 index 0000000..601d636 --- /dev/null +++ b/src/graphics/engine/modelmanager.h @@ -0,0 +1,97 @@ +#pragma once + +#include "common/singleton.h" + +#include "graphics/engine/modelfile.h" + +#include <string> +#include <vector> +#include <map> + +namespace Gfx { + +class CEngine; +class CModelFile; + +/** + * \class CModelManager + * \brief Manager for static models + * + * The manager allows for loading models as static objects and adding + * new instances of models to the engine. + * + * The models are loaded from stanard application model directory and + * they are identified by unique file names. + * + * The models are loaded by creating (if it doesn't exist yet) + * a base engine object from the model geometry. This base object + * is then shared among all instances of this model with the instances + * being engine objects linked to the shared base object. + * + * There is also a possibility of creating a copy of model so it has + * its own and unique base engine object. This is especially useful + * for models where the geometry must be altered. + */ +class CModelManager : public CSingleton<CModelManager> +{ +public: + CModelManager(CEngine* engine); + ~CModelManager(); + + //! Loads a model from given file + bool LoadModel(const std::string& fileName, bool mirrored); + + //! Adds an instance of model to the given object rank as a reference to base object + bool AddModelReference(const std::string& fileName, bool mirrored, int objRank); + + //! Adds an instance of model to the given object rank as a copy (copied base object) + bool AddModelCopy(const std::string& fileName, bool mirrored, int objRank); + + //! Returns true if given model is loaded + bool IsModelLoaded(const std::string& fileName, bool mirrored); + + //! Returns the rank of base engine object of given loaded model + int GetModelBaseObjRank(const std::string& fileName, bool mirrored); + + //! Unloads the given model + void UnloadModel(const std::string& fileName, bool mirrored); + //! Unloads all models + 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); + +private: + struct ModelInfo + { + std::vector<ModelTriangle> triangles; + int baseObjRank; + }; + struct FileInfo + { + std::string fileName; + bool mirrored; + + inline FileInfo(const std::string& fileName, bool mirrored) + : fileName(fileName), mirrored(mirrored) {} + + inline bool operator<(const FileInfo& other) const + { + int compare = fileName.compare(other.fileName); + if (compare < 0) + return true; + if (compare > 0) + return false; + + return !mirrored && mirrored != other.mirrored; + } + }; + std::map<FileInfo, ModelInfo> m_models; + CEngine* m_engine; +}; + +} // namespace Gfx diff --git a/src/graphics/engine/pyro.cpp b/src/graphics/engine/pyro.cpp index 73c5cec..978471b 100644 --- a/src/graphics/engine/pyro.cpp +++ b/src/graphics/engine/pyro.cpp @@ -363,7 +363,6 @@ bool CPyro::Create(PyroType type, CObject* obj, float force) m_type == PT_EXPLOW ) { CreateTriangle(obj, oType, 0); - m_engine->SetObjectStatic(m_object->GetObjectRank(0), false); m_engine->DeleteShadow(m_object->GetObjectRank(0)); ExploStart(); } @@ -1398,8 +1397,6 @@ void CPyro::CreateTriangle(CObject* obj, ObjectType oType, int part) int objRank = obj->GetObjectRank(part); if (objRank == -1) return; - m_engine->SetObjectStatic(objRank, false); - float min = 0.0f; float max = m_engine->GetLimitLOD(0); int total = m_engine->GetObjectTotalTriangles(objRank); diff --git a/src/graphics/engine/terrain.cpp b/src/graphics/engine/terrain.cpp index 0e77ea2..a66b4b0 100644 --- a/src/graphics/engine/terrain.cpp +++ b/src/graphics/engine/terrain.cpp @@ -34,10 +34,6 @@ // Graphics module namespace namespace Gfx { -const int LEVEL_MAT_PREALLOCATE_COUNT = 101; -const int FLYING_LIMIT_PREALLOCATE_COUNT = 10; -const int BUILDING_LEVEL_PREALLOCATE_COUNT = 101; - CTerrain::CTerrain(CInstanceManager* iMan) { @@ -60,10 +56,6 @@ CTerrain::CTerrain(CInstanceManager* iMan) m_defaultHardness = 0.5f; m_useMaterials = false; - m_materials.reserve(LEVEL_MAT_PREALLOCATE_COUNT); - m_flyingLimits.reserve(FLYING_LIMIT_PREALLOCATE_COUNT); - m_buildingLevels.reserve(BUILDING_LEVEL_PREALLOCATE_COUNT); - FlushBuildingLevel(); FlushFlyingLimit(); FlushMaterials(); @@ -498,6 +490,13 @@ bool CTerrain::CreateMosaic(int ox, int oy, int step, int objRank, const Material &mat, float min, float max) { + int baseObjRank = m_engine->GetObjectBaseRank(objRank); + if (baseObjRank == -1) + { + baseObjRank = m_engine->CreateBaseObject(); + m_engine->SetObjectBaseRank(objRank, baseObjRank); + } + std::string texName1; std::string texName2; @@ -547,7 +546,7 @@ bool CTerrain::CreateMosaic(int ox, int oy, int step, int objRank, for (int y = 0; y < brick; y += step) { - EngineObjLevel4 buffer; + EngineBaseObjDataTier buffer; buffer.vertices.reserve(total); buffer.type = ENG_TRIANGLE_TYPE_SURFACE; @@ -640,7 +639,8 @@ bool CTerrain::CreateMosaic(int ox, int oy, int step, int objRank, buffer.vertices.push_back(p1); buffer.vertices.push_back(p2); } - m_engine->AddQuick(objRank, buffer, texName1, texName2, min, max, true); + + m_engine->AddBaseObjQuick(baseObjRank, buffer, texName1, texName2, min, max, true); } } } @@ -1168,10 +1168,6 @@ bool CTerrain::CreateSquare(int x, int y) int objRank = m_engine->CreateObject(); m_engine->SetObjectType(objRank, ENG_OBJTYPE_TERRAIN); - // TODO: create a static object, but not split into squares, but a single object for all terrain - // Squares should be sub-objects accessing parts of triangle list - // m_engine->SetObjectStatic(objRank, true); - m_objRanks[x+y*m_mosaicCount] = objRank; float min = 0.0f; @@ -1278,7 +1274,10 @@ bool CTerrain::Terraform(const Math::Vector &p1, const Math::Vector &p2, float h { for (int x = pp1.x; x <= pp2.x; x++) { - m_engine->DeleteObject(m_objRanks[x+y*m_mosaicCount]); + int objRank = m_objRanks[x+y*m_mosaicCount]; + int baseObjRank = m_engine->GetObjectBaseRank(objRank); + m_engine->DeleteBaseObject(baseObjRank); + m_engine->DeleteObject(objRank); CreateSquare(x, y); // recreates the square } } diff --git a/src/graphics/engine/terrain.h b/src/graphics/engine/terrain.h index 3012e62..e17144e 100644 --- a/src/graphics/engine/terrain.h +++ b/src/graphics/engine/terrain.h @@ -328,7 +328,7 @@ protected: //! Calculates a vector of the terrain Math::Vector GetVector(int x, int y); //! Calculates a vertex of the terrain - VertexTex2 GetVertex(int x, int y, int step); + VertexTex2 GetVertex(int x, int y, int step); //! Creates all objects of a mosaic bool CreateMosaic(int ox, int oy, int step, int objRank, const Material& mat, float min, float max); //! Creates all objects in a mesh square ground diff --git a/src/graphics/engine/test/CMakeLists.txt b/src/graphics/engine/test/CMakeLists.txt index 4e3263b..b1db2c7 100644 --- a/src/graphics/engine/test/CMakeLists.txt +++ b/src/graphics/engine/test/CMakeLists.txt @@ -8,7 +8,6 @@ modelfile_test.cpp ../modelfile.cpp ../../../common/logger.cpp ../../../common/stringutils.cpp -../../../common/iman.cpp ) add_definitions(-DMODELFILE_NO_ENGINE) diff --git a/src/graphics/engine/test/modelfile_test.cpp b/src/graphics/engine/test/modelfile_test.cpp index 6879a1b..43cd43b 100644 --- a/src/graphics/engine/test/modelfile_test.cpp +++ b/src/graphics/engine/test/modelfile_test.cpp @@ -15,12 +15,11 @@ // * along with this program. If not, see http://www.gnu.org/licenses/. -#include "common/iman.h" #include "common/logger.h" #include "graphics/engine/modelfile.h" #include "math/func.h" -#include "gtest/gtest.h" +#include <gtest/gtest.h> #include <cassert> #include <sstream> @@ -190,8 +189,7 @@ TEST(ModelFileTest, RWTxtModel) std::stringstream str; str.str(TEXT_MODEL); - CInstanceManager iMan; - Gfx::CModelFile modelFile(&iMan); + Gfx::CModelFile modelFile; EXPECT_TRUE(modelFile.ReadTextModel(str)); @@ -216,8 +214,7 @@ TEST(ModelFileTest, RWBinModel) std::stringstream str; str.str(TEXT_MODEL); - CInstanceManager iMan; - Gfx::CModelFile modelFile(&iMan); + Gfx::CModelFile modelFile; EXPECT_TRUE(modelFile.ReadTextModel(str)); @@ -242,8 +239,7 @@ TEST(ModelFileTest, RWOldModel) std::stringstream str; str.str(TEXT_MODEL); - CInstanceManager iMan; - Gfx::CModelFile modelFile(&iMan); + Gfx::CModelFile modelFile; EXPECT_TRUE(modelFile.ReadTextModel(str)); |