diff options
| author | briaguya <70942617+briaguya0@users.noreply.github.com> | 2026-07-24 18:09:55 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-07-24 18:09:55 -0400 |
| commit | 4cae44160693e1beb562e39dc301bd42278be1f9 (patch) | |
| tree | 5d247f7821a6040221b4bf34d2cae2b87c42d23a /src/factories/oot/DeferredVtx.cpp | |
| parent | cd33252589a61d044138f449041a87adee2a8291 (diff) | |
oot support (#219)
Diffstat (limited to 'src/factories/oot/DeferredVtx.cpp')
| -rw-r--r-- | src/factories/oot/DeferredVtx.cpp | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/src/factories/oot/DeferredVtx.cpp b/src/factories/oot/DeferredVtx.cpp new file mode 100644 index 0000000..9ea76d0 --- /dev/null +++ b/src/factories/oot/DeferredVtx.cpp @@ -0,0 +1,128 @@ +#include "DeferredVtx.h" +#include "Companion.h" +#include "factories/DisplayListOverrides.h" +#include "n64/CommandMacros.h" +#include "spdlog/spdlog.h" +#include <algorithm> +#include <iomanip> +#include <sstream> + +// N64 vertex size in bytes (matching N64Vtx_t: 3*int16 + uint16 + 2*int16 + 4*uchar = 16) +static constexpr uint32_t kVtxSize = 16; + +// Deferred VTX consolidation state (ZAPD-style MergeConnectingVertexLists). +// ZAPD merges VTX per-DList (each DList has its own vertices map and merge pass). +// We collect VTX during each DList parse call and flush at the end of that parse. +namespace DeferredVtx { + +bool sDeferred = false; +std::vector<PendingVtx> sPendingList; + +void BeginDefer() { + sDeferred = true; + sPendingList.clear(); +} + +bool IsDeferred() { + return sDeferred; +} + +std::vector<PendingVtx> SaveAndClearPending() { + auto saved = std::move(sPendingList); + sPendingList.clear(); + return saved; +} + +void RestorePending(std::vector<PendingVtx>& saved) { + // Prepend saved items to current pending list (in case anything was added during the save) + saved.insert(saved.end(), sPendingList.begin(), sPendingList.end()); + sPendingList = std::move(saved); +} + +void AddPending(uint32_t addr, uint32_t count) { + sPendingList.push_back({addr, count}); +} + +// Flush pending VTX for a single DList: merge adjacent arrays and register assets. +// Called at the end of each DList parse() to match ZAPD's per-DList merge scope. +void FlushDeferred(const std::string& baseName) { + // Don't clear sDeferred here — it stays active for the entire room. + // Each DList parse flushes its own collected VTX. + auto pending = std::move(sPendingList); + sPendingList.clear(); + + if (pending.empty()) { + return; + } + + SPDLOG_INFO("VTX FlushDeferred: {} pending VTX for {}", pending.size(), baseName); + + // Sort by segment offset + std::sort(pending.begin(), pending.end(), + [](const PendingVtx& a, const PendingVtx& b) { + return SEGMENT_OFFSET(a.addr) < SEGMENT_OFFSET(b.addr); + }); + + // Merge adjacent/overlapping VTX arrays (ZAPD's MergeConnectingVertexLists algorithm). + // Two arrays merge if the first array's end >= the second's start. + struct MergedVtx { + uint32_t addr; // segment address of start + uint32_t endOff; // segment offset of end (exclusive) + }; + std::vector<MergedVtx> merged; + + for (auto& pv : pending) { + uint32_t startOff = SEGMENT_OFFSET(pv.addr); + uint32_t endOff = startOff + pv.count * kVtxSize; + + if (merged.empty() || startOff > merged.back().endOff) { + // New group + merged.push_back({pv.addr, endOff}); + } else { + // Extend existing group + if (endOff > merged.back().endOff) { + merged.back().endOff = endOff; + } + } + } + + // Register each merged VTX group as an asset + for (auto& mg : merged) { + uint32_t startOff = SEGMENT_OFFSET(mg.addr); + uint32_t totalBytes = mg.endOff - startOff; + uint32_t totalCount = totalBytes / kVtxSize; + + // Build proper symbol: baseName + "Vtx_" + 6-digit hex offset + std::ostringstream ss; + ss << baseName << "Vtx_" << std::uppercase << std::hex + << std::setfill('0') << std::setw(6) << startOff; + std::string symbol = ss.str(); + + SPDLOG_INFO("VTX consolidation: {} at 0x{:X} count={}", symbol, mg.addr, totalCount); + + // Look up the pre-declared VTX in YAML (should exist with enrichment) + auto registeredNode = Companion::Instance->GetNodeByAddr(mg.addr); + if (!registeredNode.has_value()) { + SPDLOG_WARN("Undeclared VTX at 0x{:X} — YAML enrichment incomplete", mg.addr); + } + + // Register overlap mappings for all pending addresses within this group. + if (registeredNode.has_value()) { + auto [fullPath, vtxNode] = registeredNode.value(); + auto overlapTuple = std::make_tuple(symbol, vtxNode); + for (auto& pv : pending) { + uint32_t pvOff = SEGMENT_OFFSET(pv.addr); + if (pvOff > startOff && pvOff < mg.endOff) { + GFXDOverride::RegisterVTXOverlap(pv.addr, overlapTuple); + } + } + } + } +} + +void EndDefer() { + sDeferred = false; + sPendingList.clear(); +} + +} // namespace DeferredVtx |
