16
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-07-18 01:59:19 +02:00

Replace per-node text capture with camera-distance ring multi-pass

The previous nearest-first build captured every deferred visual node as text into a
sorted vector, which does not scale: one tomaszewo flora file alone holds 440k model
nodes (the scenery has 1M+), so the capture ran the process to ~7 GB and its
enumeration never finished.

Stream the visual nodes in camera-distance rings instead, with no per-node capture
(O(1) memory). The visual pass replays the twin once per ring (nearest first); a node
is built only when its squared distance to the camera -- sampled once when the visual
phase starts, so the partition is stable across passes -- falls in the current ring,
otherwise the rest of its body is skipped in O(1) by jumping over the v6 marker span.
Each node is therefore built exactly once, in roughly nearest-first order, through the
normal node path (instancing buckets unchanged). Explicit triangles/lines shapes have
no single position to ring-test by, so they build in the nearest ring pass only.

Reader gains skip_to_node_end() (remembers the served node's end and jumps the cursor
there); cParser::skipReplayNode() delegates it down the active include child.

Verified: td.scn builds 4 rings, no duplicates, no unexpected tokens, complete ~1s
after the infrastructure pass. tomaszewo stays memory-bounded (no OOM, no duplicates)
where the capture approach previously hung.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
maj00r
2026-06-23 17:41:46 +02:00
parent 1160bfecac
commit d7a3e1310a
6 changed files with 127 additions and 239 deletions

View File

@@ -888,6 +888,21 @@ void cParser::readReplayToken(std::string &out, bool ToLower, const char *Break)
out.clear();
}
bool cParser::skipReplayNode()
{
// a node's entries are contiguous within a single file, served by the deepest active
// include child -- delegate down to whichever parser is actually replaying it
if (mIncludeParser) { return mIncludeParser->skipReplayNode(); }
if (m_replay && m_reader && m_reader->skip_to_node_end())
{
// any tokens already pulled into the lookahead deque belong to the node we just
// skipped past (or earlier) -- drop them so the next read starts at the next node
tokens.clear();
return true;
}
return false;
}
std::vector<std::string> cParser::readParameters(cParser &Input)
{