diff options
Diffstat (limited to 'src/graphics/engine/engine.cpp')
-rw-r--r-- | src/graphics/engine/engine.cpp | 2273 |
1 files changed, 1334 insertions, 939 deletions
diff --git a/src/graphics/engine/engine.cpp b/src/graphics/engine/engine.cpp index 3365b24..7c90a8d 100644 --- a/src/graphics/engine/engine.cpp +++ b/src/graphics/engine/engine.cpp @@ -47,55 +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; - - vertices.reserve(LEVEL4_VERTEX_PREALLOCATE_COUNT); -} - CEngine::CEngine(CInstanceManager *iMan, CApplication *app) { m_iMan = iMan; @@ -182,6 +133,7 @@ CEngine::CEngine(CInstanceManager *iMan, CApplication *app) m_alphaMode = 1; m_updateGeometry = false; + m_updateStaticBuffers = false; m_interfaceMode = false; @@ -218,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() @@ -334,6 +281,8 @@ void CEngine::Destroy() void CEngine::ResetAfterDeviceChanged() { + m_size = m_app->GetVideoConfig().size;; + m_text->FlushCache(); // TODO reload textures, reset device state, etc. @@ -378,9 +327,14 @@ void CEngine::FrameUpdate() float rTime = m_app->GetRelTime(); m_lightMan->UpdateProgression(rTime); + + m_app->StartPerformanceCounter(PCNT_UPDATE_PARTICLE); m_particle->FrameParticle(rTime); + m_app->StopPerformanceCounter(PCNT_UPDATE_PARTICLE); + ComputeDistance(); UpdateGeometry(); + UpdateStaticBuffers(); m_highlightTime = m_app->GetAbsTime(); @@ -409,7 +363,7 @@ void CEngine::FrameUpdate() { m_groundMark.intensity = 0.0f; m_groundMark.phase = ENG_GR_MARK_PHASE_NULL; - m_groundMark.draw = false; + m_groundMark.draw = false; } } } @@ -422,18 +376,6 @@ bool CEngine::WriteScreenShot(const std::string& fileName, int width, int height return true; } -bool CEngine::ReadSettings() -{ - // TODO: when INI reading is completed - return true; -} - -bool CEngine::WriteSettings() -{ - // TODO: when INI writing is completed - return true; -} - void CEngine::SetPause(bool pause) { m_pause = pause; @@ -500,7 +442,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) @@ -519,480 +461,377 @@ int CEngine::GetStatisticTriangle() Object management *******************************************************/ +EngineBaseObjTexTier& CEngine::AddLevel2(EngineBaseObject& p1, const std::string& tex1Name, const std::string& tex2Name) +{ + for (int i = 0; i < static_cast<int>( p1.next.size() ); i++) + { + if (p1.next[i].tex1Name == tex1Name && p1.next[i].tex2Name == tex2Name) + return p1.next[i]; + } + p1.next.push_back(EngineBaseObjTexTier(tex1Name, tex2Name)); + return p1.next.back(); +} -int CEngine::CreateObject() +EngineBaseObjLODTier& CEngine::AddLevel3(EngineBaseObjTexTier& p2, float min, float max) { - int i = 0; - for ( ; i < static_cast<int>( m_objects.size() ); i++) + for (int i = 0; i < static_cast<int>( p2.next.size() ); i++) { - if (! m_objects[i].used) + if ( (p2.next[i].min == min) && (p2.next[i].max == max) ) + return p2.next[i]; + } + + p2.next.push_back(EngineBaseObjLODTier(min, max)); + return p2.next.back(); +} + +EngineBaseObjDataTier& CEngine::AddLevel4(EngineBaseObjLODTier& p3, EngineTriangleType type, + const Material& material, int state) +{ + for (int i = 0; i < static_cast<int>( p3.next.size() ); i++) + { + if ( (p3.next[i].type == type) && (p3.next[i].material == material) && (p3.next[i].state == state) ) + return p3.next[i]; + } + + p3.next.push_back(EngineBaseObjDataTier(type, material, state)); + return p3.next.back(); +} + +int CEngine::CreateBaseObject() +{ + int baseObjRank = 0; + for ( ; baseObjRank < static_cast<int>( m_baseObjects.size() ); baseObjRank++) + { + if (! m_baseObjects[baseObjRank].used) { - m_objects[i].LoadDefault(); + m_baseObjects[baseObjRank].LoadDefault(); break; } } - if (i == static_cast<int>( m_objects.size() )) - m_objects.push_back(EngineObject()); - + if (baseObjRank == static_cast<int>( m_baseObjects.size() )) + m_baseObjects.push_back(EngineBaseObject()); + else + m_baseObjects[baseObjRank].LoadDefault(); - m_objects[i].used = true; - Math::Matrix mat; - mat.LoadIdentity(); - SetObjectTransform(i, mat); + m_baseObjects[baseObjRank].used = true; - 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; + return baseObjRank; } -void CEngine::FlushObject() +void CEngine::DeleteBaseObject(int baseObjRank) { - m_objectTree.clear(); - m_objects.clear(); + assert(baseObjRank >= 0 && baseObjRank < static_cast<int>( m_baseObjects.size() )); - m_shadows.clear(); + EngineBaseObject& p1 = m_baseObjects[baseObjRank]; - FlushGroundSpot(); -} - -bool CEngine::DeleteObject(int objRank) -{ - if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) ) - return false; + if (! p1.used) + return; - // Delete object's triangles - for (int l1 = 0; l1 < static_cast<int>( m_objectTree.size() ); l1++) + for (int l2 = 0; l2 < static_cast<int>( p1.next.size() ); l2++) { - EngineObjLevel1& p1 = m_objectTree[l1]; - if (! p1.used) continue; + EngineBaseObjTexTier& p2 = p1.next[l2]; - 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 (p2.objRank == objRank) + for (int l4 = 0; l4 < static_cast<int>( p3.next.size() ); l4++) { - p2.used = false; - p2.next.clear(); + EngineBaseObjDataTier& p4 = p3.next[l4]; + + m_device->DestroyStaticBuffer(p4.staticBufferId); + p4.staticBufferId = 0; } } } - // Mark object as deleted - m_objects[objRank].used = false; + p1.next.clear(); - // Delete associated shadows - DeleteShadow(objRank); - - return true; + p1.used = false; } -bool CEngine::SetObjectType(int objRank, EngineObjectType type) +void CEngine::DeleteAllBaseObjects() { - 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; + m_baseObjects.clear(); } - -bool CEngine::SetObjectTransform(int objRank, const Math::Matrix& transform) +void CEngine::CopyBaseObject(int sourceBaseObjRank, int destBaseObjRank) { - if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) ) - return false; + assert(sourceBaseObjRank >= 0 && sourceBaseObjRank < static_cast<int>( m_baseObjects.size() )); + assert(destBaseObjRank >= 0 && destBaseObjRank < static_cast<int>( m_baseObjects.size() )); - m_objects[objRank].transform = transform; - return true; + m_baseObjects[destBaseObjRank] = m_baseObjects[sourceBaseObjRank]; } -bool CEngine::GetObjectTransform(int objRank, Math::Matrix& transform) +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() ) ) - return false; + assert(baseObjRank >= 0 && baseObjRank < static_cast<int>( m_baseObjects.size() )); - transform = m_objects[objRank].transform; - return true; -} + m_lastSize = m_size; + m_lastObjectDetail = m_objectDetail; + m_lastClippingDistance = m_clippingDistance; -bool CEngine::SetObjectDrawWorld(int objRank, bool draw) -{ - if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) ) - return false; + EngineBaseObject& p1 = m_baseObjects[baseObjRank]; + EngineBaseObjTexTier& p2 = AddLevel2(p1, tex1Name, tex2Name); + EngineBaseObjLODTier& p3 = AddLevel3(p2, min, max); + EngineBaseObjDataTier& p4 = AddLevel4(p3, triangleType, material, state); - m_objects[objRank].drawWorld = draw; - return true; -} + p4.vertices.insert(p4.vertices.end(), vertices.begin(), vertices.end()); -bool CEngine::SetObjectDrawFront(int objRank, bool draw) -{ - if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) ) - return false; + p4.updateStaticBuffer = true; + m_updateStaticBuffers = true; - m_objects[objRank].drawFront = draw; - return true; -} + if (globalUpdate) + { + m_updateGeometry = true; + } + else + { + for (int i = 0; i < static_cast<int>( vertices.size() ); i++) + { + p1.bboxMin.x = Math::Min(vertices[i].coord.x, p1.bboxMin.x); + p1.bboxMin.y = Math::Min(vertices[i].coord.y, p1.bboxMin.y); + p1.bboxMin.z = Math::Min(vertices[i].coord.z, p1.bboxMin.z); + p1.bboxMax.x = Math::Max(vertices[i].coord.x, p1.bboxMax.x); + p1.bboxMax.y = Math::Max(vertices[i].coord.y, p1.bboxMax.y); + p1.bboxMax.z = Math::Max(vertices[i].coord.z, p1.bboxMax.z); + } -bool CEngine::SetObjectTransparency(int objRank, float value) -{ - if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) ) - return false; + p1.radius = Math::Max(p1.bboxMin.Length(), p1.bboxMax.Length()); + } - m_objects[objRank].transparency = value; - return true; + if (triangleType == ENG_TRIANGLE_TYPE_TRIANGLES) + p1.totalTriangles += vertices.size() / 3; + else + p1.totalTriangles += vertices.size() - 2; } -bool CEngine::GetObjectBBox(int objRank, Math::Vector& min, Math::Vector& max) +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() ) ) - return 0; + assert(baseObjRank >= 0 && baseObjRank < static_cast<int>( m_baseObjects.size() )); - min = m_objects[objRank].bboxMin; - max = m_objects[objRank].bboxMax; - return true; -} + EngineBaseObject& p1 = m_baseObjects[baseObjRank]; + EngineBaseObjTexTier& p2 = AddLevel2(p1, tex1Name, tex2Name); + EngineBaseObjLODTier& p3 = AddLevel3(p2, min, max); + p3.next.push_back(buffer); -int CEngine::GetObjectTotalTriangles(int objRank) -{ - if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) ) - return 0; + EngineBaseObjDataTier& p4 = p3.next.back(); - return m_objects[objRank].totalTriangles; -} + UpdateStaticBuffer(p4); - -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 (globalUpdate) { - if (! m_objectTree[i].used) - { - unusedPresent = true; - continue; - } - - if (m_objectTree[i].tex1Name == tex1Name && m_objectTree[i].tex2Name == tex2Name) - return m_objectTree[i]; + m_updateGeometry = true; } - - if (unusedPresent) + else { - for (int i = 0; i < static_cast<int>( m_objectTree.size() ); i++) + for (int i = 0; i < static_cast<int>( p4.vertices.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]; - } + p1.bboxMin.x = Math::Min(p4.vertices[i].coord.x, p1.bboxMin.x); + p1.bboxMin.y = Math::Min(p4.vertices[i].coord.y, p1.bboxMin.y); + p1.bboxMin.z = Math::Min(p4.vertices[i].coord.z, p1.bboxMin.z); + p1.bboxMax.x = Math::Max(p4.vertices[i].coord.x, p1.bboxMax.x); + p1.bboxMax.y = Math::Max(p4.vertices[i].coord.y, p1.bboxMax.y); + p1.bboxMax.z = Math::Max(p4.vertices[i].coord.z, p1.bboxMax.z); } + + p1.radius = Math::Max(p1.bboxMin.Length(), p1.bboxMax.Length()); } - m_objectTree.push_back(EngineObjLevel1(true, tex1Name, tex2Name)); - return m_objectTree.back(); + if (p4.type == ENG_TRIANGLE_TYPE_TRIANGLES) + p1.totalTriangles += p4.vertices.size() / 3; + else if (p4.type == ENG_TRIANGLE_TYPE_SURFACE) + p1.totalTriangles += p4.vertices.size() - 2; } -EngineObjLevel2& CEngine::AddLevel2(EngineObjLevel1& p1, int objRank) + +int CEngine::CreateObject() { - bool unusedPresent = false; - for (int i = 0; i < static_cast<int>( p1.next.size() ); i++) + int objRank = 0; + for ( ; objRank < static_cast<int>( m_objects.size() ); objRank++) { - if (! p1.next[i].used) + if (! m_objects[objRank].used) { - unusedPresent = true; - continue; + m_objects[objRank].LoadDefault(); + break; } - - if (p1.next[i].objRank == objRank) - return p1.next[i]; } - if (unusedPresent) - { - for (int i = 0; i < static_cast<int>( p1.next.size() ); i++) - { - if (! p1.next[i].used) - { - p1.next[i].used = true; - p1.next[i].objRank = objRank; - return p1.next[i]; - } - } - } + if (objRank == static_cast<int>( m_objects.size() )) + m_objects.push_back(EngineObject()); - p1.next.push_back(EngineObjLevel2(true, objRank)); - return p1.next.back(); + + m_objects[objRank].used = true; + + Math::Matrix mat; + mat.LoadIdentity(); + SetObjectTransform(objRank, mat); + + m_objects[objRank].drawWorld = true; + m_objects[objRank].distance = 0.0f; + m_objects[objRank].shadowRank = -1; + + return objRank; } -EngineObjLevel3& CEngine::AddLevel3(EngineObjLevel2& p2, float min, float max) +void CEngine::DeleteAllObjects() { - bool unusedPresent = false; - for (int i = 0; i < static_cast<int>( p2.next.size() ); i++) - { - if (! p2.next[i].used) - { - unusedPresent = true; - continue; - } + m_objects.clear(); + m_shadows.clear(); - if ( (p2.next[i].min == min) && (p2.next[i].max == max) ) - return p2.next[i]; - } + DeleteAllGroundSpots(); +} - if (unusedPresent) - { - for (int i = 0; i < static_cast<int>( p2.next.size() ); i++) - { - if (! p2.next[i].used) - { - p2.next[i].used = true; - p2.next[i].min = min; - p2.next[i].max = max; - return p2.next[i]; - } - } - } +void CEngine::DeleteObject(int objRank) +{ + assert(objRank >= 0 && objRank < static_cast<int>( m_objects.size() )); - p2.next.push_back(EngineObjLevel3(true, min, max)); - return p2.next.back(); + // Mark object as deleted + m_objects[objRank].used = false; + + // Delete associated shadows + DeleteShadow(objRank); } -EngineObjLevel4& CEngine::AddLevel4(EngineObjLevel3& p3, EngineTriangleType type, - const Material& material, int state) +void CEngine::SetObjectBaseRank(int objRank, int baseObjRank) { - bool unusedPresent = false; - for (int i = 0; i < static_cast<int>( p3.next.size() ); i++) - { - if (! p3.next[i].used) - { - unusedPresent = true; - continue; - } + assert(objRank == -1 || (objRank >= 0 && objRank < static_cast<int>( m_objects.size() ))); - if ( (p3.next[i].type == type) && (p3.next[i].material == material) && (p3.next[i].state == state) ) - return p3.next[i]; - } + m_objects[objRank].baseObjRank = baseObjRank; +} - if (unusedPresent) - { - for (int i = 0; i < static_cast<int>( p3.next.size() ); i++) - { - if (! p3.next[i].used) - { - p3.next[i].used = true; - p3.next[i].type = type; - p3.next[i].material = material; - p3.next[i].state = state; - return p3.next[i]; - } - } - } +int CEngine::GetObjectBaseRank(int objRank) +{ + assert(objRank >= 0 && objRank < static_cast<int>( m_objects.size() )); - p3.next.push_back(EngineObjLevel4(true, type, material, state)); - return p3.next.back(); + return m_objects[objRank].baseObjRank; } -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) +void CEngine::SetObjectType(int objRank, EngineObjectType type) { - if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) ) - { - GetLogger()->Error("AddTriangle(): invalid object rank %d\n", objRank); - return false; - } + assert(objRank >= 0 && objRank < static_cast<int>( m_objects.size() )); - m_lastSize = m_size; - m_lastObjectDetail = m_objectDetail; - m_lastClippingDistance = m_clippingDistance; + m_objects[objRank].type = type; +} - 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); +EngineObjectType CEngine::GetObjectType(int objRank) +{ + assert(objRank >= 0 && objRank < static_cast<int>( m_objects.size() )); - p4.vertices.insert(p4.vertices.end(), vertices.begin(), vertices.end()); + return m_objects[objRank].type; +} - if (globalUpdate) - { - m_updateGeometry = true; - } - else - { - 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_objects[objRank].radius = Math::Max(m_objects[objRank].bboxMin.Length(), - m_objects[objRank].bboxMax.Length()); - } - - m_objects[objRank].totalTriangles += vertices.size() / 3; +void CEngine::SetObjectTransform(int objRank, const Math::Matrix& transform) +{ + assert(objRank >= 0 && objRank < static_cast<int>( m_objects.size() )); - return true; + m_objects[objRank].transform = transform; } -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::GetObjectTransform(int objRank, Math::Matrix& transform) { - if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) ) - { - GetLogger()->Error("AddSurface(): invalid object rank %d\n", objRank); - return false; - } + assert(objRank >= 0 && objRank < static_cast<int>( m_objects.size() )); - m_lastSize = m_size; - m_lastObjectDetail = m_objectDetail; - m_lastClippingDistance = m_clippingDistance; + transform = m_objects[objRank].transform; +} - 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); +void CEngine::SetObjectDrawWorld(int objRank, bool draw) +{ + assert(objRank >= 0 && objRank < static_cast<int>( m_objects.size() )); - p4.vertices.insert(p4.vertices.end(), vertices.begin(), vertices.end()); + m_objects[objRank].drawWorld = draw; +} - if (globalUpdate) - { - m_updateGeometry = true; - } - else - { - 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); - } +void CEngine::SetObjectDrawFront(int objRank, bool draw) +{ + assert(objRank >= 0 && objRank < static_cast<int>( m_objects.size() )); - m_objects[objRank].radius = Math::Max(m_objects[objRank].bboxMin.Length(), - m_objects[objRank].bboxMax.Length()); - } + m_objects[objRank].drawFront = draw; +} - m_objects[objRank].totalTriangles += vertices.size() - 2; +void CEngine::SetObjectTransparency(int objRank, float value) +{ + assert(objRank >= 0 && objRank < static_cast<int>( m_objects.size() )); - return true; + m_objects[objRank].transparency = value; } -bool CEngine::AddQuick(int objRank, const EngineObjLevel4& buffer, - std::string tex1Name, std::string tex2Name, - float min, float max, bool globalUpdate) +void CEngine::GetObjectBBox(int objRank, Math::Vector& min, Math::Vector& max) { - if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) ) - { - GetLogger()->Error("AddQuick(): invalid object rank %d\n", objRank); - return false; - } + assert(objRank >= 0 && objRank < static_cast<int>( m_objects.size() )); - EngineObjLevel1& p1 = AddLevel1(tex1Name, tex2Name); - EngineObjLevel2& p2 = AddLevel2(p1, objRank); - EngineObjLevel3& p3 = AddLevel3(p2, min, max); + int baseObjRank = m_objects[objRank].baseObjRank; + if (baseObjRank == -1) + return; - p3.next.push_back(buffer); - p3.next.back().used = true; // ensure that it is used + assert(baseObjRank >= 0 && baseObjRank < static_cast<int>(m_baseObjects.size())); - if (globalUpdate) - { - m_updateGeometry = true; - } - else - { - for (int i = 0; i < static_cast<int>( buffer.vertices.size() ); i++) - { - m_objects[objRank].bboxMin.x = Math::Min(buffer.vertices[i].coord.x, m_objects[objRank].bboxMin.x); - m_objects[objRank].bboxMin.y = Math::Min(buffer.vertices[i].coord.y, m_objects[objRank].bboxMin.y); - m_objects[objRank].bboxMin.z = Math::Min(buffer.vertices[i].coord.z, m_objects[objRank].bboxMin.z); - m_objects[objRank].bboxMax.x = Math::Max(buffer.vertices[i].coord.x, m_objects[objRank].bboxMax.x); - m_objects[objRank].bboxMax.y = Math::Max(buffer.vertices[i].coord.y, m_objects[objRank].bboxMax.y); - m_objects[objRank].bboxMax.z = Math::Max(buffer.vertices[i].coord.z, m_objects[objRank].bboxMax.z); - } + min = m_baseObjects[baseObjRank].bboxMin; + max = m_baseObjects[baseObjRank].bboxMax; +} - m_objects[objRank].radius = Math::Max(m_objects[objRank].bboxMin.Length(), - m_objects[objRank].bboxMax.Length()); - } - if (buffer.type == ENG_TRIANGLE_TYPE_TRIANGLES) - m_objects[objRank].totalTriangles += buffer.vertices.size() / 3; - else if (buffer.type == ENG_TRIANGLE_TYPE_SURFACE) - m_objects[objRank].totalTriangles += buffer.vertices.size() - 2; +int CEngine::GetObjectTotalTriangles(int objRank) +{ + assert(objRank >= 0 && objRank < static_cast<int>( m_objects.size() )); - return true; + int baseObjRank = m_objects[objRank].baseObjRank; + if (baseObjRank == -1) + return 0; + + assert(baseObjRank >= 0 && baseObjRank < static_cast<int>( m_baseObjects.size() )); + + return m_baseObjects[baseObjRank].totalTriangles; } -EngineObjLevel4* CEngine::FindTriangles(int objRank, const Material& material, - int state, std::string tex1Name, - std::string tex2Name, float min, float max) +EngineBaseObjDataTier* CEngine::FindTriangles(int objRank, const Material& material, + int state, std::string tex1Name, + std::string tex2Name, float min, float max) { - if ( objRank < 0 || objRank >= static_cast<int>( m_objects.size() ) ) - { - GetLogger()->Error("FindTriangles(): invalid object rank %d\n", objRank); + assert(objRank >= 0 && objRank < static_cast<int>( m_objects.size() )); + + int baseObjRank = m_objects[objRank].baseObjRank; + if (baseObjRank == -1) return nullptr; - } - for (int l1 = 0; l1 < static_cast<int>( m_objectTree.size() ); l1++) + assert(baseObjRank >= 0 && baseObjRank < static_cast<int>( m_baseObjects.size() )); + + EngineBaseObject& p1 = m_baseObjects[baseObjRank]; + + for (int l2 = 0; l2 < static_cast<int>( p1.next.size() ); l2++) { - EngineObjLevel1& p1 = m_objectTree[l1]; - if (! p1.used) continue; + EngineBaseObjTexTier& p2 = p1.next[l2]; - if (p1.tex1Name != tex1Name) continue; - // TODO: tex2Name compare? + 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 (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.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; } } } @@ -1001,91 +840,85 @@ 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); + assert(objRank >= 0 && objRank < static_cast<int>( m_objects.size() )); + + int baseObjRank = m_objects[objRank].baseObjRank; + if (baseObjRank == -1) return 0; - } - int total = m_objects[objRank].totalTriangles; + assert(baseObjRank >= 0 && baseObjRank < static_cast<int>( m_baseObjects.size() )); + + EngineBaseObject& p1 = m_baseObjects[baseObjRank]; + + int total = p1.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>( p1.next.size() ); l2++) { - EngineObjLevel1& p1 = m_objectTree[l1]; - if (! p1.used) continue; + EngineBaseObjTexTier& p2 = p1.next[l2]; - 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 (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; + EngineBaseObjDataTier& p4 = p3.next[l4]; - if (p3.min != min || p3.max != max) 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; } } } @@ -1112,20 +945,20 @@ 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; + 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; + EngineBaseObjTexTier& p2 = p1.next[l2]; 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 ( Math::IsEqual(p3.min, 0.0f ) && Math::IsEqual(p3.max, oldLimit[0]) ) @@ -1157,43 +990,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 + assert(objRank >= 0 && objRank < static_cast<int>( m_objects.size() )); - 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; + if (baseObjRank == -1) + return; - if (p2.objRank != objRank) continue; + assert(baseObjRank >= 0 && baseObjRank < static_cast<int>( m_baseObjects.size() )); - EngineObjLevel1& newP1 = AddLevel1(p1.tex1Name, tex2Name); + 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]; - EngineObjLevel2& newP2 = newP1.next.back(); - newP2.next.swap(p2.next); + if (p2.tex2Name == tex2Name) + continue; // already new - p2.used = false; - } + EngineBaseObjTexTier& newP2 = AddLevel2(p1, p2.tex1Name, tex2Name); + newP2.next.swap(p2.next); } - 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(); @@ -1243,27 +1073,113 @@ bool CEngine::ChangeTextureMapping(int objRank, const Material& mat, int state, } } - return true; + UpdateStaticBuffer(*p4); } -bool 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) +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) { - // TODO track texture mapping: pretty complex code, so leaving it for now - GetLogger()->Trace("CEngine::TrackTextureMapping(): stub!\n"); - return true; + 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 = p4->vertices.size(); + if (tNum < 12 || tNum % 6 != 0) + return; + + std::vector<Gfx::VertexTex2>& vs = p4->vertices; + + while (pos < 0.0f) + pos += 1.0f; // never negative! + + Math::Vector current; + + for (int i = 0; i < 6; i++) + { + for (int j = 0; j < 6; j++) + { + if (Math::IsEqual(vs[i].coord.x, vs[j+6].coord.x) && + Math::IsEqual(vs[i].coord.y, vs[j+6].coord.y)) + { + current.x = vs[i].coord.x; // position end link + current.y = vs[i].coord.y; + break; + } + } + } + + float ps = 0.0f; // start position on the periphery + float pe = 0.0f; + int is[6] = { 0 }, ie[6] = { 0 }; + + int tBase = 0; + for (int ti = 0; ti < tNum / 6; ti++) + { + int s = 0; + int e = 0; + + for (int i = 0; i < 6; i++) + { + if (Math::IsEqual(vs[tBase + i].coord.x, current.x, 0.0001f) && + Math::IsEqual(vs[tBase + i].coord.y, current.y, 0.0001f)) + { + ie[e++] = i; + } + else + { + is[s++] = i; + } + } + if (s == 3 && e == 3) + { + pe = ps + Math::Point(vs[tBase + is[0]].coord.x - vs[tBase + ie[0]].coord.x, + vs[tBase + is[0]].coord.y - vs[tBase + ie[0]].coord.y).Length() / factor; // end position on the periphery + + float pps = ps + pos; + float ppe = pe + pos; + int offset = static_cast<int>(pps); + ppe -= offset; + pps -= offset; + + for (int i = 0; i < 3; i++) + { + vs[tBase + is[i]].texCoord.x = ((pps * tl) + ts) / tt; + vs[tBase + ie[i]].texCoord.x = ((ppe * tl) + ts) / tt; + } + } + + if (ti >= (tNum / 6) - 1) + break; + + for (int i = 0; i < 6; i++) + { + if (!Math::IsEqual(vs[tBase + i+6].coord.x, current.x, 0.0001f) || + !Math::IsEqual(vs[tBase + i+6].coord.y, current.y, 0.0001f)) + { + current.x = vs[tBase + i+6].coord.x; // end next link + current.y = vs[tBase + i+6].coord.y; + break; + } + } + ps = pe; // following start position on the periphery + tBase += 6; + } + + 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++) @@ -1275,146 +1191,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) @@ -1436,21 +1353,31 @@ 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; + if (baseObjRank == -1) + return false; + + assert(baseObjRank >= 0 && baseObjRank < static_cast<int>( m_baseObjects.size() )); + + EngineBaseObject& p1 = m_baseObjects[baseObjRank]; + 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 = p1.bboxMin.x; + else p.x = p1.bboxMax.x; + if ( i & (1<<1) ) p.y = p1.bboxMin.y; + else p.y = p1.bboxMax.y; + if ( i & (1<<2) ) p.z = p1.bboxMin.z; + else p.z = p1.bboxMax.z; Math::Vector pp; if (TransformPoint(pp, objRank, p)) @@ -1462,20 +1389,36 @@ 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; - // TODO: blank all shadow textures + for (int s = 0; s < 16; s++) + { + CImage shadowImg(Math::IntPoint(256, 256)); + shadowImg.Fill(Gfx::IntColor(255, 255, 255, 255)); + + std::stringstream str; + str << "shadow" << std::setfill('0') << std::setw(2) << s << ".png"; + std::string texName = str.str(); + + DeleteTexture(texName); + + Gfx::Texture tex = m_device->CreateTexture(&shadowImg, m_defaultTexParams); + + m_texNameMap[texName] = tex; + m_revTexNameMap[tex] = texName; + } } int CEngine::CreateGroundSpot() @@ -1500,54 +1443,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, @@ -1556,6 +1491,7 @@ void CEngine::CreateGroundMark(Math::Vector pos, float radius, { m_groundMark.LoadDefault(); + m_groundMark.draw = true; m_groundMark.phase = ENG_GR_MARK_PHASE_INC; m_groundMark.delay[0] = delay1; m_groundMark.delay[1] = delay2; @@ -1575,8 +1511,6 @@ void CEngine::DeleteGroundMark(int rank) void CEngine::ComputeDistance() { - // TODO: s_resol??? - for (int i = 0; i < static_cast<int>( m_objects.size() ); i++) { if (! m_objects[i].used) @@ -1595,51 +1529,39 @@ 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]; 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]; 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]; 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()); } } } @@ -1648,14 +1570,76 @@ void CEngine::UpdateGeometry() m_updateGeometry = false; } +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_updateStaticBuffers) + return; + + m_updateStaticBuffers = false; + + for (int baseObjRank = 0; baseObjRank < static_cast<int>( m_baseObjects.size() ); baseObjRank++) + { + EngineBaseObject& p1 = m_baseObjects[baseObjRank]; + if (! p1.used) + continue; + + for (int l2 = 0; l2 < static_cast<int>( p1.next.size() ); l2++) + { + EngineBaseObjTexTier& p2 = p1.next[l2]; + + for (int l3 = 0; l3 < static_cast<int>( p2.next.size() ); l3++) + { + EngineBaseObjLODTier& p3 = p2.next[l3]; + + for (int l4 = 0; l4 < static_cast<int>( p3.next.size() ); l4++) + { + EngineBaseObjDataTier& p4 = p3.next[l4]; + + if (! p4.updateStaticBuffer) + continue; + + UpdateStaticBuffer(p4); + } + } + } + } +} + void CEngine::Update() { ComputeDistance(); UpdateGeometry(); + 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; + if (baseObjRank == -1) + return false; + + assert(baseObjRank >= 0 && baseObjRank < static_cast<int>(m_baseObjects.size())); + + EngineBaseObject& p1 = m_baseObjects[baseObjRank]; + Math::Point min, max; min.x = 1000000.0f; min.y = 1000000.0f; @@ -1666,12 +1650,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 = p1.bboxMin.x; + else p.x = p1.bboxMax.x; + if ( i & (1<<1) ) p.y = p1.bboxMin.y; + else p.y = p1.bboxMax.y; + if ( i & (1<<2) ) p.z = p1.bboxMin.z; + else p.z = p1.bboxMax.z; Math::Vector pp; if ( TransformPoint(pp, objRank, p) ) @@ -1694,41 +1678,51 @@ 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 (m_objects[p2.objRank].type == ENG_OBJTYPE_TERRAIN) continue; + if (! DetectBBox(objRank, mouse)) + continue; - if (! DetectBBox(p2.objRank, mouse)) continue; + int baseObjRank = m_objects[objRank].baseObjRank; + if (baseObjRank == -1) + continue; + + assert(baseObjRank >= 0 && baseObjRank < static_cast<int>(m_baseObjects.size())); + + EngineBaseObject& p1 = m_baseObjects[baseObjRank]; + if (! p1.used) + continue; + + for (int l2 = 0; l2 < static_cast<int>( p1.next.size() ); l2++) + { + EngineBaseObjTexTier& p2 = p1.next[l2]; 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.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.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; } } } @@ -1737,10 +1731,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; } } } @@ -1754,6 +1748,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++) @@ -1766,18 +1762,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; @@ -1794,18 +1797,38 @@ bool CEngine::DetectTriangle(Math::Point mouse, VertexTex2* triangle, int objRan return true; } +//! Use only after world transform already set bool CEngine::IsVisible(int objRank) { - // TODO: use ComputeSphereVisiblity() after tested OK - return true; + assert(objRank >= 0 && objRank < static_cast<int>(m_objects.size())); + + int baseObjRank = m_objects[objRank].baseObjRank; + if (baseObjRank == -1) + return false; + + 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) + { + m_objects[objRank].visible = true; + return true; + } + + m_objects[objRank].visible = false; + 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); @@ -1855,7 +1878,7 @@ void CEngine::SetState(int state, const Color& color) params.colorOperation = TEX_MIX_OPER_MODULATE; params.colorArg1 = TEX_MIX_ARG_TEXTURE; params.colorArg2 = TEX_MIX_ARG_FACTOR; - params.alphaOperation = TEX_MIX_OPER_DEFAULT; // TODO: replace with src color ? + params.alphaOperation = TEX_MIX_OPER_DEFAULT; params.factor = color; m_device->SetTextureEnabled(0, true); @@ -1874,7 +1897,7 @@ void CEngine::SetState(int state, const Color& color) params.colorOperation = TEX_MIX_OPER_ADD; params.colorArg1 = TEX_MIX_ARG_TEXTURE; params.colorArg2 = TEX_MIX_ARG_FACTOR; - params.alphaOperation = TEX_MIX_OPER_DEFAULT; // TODO: replace with src color ? + params.alphaOperation = TEX_MIX_OPER_DEFAULT; params.factor = color.Inverse(); m_device->SetTextureEnabled(0, true); @@ -1914,7 +1937,7 @@ void CEngine::SetState(int state, const Color& color) TextureStageParams params; params.colorOperation = TEX_MIX_OPER_REPLACE; params.colorArg1 = TEX_MIX_ARG_TEXTURE; - params.alphaOperation = TEX_MIX_OPER_DEFAULT; // TODO: replace with src color ? + params.alphaOperation = TEX_MIX_OPER_DEFAULT; m_device->SetTextureEnabled(0, true); m_device->SetTextureStageParams(0, params); @@ -1982,7 +2005,7 @@ void CEngine::SetState(int state, const Color& color) TextureStageParams params; params.colorOperation = TEX_MIX_OPER_DEFAULT; // default modulate - params.alphaOperation = TEX_MIX_OPER_DEFAULT; // TODO: replace with src color ? + params.alphaOperation = TEX_MIX_OPER_DEFAULT; m_device->SetTextureEnabled(0, true); m_device->SetTextureStageParams(0, params); @@ -2003,7 +2026,7 @@ void CEngine::SetState(int state, const Color& color) params.colorOperation = TEX_MIX_OPER_MODULATE; params.colorArg1 = TEX_MIX_ARG_TEXTURE; params.colorArg2 = TEX_MIX_ARG_COMPUTED_COLOR; - params.alphaOperation = TEX_MIX_OPER_DEFAULT; // TODO: ??? + params.alphaOperation = TEX_MIX_OPER_DEFAULT; m_device->SetTextureEnabled(1, true); m_device->SetTextureStageParams(1, params); } @@ -2013,7 +2036,7 @@ void CEngine::SetState(int state, const Color& color) params.colorOperation = TEX_MIX_OPER_ADD; params.colorArg1 = TEX_MIX_ARG_TEXTURE; params.colorArg2 = TEX_MIX_ARG_COMPUTED_COLOR; - params.alphaOperation = TEX_MIX_OPER_DEFAULT; // TODO: ??? + params.alphaOperation = TEX_MIX_OPER_DEFAULT; m_device->SetTextureEnabled(1, true); m_device->SetTextureStageParams(1, params); } @@ -2168,42 +2191,50 @@ 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; + if (baseObjRank == -1) + continue; - if (m_objects[p2.objRank].type == ENG_OBJTYPE_TERRAIN) - terrain = true; - } + assert(baseObjRank >= 0 && baseObjRank < static_cast<int>( m_baseObjects.size() )); + + 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 (! 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 (! p1.tex2.Valid()) - ok = false; + if (! p2.tex2Name.empty()) + { + if (terrain) + p2.tex2 = LoadTexture(p2.tex2Name, m_terrainTexParams); + else + p2.tex2 = LoadTexture(p2.tex2Name); + + if (! p2.tex2.Valid()) + ok = false; + } } } @@ -2219,7 +2250,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; } @@ -2235,12 +2267,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); @@ -2275,7 +2308,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)); @@ -2905,7 +2939,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; @@ -2928,7 +2963,9 @@ void CEngine::Render() if (m_drawWorld) Draw3DScene(); + m_app->StartPerformanceCounter(PCNT_RENDER_INTERFACE); DrawInterface(); + m_app->StopPerformanceCounter(PCNT_RENDER_INTERFACE); // End the scene m_device->EndScene(); @@ -2959,41 +2996,49 @@ void CEngine::Draw3DScene() if (m_waterMode) m_water->DrawBack(); // draws water background + m_app->StartPerformanceCounter(PCNT_RENDER_TERRAIN); + + // Draw terrain with shadows, if shadows enabled if (m_shadowVisible) { m_lightMan->UpdateDeviceLights(ENG_OBJTYPE_TERRAIN); - // Draw the 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; - if (! IsVisible(objRank)) - continue; + int baseObjRank = m_objects[objRank].baseObjRank; + if (baseObjRank == -1) + continue; + + assert(baseObjRank >= 0 && baseObjRank < static_cast<int>( m_baseObjects.size() )); + + EngineBaseObject& p1 = m_baseObjects[baseObjRank]; + if (! p1.used) + continue; + + for (int l2 = 0; l2 < static_cast<int>( p1.next.size() ); l2++) + { + EngineBaseObjTexTier& p2 = p1.next[l2]; + + 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 ( m_objects[objRank].distance < p3.min || m_objects[objRank].distance >= p3.max ) @@ -3001,26 +3046,12 @@ 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]; SetMaterial(p4.material); SetState(p4.state); - if (p4.type == ENG_TRIANGLE_TYPE_TRIANGLES) - { - m_device->DrawPrimitive( PRIMITIVE_TRIANGLES, - &p4.vertices[0], - p4.vertices.size() ); - m_statisticTriangle += p4.vertices.size() / 3; - } - if (p4.type == ENG_TRIANGLE_TYPE_SURFACE) - { - m_device->DrawPrimitive( PRIMITIVE_TRIANGLE_STRIP, - &p4.vertices[0], - p4.vertices.size() ); - m_statisticTriangle += p4.vertices.size() - 2; - } + DrawObject(p4); } } } @@ -3030,51 +3061,60 @@ void CEngine::Draw3DScene() DrawShadow(); } - // Draw objects (non-terrain) + m_app->StopPerformanceCounter(PCNT_RENDER_TERRAIN); + + // Draw other objects (and if shadows disabled, also terrain) + + m_app->StartPerformanceCounter(PCNT_RENDER_OBJECTS); 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; + if (baseObjRank == -1) + continue; - m_device->SetTransform(TRANSFORM_WORLD, m_objects[objRank].transform); + assert(baseObjRank >= 0 && baseObjRank < static_cast<int>( m_baseObjects.size() )); - if (! IsVisible(objRank)) - continue; + EngineBaseObject& p1 = m_baseObjects[baseObjRank]; + if (! p1.used) + continue; - m_lightMan->UpdateDeviceLights(m_objects[objRank].type); + m_lightMan->UpdateDeviceLights(m_objects[objRank].type); + + for (int l2 = 0; l2 < static_cast<int>( p1.next.size() ); l2++) + { + EngineBaseObjTexTier& p2 = p1.next[l2]; + + 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 ( 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 (m_objects[objRank].transparency != 0.0f) // transparent ? { @@ -3085,22 +3125,7 @@ void CEngine::Draw3DScene() SetMaterial(p4.material); SetState(p4.state); - if (p4.type == ENG_TRIANGLE_TYPE_TRIANGLES) - { - m_device->DrawPrimitive( PRIMITIVE_TRIANGLES, - &p4.vertices[0], - p4.vertices.size() ); - - m_statisticTriangle += p4.vertices.size() / 3; - } - else if (p4.type == ENG_TRIANGLE_TYPE_SURFACE) - { - m_device->DrawPrimitive( PRIMITIVE_TRIANGLE_STRIP, - &p4.vertices[0], - p4.vertices.size() ); - - m_statisticTriangle += p4.vertices.size() - 2; - } + DrawObject(p4); } } } @@ -3113,47 +3138,52 @@ 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; + if (baseObjRank == -1) + continue; - m_device->SetTransform(TRANSFORM_WORLD, m_objects[objRank].transform); + assert(baseObjRank >= 0 && baseObjRank < static_cast<int>( m_baseObjects.size() )); - if (! IsVisible(objRank)) - continue; + EngineBaseObject& p1 = m_baseObjects[baseObjRank]; + if (! p1.used) + continue; + + m_lightMan->UpdateDeviceLights(m_objects[objRank].type); + + for (int l2 = 0; l2 < static_cast<int>( p1.next.size() ); l2++) + { + EngineBaseObjTexTier& p2 = p1.next[l2]; - 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 ( 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 (m_objects[objRank].transparency == 0.0f) continue; @@ -3161,40 +3191,61 @@ void CEngine::Draw3DScene() SetMaterial(p4.material); SetState(tState, tColor); - if (p4.type == ENG_TRIANGLE_TYPE_TRIANGLES) - { - m_device->DrawPrimitive( PRIMITIVE_TRIANGLES, - &p4.vertices[0], - p4.vertices.size() ); - - m_statisticTriangle += p4.vertices.size() / 3; - } - else if (p4.type == ENG_TRIANGLE_TYPE_SURFACE) - { - m_device->DrawPrimitive( PRIMITIVE_TRIANGLE_STRIP, - &p4.vertices[0], - p4.vertices.size() ); - m_statisticTriangle += p4.vertices.size() - 2; - } + DrawObject(p4); } } } } } + m_app->StopPerformanceCounter(PCNT_RENDER_OBJECTS); + m_lightMan->UpdateDeviceLights(ENG_OBJTYPE_TERRAIN); - if (m_waterMode) m_water->DrawSurf(); // draws water surface + if (m_waterMode) + { + m_app->StartPerformanceCounter(PCNT_RENDER_WATER); + m_water->DrawSurf(); // draws water surface + m_app->StopPerformanceCounter(PCNT_RENDER_WATER); + } + m_app->StartPerformanceCounter(PCNT_RENDER_PARTICLE); m_particle->DrawParticle(SH_WORLD); // draws the particles of the 3D world + m_app->StopPerformanceCounter(PCNT_RENDER_PARTICLE); + m_lightning->Draw(); // draws lightning - // TODO: fix white screen error; commenting out temporarily - // if (m_lensMode) DrawForegroundImage(); // draws the foreground + if (m_lensMode) DrawForegroundImage(); // draws the foreground if (! m_overFront) DrawOverColor(); // draws the foreground color } +void CEngine::DrawObject(const EngineBaseObjDataTier& p4) +{ + if (p4.staticBufferId != 0) + { + m_device->DrawStaticBuffer(p4.staticBufferId); + + if (p4.type == ENG_TRIANGLE_TYPE_TRIANGLES) + m_statisticTriangle += p4.vertices.size() / 3; + else + m_statisticTriangle += p4.vertices.size() - 2; + } + else + { + if (p4.type == ENG_TRIANGLE_TYPE_TRIANGLES) + { + m_device->DrawPrimitive(PRIMITIVE_TRIANGLES, &p4.vertices[0], p4.vertices.size()); + m_statisticTriangle += p4.vertices.size() / 3; + } + else + { + m_device->DrawPrimitive(PRIMITIVE_TRIANGLE_STRIP, &p4.vertices[0], p4.vertices.size() ); + m_statisticTriangle += p4.vertices.size() - 2; + } + } +} + void CEngine::DrawInterface() { m_device->SetRenderState(RENDER_STATE_DEPTH_TEST, false); @@ -3240,66 +3291,57 @@ 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; + if (baseObjRank == -1) + continue; - m_device->SetTransform(TRANSFORM_WORLD, m_objects[objRank].transform); + assert(baseObjRank >= 0 && baseObjRank < static_cast<int>( m_baseObjects.size() )); - if (! IsVisible(objRank)) - continue; + EngineBaseObject& p1 = m_baseObjects[baseObjRank]; + if (! p1.used) + continue; - m_lightMan->UpdateDeviceLights(m_objects[objRank].type); + m_lightMan->UpdateDeviceLights(m_objects[objRank].type); + + for (int l2 = 0; l2 < static_cast<int>( p1.next.size() ); l2++) + { + EngineBaseObjTexTier& p2 = p1.next[l2]; + + 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 ( 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]; SetMaterial(p4.material); SetState(p4.state); - if (p4.type == ENG_TRIANGLE_TYPE_TRIANGLES) - { - m_device->DrawPrimitive( PRIMITIVE_TRIANGLES, - &p4.vertices[0], - p4.vertices.size() ); - - m_statisticTriangle += p4.vertices.size() / 3; - } - else if (p4.type == ENG_TRIANGLE_TYPE_SURFACE) - { - m_device->DrawPrimitive( PRIMITIVE_TRIANGLE_STRIP, - &p4.vertices[0], - p4.vertices.size() ); - m_statisticTriangle += p4.vertices.size() - 2; - } + DrawObject(p4); } } } @@ -3328,8 +3370,270 @@ void CEngine::DrawInterface() void CEngine::UpdateGroundSpotTextures() { - // TODO the original code modifying the textures is very complex, so stub for now - GetLogger()->Trace("CEngine::UpdateGroundSpotTextures(): stub!\n"); + if (!m_firstGroundSpot && + 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; + + for (int s = 0; s < 16; s++) + { + Math::Point min, max; + min.x = (s%4) * 254.0f - 1.0f; // 1 pixel cover + min.y = (s/4) * 254.0f - 1.0f; + max.x = min.x + 254.0f + 2.0f; + max.y = min.y + 254.0f + 2.0f; + + bool clear = false; + bool set = false; + + // Calculate the area to be erased. + int dot = static_cast<int>(m_groundMark.drawRadius/2.0f); + + float tu, tv; + float cx, cy; + + tu = (m_groundMark.drawPos.x+1600.0f)/3200.0f; + tv = (m_groundMark.drawPos.z+1600.0f)/3200.0f; // 0..1 + + cx = (tu*254.0f*4.0f)-0.5f; + cy = (tv*254.0f*4.0f)-0.5f; + + if (dot == 0) + { + cx += 0.5f; + cy += 0.5f; + } + + float px = cx-Math::Mod(cx, 1.0f); + float py = cy-Math::Mod(cy, 1.0f); // multiple of 1 + + if (m_firstGroundSpot || + (m_groundMark.drawRadius != 0.0f && + px+dot >= min.x && py+dot >= min.y && + px-dot <= max.x && py-dot <= max.y)) + { + clear = true; + } + + // Calculate the area to draw. + dot = static_cast<int>(m_groundMark.radius/2.0f); + + tu = (m_groundMark.pos.x+1600.0f)/3200.0f; + tv = (m_groundMark.pos.z+1600.0f)/3200.0f; // 0..1 + + cx = (tu*254.0f*4.0f)-0.5f; + cy = (tv*254.0f*4.0f)-0.5f; + + if ( dot == 0 ) + { + cx += 0.5f; + cy += 0.5f; + } + + px = cx - Math::Mod(cx, 1.0f); + py = cy - Math::Mod(cy, 1.0f); // multiple of 1 + + if (m_groundMark.draw && + px+dot >= min.x && py+dot >= min.y && + px-dot <= max.x && py-dot <= max.y) + { + set = true; + } + + if (clear || set) + { + CImage shadowImg(Math::IntPoint(256, 256)); + shadowImg.Fill(Gfx::IntColor(255, 255, 255, 255)); + + // 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].min == 0.0f && + m_groundSpots[i].max == 0.0f) + { + dot = static_cast<int>(m_groundSpots[i].radius/2.0f); + + tu = (m_groundSpots[i].pos.x+1600.0f)/3200.0f; + tv = (m_groundSpots[i].pos.z+1600.0f)/3200.0f; // 0..1 + + cx = (tu*254.0f*4.0f) - 0.5f; + cy = (tv*254.0f*4.0f) - 0.5f; + + if (dot == 0) + { + cx += 0.5f; + cy += 0.5f; + } + + 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; + + for (int iy = -dot; iy <= dot; iy++) + { + for (int ix =- dot; ix <= dot; ix++) + { + float ppx = px+ix; + float ppy = py+iy; + + if (ppx < min.x || ppy < min.y || + ppx >= max.x || ppy >= max.y) + continue; + + float intensity; + if (dot == 0) + intensity = 0.0f; + else + intensity = Math::Point(ppx-cx, ppy-cy).Length()/dot; + + Gfx::Color color; + color.r = Math::Norm(m_groundSpots[i].color.r+intensity); + color.g = Math::Norm(m_groundSpots[i].color.g+intensity); + color.b = Math::Norm(m_groundSpots[i].color.b+intensity); + + ppx -= min.x; // on the texture + ppy -= min.y; + + shadowImg.SetPixel(Math::IntPoint(ppx, ppy), color); + } + } + } + else + { + for (int iy = 0; iy < 256; iy++) + { + for (int ix = 0; ix < 256; ix++) + { + Math::Vector pos; + pos.x = (256.0f * (s%4) + ix) * 3200.0f/1024.0f - 1600.0f; + pos.z = (256.0f * (s/4) + iy) * 3200.0f/1024.0f - 1600.0f; + pos.y = 0.0f; + + float level = m_terrain->GetFloorLevel(pos, true); + 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) + intensity = 1.0f - (m_groundSpots[i].max-level) / m_groundSpots[i].smooth; + else + intensity = 1.0f - (level-m_groundSpots[i].min) / m_groundSpots[i].smooth; + + if (intensity < 0.0f) intensity = 0.0f; + + Gfx::Color color; + color.r = Math::Norm(m_groundSpots[i].color.r+intensity); + color.g = Math::Norm(m_groundSpots[i].color.g+intensity); + color.b = Math::Norm(m_groundSpots[i].color.b+intensity); + + shadowImg.SetPixel(Math::IntPoint(ix, iy), color); + } + } + } + } + + if (set) + { + dot = static_cast<int>(m_groundMark.radius/2.0f); + + tu = (m_groundMark.pos.x + 1600.0f) / 3200.0f; + tv = (m_groundMark.pos.z + 1600.0f) / 3200.0f; // 0..1 + + cx = (tu*254.0f*4.0f)-0.5f; + cy = (tv*254.0f*4.0f)-0.5f; + + if (dot == 0) + { + cx += 0.5f; + cy += 0.5f; + } + + px = cx-Math::Mod(cx, 1.0f); + py = cy-Math::Mod(cy, 1.0f); // multiple of 1 + + for (int iy = -dot; iy <= dot; iy++) + { + for (int ix = -dot; ix <= dot; ix++) + { + float ppx = px+ix; + float ppy = py+iy; + + if (ppx < min.x || ppy < min.y || + 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; + + intensity *= m_groundMark.intensity; + + int j = (ix+dot) + (iy+dot) * m_groundMark.dx; + if (m_groundMark.table[j] == 1) // green ? + { + Gfx::Color color; + color.r = Math::Norm(1.0f-intensity); + color.g = 1.0f; + color.b = Math::Norm(1.0f-intensity); + shadowImg.SetPixel(Math::IntPoint(ppx, ppy), color); + } + if (m_groundMark.table[j] == 2) // red ? + { + Gfx::Color color; + color.r = 1.0f; + color.g = Math::Norm(1.0f-intensity); + color.b = Math::Norm(1.0f-intensity); + shadowImg.SetPixel(Math::IntPoint(ppx, ppy), color); + } + } + } + } + + std::stringstream str; + str << "shadow" << std::setfill('0') << std::setw(2) << s << ".png"; + std::string texName = str.str(); + + DeleteTexture(texName); + + Gfx::Texture tex = m_device->CreateTexture(&shadowImg, m_defaultTexParams); + + m_texNameMap[texName] = tex; + m_revTexNameMap[tex] = texName; + } + } + + for (int i = 0; i < static_cast<int>( m_groundSpots.size() ); i++) + { + if (m_groundSpots[i].used == false || + m_groundSpots[i].radius == 0.0f) + { + m_groundSpots[i].drawRadius = 0.0f; + } + else + { + m_groundSpots[i].drawPos = m_groundSpots[i].pos; + m_groundSpots[i].drawRadius = m_groundSpots[i].radius; + } + } + + m_groundMark.drawPos = m_groundMark.pos; + m_groundMark.drawRadius = m_groundMark.radius; + m_groundMark.drawIntensity = m_groundMark.intensity; + + m_firstGroundSpot = false; } void CEngine::DrawShadow() @@ -3366,11 +3670,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; @@ -3386,7 +3692,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; @@ -3402,7 +3710,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; @@ -3510,7 +3820,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? { @@ -3526,7 +3837,6 @@ void CEngine::DrawShadow() m_device->SetRenderState(RENDER_STATE_LIGHTING, true); } -// STATUS: TESTED, VERIFIED void CEngine::DrawBackground() { if (m_skyMode && m_cloud->GetLevel() != 0.0f) // clouds ? @@ -3546,7 +3856,6 @@ void CEngine::DrawBackground() } } -// STATUS: TESTED void CEngine::DrawBackgroundGradient(const Color& up, const Color& down) { Math::Point p1(0.0f, 0.5f); @@ -3577,7 +3886,6 @@ void CEngine::DrawBackgroundGradient(const Color& up, const Color& down) AddStatisticTriangle(2); } -// Status: TESTED, VERIFIED void CEngine::DrawBackgroundImage() { Math::Point p1, p2; @@ -3586,7 +3894,7 @@ void CEngine::DrawBackgroundImage() p2.x = 1.0f; p2.y = 1.0f; -Math::Vector n = Math::Vector(0.0f, 0.0f, -1.0f); // normal + Math::Vector n = Math::Vector(0.0f, 0.0f, -1.0f); // normal float u1, u2, v1, v2; if (m_backgroundFull) @@ -3635,7 +3943,8 @@ Math::Vector n = Math::Vector(0.0f, 0.0f, -1.0f); // normal 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); @@ -3648,10 +3957,10 @@ void CEngine::DrawPlanet() m_planet->Draw(); // draws the planets } -// Status: PART_TESTED 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 @@ -3684,12 +3993,11 @@ void CEngine::DrawForegroundImage() AddStatisticTriangle(2); } -// Status: PART_TESTED void CEngine::DrawOverColor() { - // TODO: fuzzy compare? - 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); @@ -3703,11 +4011,6 @@ void CEngine::DrawOverColor() SetState(m_overMode); - // TODO: set also with m_overMode ? - m_device->SetRenderState(RENDER_STATE_DEPTH_WRITE, false); - m_device->SetRenderState(RENDER_STATE_LIGHTING, false); - m_device->SetRenderState(RENDER_STATE_FOG, false); - m_device->SetTransform(TRANSFORM_VIEW, m_matViewInterface); m_device->SetTransform(TRANSFORM_PROJECTION, m_matProjInterface); m_device->SetTransform(TRANSFORM_WORLD, m_matWorldInterface); @@ -3724,7 +4027,6 @@ void CEngine::DrawOverColor() AddStatisticTriangle(2); } -// Status: TESTED, VERIFIED void CEngine::DrawHighlight() { Math::Point min, max; @@ -3816,7 +4118,6 @@ void CEngine::DrawHighlight() m_device->DrawPrimitive(PRIMITIVE_LINE_STRIP, line, 3); } -// Status: TESTED, VERIFIED void CEngine::DrawMouse() { MouseMode mode = m_app->GetMouseMode(); @@ -3850,7 +4151,6 @@ void CEngine::DrawMouse() DrawMouseSprite(pos, m_mouseSize, m_mice[index].icon2); } -// Status: TESTED, VERIFIED void CEngine::DrawMouseSprite(Math::Point pos, Math::Point size, int icon) { if (icon == -1) @@ -3889,15 +4189,10 @@ void CEngine::DrawStats() if (!m_showStats) return; - std::stringstream str; - str << "Triangles: "; - str << m_statisticTriangle; - std::string triangleText = str.str(); - float height = m_text->GetAscent(FONT_COLOBOT, 12.0f); float width = 0.2f; - Math::Point pos(0.04f, 0.04f + height); + Math::Point pos(0.04f, 0.04f + 17 * height); SetState(ENG_RSTATE_OPAQUE_COLOR); @@ -3905,9 +4200,9 @@ void CEngine::DrawStats() VertexCol vertex[4] = { - VertexCol(Math::Vector(pos.x , pos.y - height, 0.0f), black), + VertexCol(Math::Vector(pos.x , pos.y - 17 * height, 0.0f), black), VertexCol(Math::Vector(pos.x , pos.y + height, 0.0f), black), - VertexCol(Math::Vector(pos.x + width, pos.y - height, 0.0f), black), + VertexCol(Math::Vector(pos.x + width, pos.y - 17 * height, 0.0f), black), VertexCol(Math::Vector(pos.x + width, pos.y + height, 0.0f), black) }; @@ -3915,7 +4210,107 @@ void CEngine::DrawStats() SetState(ENG_RSTATE_TEXT); - m_text->DrawText(triangleText, FONT_COLOBOT, 12.0f, pos, 1.0f, TEXT_ALIGN_LEFT, 0, Color(1.0f, 1.0f, 1.0f, 1.0f)); + std::stringstream str; + + str.str(""); + str << "Event processing: " << std::fixed << std::setprecision(2) << m_app->GetPerformanceCounterData(PCNT_EVENT_PROCESSING); + m_text->DrawText(str.str(), FONT_COLOBOT, 12.0f, pos, 1.0f, TEXT_ALIGN_LEFT, 0, Color(1.0f, 1.0f, 1.0f, 1.0f)); + + pos.y -= height; + pos.y -= height; + + + str.str(""); + str << "Frame update: " << std::fixed << std::setprecision(2) << m_app->GetPerformanceCounterData(PCNT_UPDATE_ALL); + m_text->DrawText(str.str(), FONT_COLOBOT, 12.0f, pos, 1.0f, TEXT_ALIGN_LEFT, 0, Color(1.0f, 1.0f, 1.0f, 1.0f)); + + pos.y -= height; + + str.str(""); + str << "Engine update: " << std::fixed << std::setprecision(2) << m_app->GetPerformanceCounterData(PCNT_UPDATE_ENGINE); + m_text->DrawText(str.str(), FONT_COLOBOT, 12.0f, pos, 1.0f, TEXT_ALIGN_LEFT, 0, Color(1.0f, 1.0f, 1.0f, 1.0f)); + + pos.y -= height; + + str.str(""); + str << "Particle update: " << std::fixed << std::setprecision(2) << m_app->GetPerformanceCounterData(PCNT_UPDATE_PARTICLE); + m_text->DrawText(str.str(), FONT_COLOBOT, 12.0f, pos, 1.0f, TEXT_ALIGN_LEFT, 0, Color(1.0f, 1.0f, 1.0f, 1.0f)); + + pos.y -= height; + + str.str(""); + str << "Game update: " << std::fixed << std::setprecision(2) << m_app->GetPerformanceCounterData(PCNT_UPDATE_GAME); + m_text->DrawText(str.str(), FONT_COLOBOT, 12.0f, pos, 1.0f, TEXT_ALIGN_LEFT, 0, Color(1.0f, 1.0f, 1.0f, 1.0f)); + + pos.y -= height; + + float otherUpdate = Math::Max(0.0f, m_app->GetPerformanceCounterData(PCNT_UPDATE_ALL) - + m_app->GetPerformanceCounterData(PCNT_UPDATE_ENGINE) - + m_app->GetPerformanceCounterData(PCNT_UPDATE_PARTICLE) - + m_app->GetPerformanceCounterData(PCNT_UPDATE_GAME)); + + str.str(""); + str << "Other update: " << std::fixed << std::setprecision(2) << otherUpdate; + m_text->DrawText(str.str(), FONT_COLOBOT, 12.0f, pos, 1.0f, TEXT_ALIGN_LEFT, 0, Color(1.0f, 1.0f, 1.0f, 1.0f)); + + pos.y -= height; + pos.y -= height; + + + str.str(""); + str << "Frame render: " << std::fixed << std::setprecision(2) << m_app->GetPerformanceCounterData(PCNT_RENDER_ALL); + m_text->DrawText(str.str(), FONT_COLOBOT, 12.0f, pos, 1.0f, TEXT_ALIGN_LEFT, 0, Color(1.0f, 1.0f, 1.0f, 1.0f)); + + pos.y -= height; + + str.str(""); + str << "Particle render: " << std::fixed << std::setprecision(2) << m_app->GetPerformanceCounterData(PCNT_RENDER_PARTICLE); + m_text->DrawText(str.str(), FONT_COLOBOT, 12.0f, pos, 1.0f, TEXT_ALIGN_LEFT, 0, Color(1.0f, 1.0f, 1.0f, 1.0f)); + + pos.y -= height; + + str.str(""); + str << "Water render: " << std::fixed << std::setprecision(2) << m_app->GetPerformanceCounterData(PCNT_RENDER_WATER); + m_text->DrawText(str.str(), FONT_COLOBOT, 12.0f, pos, 1.0f, TEXT_ALIGN_LEFT, 0, Color(1.0f, 1.0f, 1.0f, 1.0f)); + + pos.y -= height; + + str.str(""); + str << "Terrain render: " << std::fixed << std::setprecision(2) << m_app->GetPerformanceCounterData(PCNT_RENDER_TERRAIN); + m_text->DrawText(str.str(), FONT_COLOBOT, 12.0f, pos, 1.0f, TEXT_ALIGN_LEFT, 0, Color(1.0f, 1.0f, 1.0f, 1.0f)); + + pos.y -= height; + + str.str(""); + str << "Objects render: " << std::fixed << std::setprecision(2) << m_app->GetPerformanceCounterData(PCNT_RENDER_OBJECTS); + m_text->DrawText(str.str(), FONT_COLOBOT, 12.0f, pos, 1.0f, TEXT_ALIGN_LEFT, 0, Color(1.0f, 1.0f, 1.0f, 1.0f)); + + pos.y -= height; + + str.str(""); + str << "UI render: " << std::fixed << std::setprecision(2) << m_app->GetPerformanceCounterData(PCNT_RENDER_INTERFACE); + m_text->DrawText(str.str(), FONT_COLOBOT, 12.0f, pos, 1.0f, TEXT_ALIGN_LEFT, 0, Color(1.0f, 1.0f, 1.0f, 1.0f)); + + pos.y -= height; + + float otherRender = m_app->GetPerformanceCounterData(PCNT_RENDER_ALL) - + m_app->GetPerformanceCounterData(PCNT_RENDER_PARTICLE) - + m_app->GetPerformanceCounterData(PCNT_RENDER_WATER) - + m_app->GetPerformanceCounterData(PCNT_RENDER_TERRAIN) - + m_app->GetPerformanceCounterData(PCNT_RENDER_OBJECTS) - + m_app->GetPerformanceCounterData(PCNT_RENDER_INTERFACE); + + str.str(""); + str << "Other render: " << std::fixed << std::setprecision(2) << otherRender; + m_text->DrawText(str.str(), FONT_COLOBOT, 12.0f, pos, 1.0f, TEXT_ALIGN_LEFT, 0, Color(1.0f, 1.0f, 1.0f, 1.0f)); + + pos.y -= height; + pos.y -= height; + + + str.str(""); + str << "Triangles: " << m_statisticTriangle; + m_text->DrawText(str.str(), FONT_COLOBOT, 12.0f, pos, 1.0f, TEXT_ALIGN_LEFT, 0, Color(1.0f, 1.0f, 1.0f, 1.0f)); pos.y -= height; |