From 483dbdda2e40cf5109136d9e3742dc920f9954b0 Mon Sep 17 00:00:00 2001 From: gm-matthew <108370479+gm-matthew@users.noreply.github.com> Date: Thu, 2 Nov 2023 00:25:52 +0000 Subject: [PATCH] Add LOD switching and blending out culling nodes We're not blending between LODs yet as we're not sure of the best way to implement it Also implementing control bits for disable culling and enable model scale (needed for ECA and Harley) --- Src/Graphics/New3D/Model.cpp | 52 +++++++++++++++++++----------------- Src/Graphics/New3D/Model.h | 2 ++ Src/Graphics/New3D/New3D.cpp | 49 ++++++++++++++++++++++++--------- Src/Graphics/New3D/R3DData.h | 4 +-- 4 files changed, 68 insertions(+), 39 deletions(-) diff --git a/Src/Graphics/New3D/Model.cpp b/Src/Graphics/New3D/Model.cpp index d30994a..56eb473 100644 --- a/Src/Graphics/New3D/Model.cpp +++ b/Src/Graphics/New3D/Model.cpp @@ -4,12 +4,13 @@ namespace New3D { NodeAttributes::NodeAttributes() { - currentTexOffsetX = 0; - currentTexOffsetY = 0; - currentPage = 0; - currentClipStatus = Clip::INTERCEPT; - currentModelScale = 1.0f; - currentModelAlpha = 1.0; + currentTexOffsetX = 0; + currentTexOffsetY = 0; + currentPage = 0; + currentClipStatus = Clip::INTERCEPT; + currentModelScale = 1.0f; + currentModelAlpha = 1.0; + currentDisableCulling = false; } bool NodeAttributes::Push() @@ -23,12 +24,13 @@ bool NodeAttributes::Push() return false; } - na.page = currentPage; - na.texOffsetX = currentTexOffsetX; - na.texOffsetY = currentTexOffsetY; - na.clip = currentClipStatus; - na.modelScale = currentModelScale; - na.modelAlpha = currentModelAlpha; + na.page = currentPage; + na.texOffsetX = currentTexOffsetX; + na.texOffsetY = currentTexOffsetY; + na.clip = currentClipStatus; + na.modelScale = currentModelScale; + na.modelAlpha = currentModelAlpha; + na.disableCulling = currentDisableCulling; m_vecAttribs.emplace_back(na); @@ -43,12 +45,13 @@ bool NodeAttributes::Pop() auto &last = m_vecAttribs.back(); - currentPage = last.page; - currentTexOffsetX = last.texOffsetX; - currentTexOffsetY = last.texOffsetY; - currentClipStatus = last.clip; - currentModelScale = last.modelScale; - currentModelAlpha = last.modelAlpha; + currentPage = last.page; + currentTexOffsetX = last.texOffsetX; + currentTexOffsetY = last.texOffsetY; + currentClipStatus = last.clip; + currentModelScale = last.modelScale; + currentModelAlpha = last.modelAlpha; + currentDisableCulling = last.disableCulling; m_vecAttribs.pop_back(); @@ -62,12 +65,13 @@ bool NodeAttributes::StackLimit() void NodeAttributes::Reset() { - currentPage = 0; - currentTexOffsetX = 0; - currentTexOffsetY = 0; - currentClipStatus = Clip::INTERCEPT; - currentModelScale = 1.0f; - currentModelAlpha = 1.0f; + currentPage = 0; + currentTexOffsetX = 0; + currentTexOffsetY = 0; + currentClipStatus = Clip::INTERCEPT; + currentModelScale = 1.0f; + currentModelAlpha = 1.0f; + currentDisableCulling = false; m_vecAttribs.clear(); } diff --git a/Src/Graphics/New3D/Model.h b/Src/Graphics/New3D/Model.h index 62daf8d..97837d4 100644 --- a/Src/Graphics/New3D/Model.h +++ b/Src/Graphics/New3D/Model.h @@ -242,6 +242,7 @@ public: Clip currentClipStatus; float currentModelScale; float currentModelAlpha; + bool currentDisableCulling; private: @@ -253,6 +254,7 @@ private: Clip clip; float modelScale; float modelAlpha; // from culling node + bool disableCulling; }; std::vector m_vecAttribs; }; diff --git a/Src/Graphics/New3D/New3D.cpp b/Src/Graphics/New3D/New3D.cpp index dff3b02..f64e2a4 100644 --- a/Src/Graphics/New3D/New3D.cpp +++ b/Src/Graphics/New3D/New3D.cpp @@ -559,11 +559,12 @@ bool CNew3D::DrawModel(UINT32 modelAddr) -------- -------- -------- -----x-- Valid color table -------- -------- -------- ------xx Node type(0 = viewport, 1 = root node, 2 = culling node) - 0x01, 0x02 only present on Step 2 + + 0x01, 0x02 only present on Step 1.5+ 0x01: xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx-- Model scale (float32) last 2 bits are control words -------- -------- -------- ------x- Disable culling -------- -------- -------- -------x Valid model scale + 0x02 : -------- -------- x------- -------- Texture replace -------- -------- -x------ -------- Switch bank -------- -------- --xxxxxx x------- X offset @@ -595,7 +596,7 @@ void CNew3D::DescendCullingNode(UINT32 addr) { enum class NodeType { undefined = -1, viewport = 0, rootNode = 1, cullingNode = 2 }; - const UINT32 *node, *lodTable; + const UINT32 *node, *lodPtr; UINT32 matrixOffset, child1Ptr, sibling2Ptr; BBox bbox; UINT16 uCullRadius; @@ -645,10 +646,11 @@ void CNew3D::DescendCullingNode(UINT32 addr) if (!m_offset) { // Step 1.5+ - float modelScale = Util::Uint32AsFloat(node[1]); - if (modelScale > std::numeric_limits::min()) { - m_nodeAttribs.currentModelScale = modelScale; - } + if (node[0x01] & 1) + m_nodeAttribs.currentModelScale = Util::Uint32AsFloat(node[0x01] & ~3); // mask out control bits + + if (node[0x01] & 2) + m_nodeAttribs.currentDisableCulling = true; // apply texture offsets, else retain current ones if ((node[0x02] & 0x8000)) { @@ -660,8 +662,6 @@ void CNew3D::DescendCullingNode(UINT32 addr) } } - m_nodeAttribs.currentModelAlpha = 1; // TODO fade out if required - // Apply matrix and translation m_modelMat.PushMatrix(); @@ -705,19 +705,42 @@ void CNew3D::DescendCullingNode(UINT32 addr) } } - if (m_nodeAttribs.currentClipStatus != Clip::OUTSIDE && fCullRadius > R3DFloat::Pro16BitFltMin) { + float LODscale = fBlendRadius * m_nodeAttribs.currentModelScale / std::abs(m_modelMat.currentMatrix[14]); + + LODFeatureType lodTableEntry = m_LODBlendTable->table[lodTablePointer]; + + if (m_nodeAttribs.currentDisableCulling) + { + m_nodeAttribs.currentModelAlpha = 1.0f; + } + else + { + float nodeAlpha = lodTableEntry.lod[3].blendFactor * (LODscale - lodTableEntry.lod[3].deleteSize); + nodeAlpha = std::clamp(nodeAlpha, 0.0f, 1.0f); + m_nodeAttribs.currentModelAlpha *= nodeAlpha; // alpha of each node multiples by the alpha of its parent + } + + if (m_nodeAttribs.currentClipStatus != Clip::OUTSIDE && m_nodeAttribs.currentModelAlpha > 0.0f) { // Descend down first link if ((node[0x00] & 0x08)) // 4-element LOD table { - lodTable = TranslateCullingAddress(child1Ptr); + lodPtr = TranslateCullingAddress(child1Ptr); - if (NULL != lodTable) { + // determine which LOD to use; we do not currently blend between LODs + int modelLOD; + for (modelLOD = 0; modelLOD < 3; modelLOD++) + { + if (LODscale >= lodTableEntry.lod[modelLOD].deleteSize) + break; + } + + if (NULL != lodPtr) { if ((node[0x03 - m_offset] & 0x20000000)) { - DescendCullingNode(lodTable[0] & 0xFFFFFF); + DescendCullingNode(lodPtr[modelLOD] & 0xFFFFFF); } else { - DrawModel(lodTable[0] & 0xFFFFFF); //TODO + DrawModel(lodPtr[modelLOD] & 0xFFFFFF); } } } diff --git a/Src/Graphics/New3D/R3DData.h b/Src/Graphics/New3D/R3DData.h index a289f7c..ecc66d6 100644 --- a/Src/Graphics/New3D/R3DData.h +++ b/Src/Graphics/New3D/R3DData.h @@ -3,8 +3,8 @@ struct LOD { - float startRange; // possibly specified as angles also, yeah who knows >_< - float deleteRange; + float deleteSize; + float blendFactor; }; struct LODFeatureType