mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-07-22 10:29: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:
@@ -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)
|
||||
{
|
||||
|
||||
|
||||
@@ -57,6 +57,11 @@ class cParser //: public std::stringstream
|
||||
// true when this (top-level) file is served from a binary twin, i.e. a second
|
||||
// (visual) pass via restartReplay() is possible. false for a text/compile load.
|
||||
bool isReplaying() const { return m_replay; }
|
||||
// skips the rest of the node currently being replayed in O(1) (jump over its v6 marker
|
||||
// span), delegating to the active include child that is actually serving it. returns
|
||||
// false if the skip can't be done here (e.g. a text include with no binary twin), so the
|
||||
// caller can fall back to a token-by-token skip. used by the camera-ring visual load.
|
||||
bool skipReplayNode();
|
||||
// methods:
|
||||
template <typename Type_>
|
||||
cParser &
|
||||
|
||||
Reference in New Issue
Block a user