mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-07-21 19:29:19 +02:00
Stream deferred visual nodes in camera-distance order (nearest first)
The progressive load previously streamed the deferred visual nodes (3d model instances + terrain shapes/lines) in file order, so distant scenery could load before the player's surroundings. This builds them nearest-camera first instead. The visual pass now runs in two steps. Enumeration replays the twin and captures each visual node verbatim (its resolved tokens as text -- numbers round-trip losslessly through cParser) together with the transform/group context it was read under and, for models, its transformed world position. Once the replay is exhausted the records are sorted by squared distance to the camera (terrain shapes first so the ground appears before the props on it), then built a budgeted slice per frame through the normal node path with the captured transform and group restored -- so placement, grouping and the per-cell instance buckets come out identical to an in-order load. Two supporting fixes make out-of-order/late insertion correct: - a cell/section whose geometry was already baked (the renderer finalised it before a deferred node arrived) now appends the new shape/lines straight into its live geometry bank instead of merging into vertex-freed geometry, which would silently drop it; create_geometry() remembers the bank for every cell. - events that bind to visual model instances (lights/animation/texture/visible) are deferred from InitEvents() to a new InitInstanceEvents() run after the visual nodes are built, so their target models exist when they initialise. Verified on td.scn: playable ~2s, 540 deferred nodes enumerated and built nearest-first ~0.5s later, no duplicate instances. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -275,6 +275,16 @@ basic_cell::insert( shape_node Shape ) {
|
||||
shapedata.translucent ?
|
||||
m_shapestranslucent :
|
||||
m_shapesopaque );
|
||||
// if this cell's geometry was already baked (deferred visual streaming inserting into a
|
||||
// section the renderer already finalised), don't try to merge into an existing shape
|
||||
// whose CPU-side vertices were freed at bake time -- add the shape standalone and upload
|
||||
// it straight into the live bank, otherwise it would never become visible.
|
||||
if( m_geometrybank != null_handle ) {
|
||||
Shape.origin( m_area.center );
|
||||
shapes.emplace_back( Shape );
|
||||
shapes.back().create_geometry( m_geometrybank );
|
||||
return;
|
||||
}
|
||||
for( auto &targetshape : shapes ) {
|
||||
// try to merge shapes with matching view ranges...
|
||||
auto const &targetshapedata { targetshape.data() };
|
||||
@@ -302,6 +312,14 @@ basic_cell::insert( lines_node Lines ) {
|
||||
m_active = true;
|
||||
|
||||
auto const &linesdata { Lines.data() };
|
||||
// see the matching note in insert( shape_node ): once the cell is baked, append the new
|
||||
// lines straight into the live bank rather than merging into vertex-freed geometry.
|
||||
if( m_geometrybank != null_handle ) {
|
||||
Lines.origin( m_area.center );
|
||||
m_lines.emplace_back( Lines );
|
||||
m_lines.back().create_geometry( m_geometrybank );
|
||||
return;
|
||||
}
|
||||
for( auto &targetlines : m_lines ) {
|
||||
// try to merge shapes with matching view ranges...
|
||||
auto const &targetlinesdata { targetlines.data() };
|
||||
@@ -632,6 +650,10 @@ basic_cell::center( glm::dvec3 Center ) {
|
||||
void
|
||||
basic_cell::create_geometry( gfx::geometrybank_handle const &Bank ) {
|
||||
|
||||
// remember the bank for *all* cells (even ones empty at bake time): a deferred visual
|
||||
// node may activate this cell later, and insert() needs the live bank to upload into.
|
||||
m_geometrybank = Bank;
|
||||
|
||||
if( false == m_active ) { return; } // nothing to do here
|
||||
|
||||
for( auto &shape : m_shapesopaque ) { shape.create_geometry( Bank ); }
|
||||
@@ -850,6 +872,14 @@ basic_section::insert( shape_node Shape ) {
|
||||
}
|
||||
else {
|
||||
// large, opaque shapes are placed on section level
|
||||
// if the section was already baked (deferred visual streaming), append straight into
|
||||
// the live bank instead of merging into vertex-freed geometry -- see basic_cell::insert.
|
||||
if( true == m_geometrycreated ) {
|
||||
Shape.origin( m_area.center );
|
||||
m_shapes.emplace_back( Shape );
|
||||
m_shapes.back().create_geometry( m_geometrybank );
|
||||
return;
|
||||
}
|
||||
for( auto &shape : m_shapes ) {
|
||||
// check first if the shape can't be merged with one of the shapes already present in the section
|
||||
if( true == shape.merge( Shape ) ) {
|
||||
|
||||
@@ -234,6 +234,11 @@ public:
|
||||
} m_directories;
|
||||
// animation of owned items (legacy code, clean up along with track refactoring)
|
||||
bool m_geometrycreated { false };
|
||||
// bank this cell's geometry was baked into; remembered so shapes/lines inserted
|
||||
// *after* the section was first rendered (deferred visual streaming) can be appended
|
||||
// straight into the live bank instead of being silently dropped. null until the owning
|
||||
// section bakes its geometry, which doubles as the "already baked" signal.
|
||||
gfx::geometrybank_handle m_geometrybank {};
|
||||
unsigned int m_framestamp { 0 }; // id of last rendered gfx frame
|
||||
TTrack *tTrackAnim = nullptr; // obiekty do przeliczenia animacji
|
||||
command_relay m_relay;
|
||||
|
||||
@@ -40,6 +40,13 @@ public:
|
||||
// returns current active group, or null_handle if group stack is empty
|
||||
group_handle
|
||||
handle() const;
|
||||
// makes Group the active group for subsequent inserts, without creating a new group.
|
||||
// used by deferred (camera-ordered) visual loading to re-attach a node to the group it
|
||||
// was originally read under during the enumeration pass. must be paired with pop_active().
|
||||
void
|
||||
push_active( scene::group_handle const Group ) { m_activegroup.push( Group ); }
|
||||
void
|
||||
pop_active() { if( false == m_activegroup.empty() ) { m_activegroup.pop(); } }
|
||||
// places provided node in specified group
|
||||
void
|
||||
insert( scene::group_handle const Group, scene::basic_node *Node );
|
||||
|
||||
Reference in New Issue
Block a user