16
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-07-21 12:29:18 +02:00

Store model position in the v7 node marker for O(1) ring skipping

The camera-ring visual load replays the twin once per distance ring, and each pass
had to read every node's header + X Y Z tokens (~8 tokens through the cParser pipeline)
just to decide whether the node is in the current ring -- expensive when a scenery has
a million flora instances.

Bump the twin format to v7: a visual model node's marker now carries its local position
(3 f32), captured at bake time from the node's first three numbers. The reader hands the
position out (scenery_binary_reader::node_position), and the deserializer ring-tests a
model and skips it in O(1) over the marker span, straight from the dispatch loop, without
deserialize_node decoding any of its tokens. deserialize_model uses the same marker
position for its own ring test so the two decisions agree exactly (a node near a ring
boundary can't be dropped by both adjacent rings). Shapes/older twins have no marker
position and fall back to the token-based test. The per-frame visual budget is factored
into VISUAL_BUDGET_MS.

Verified: td.scn rebakes to v7, no duplicates, no unexpected tokens, completes ~1s.
tomaszewo (1M+ flora) stays memory-bounded with no duplicates; full streaming is still
paced by walking every node per ring (the remaining cost is the replay pipeline itself,
which a spatial section index would address).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
maj00r
2026-06-23 18:09:03 +02:00
parent d7a3e1310a
commit 06409a54ea
5 changed files with 105 additions and 14 deletions

View File

@@ -62,6 +62,10 @@ class cParser //: public std::stringstream
// 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();
// local position of the node about to be replayed (the "node" token just read), if its
// v7 marker carried one (visual model nodes). lets the camera-ring load distance-test and
// skip a node without decoding its body. returns false for shapes / non-replay / older twins.
bool currentNodePosition( double &X, double &Y, double &Z );
// methods:
template <typename Type_>
cParser &
@@ -214,6 +218,10 @@ class cParser //: public std::stringstream
int m_bakenode_count { 0 }; // entries captured since "node" (1=node,...,5=type)
bool m_bakenode_visual { false };
std::string m_bakenode_end; // terminator token; empty until type classified
// v7: a model node's local position (entries 6,7,8 = X,Y,Z), stored in its marker so the
// camera-ring load can distance-test it without decoding the node body
bool m_bakenode_haspos { false };
double m_bakenode_pos[ 3 ] { 0.0, 0.0, 0.0 };
// flushes a node still open at end-of-file (or unknown type), so its buffer is written
void bakeFinishNode();
};