terra_range( new ssgRangeSelector ),
rwy_lights_range( new ssgRangeSelector ),
loaded(false),
- pending_models(0)
+ pending_models(0),
+ free_tracker(0)
{
nodes.clear();
#endif
+// Free "n" leaf elements of an ssg tree. returns the number of
+// elements freed. An empty branch node is considered a leaf. This
+// is intended to spread the load of freeing a complex tile out over
+// several frames.
+static int fgPartialFreeSSGtree( ssgBranch *b, int n ) {
+ if ( n > 0 ) {
+ // we still have some delete budget left
+ int num_deletes = 0;
+ for ( int i = 0; i < b->getNumKids(); ++i ) {
+ ssgEntity *kid = b->getKid(i);
+ if ( kid->isAKindOf( ssgTypeBranch() ) ) {
+ int result = fgPartialFreeSSGtree( (ssgBranch *)kid, n );
+ num_deletes += result;
+ n -= result;
+ if ( kid->getNumKids() == 0 ) {
+ b->removeKid(i);
+ num_deletes++;
+ n--;
+ }
+ if ( n < 0 ) {
+ break;
+ }
+ } else {
+ b->removeKid(i);
+ num_deletes++;
+ }
+ }
+ return num_deletes;
+ } else {
+ return 0;
+ }
+}
+
+
// Clean up the memory used by this tile and delete the arrays used by
// ssg as well as the whole ssg branch
-void FGTileEntry::free_tile() {
+bool FGTileEntry::free_tile() {
int i;
- SG_LOG( SG_TERRAIN, SG_INFO,
- "FREEING TILE = (" << tile_bucket << ")" );
-
+ int delete_size = 100;
SG_LOG( SG_TERRAIN, SG_DEBUG,
- " deleting " << nodes.size() << " nodes" );
- nodes.clear();
+ "FREEING TILE = (" << tile_bucket << ")" );
- // delete the ssg structures
- SG_LOG( SG_TERRAIN, SG_DEBUG,
- " deleting (leaf data) vertex, normal, and "
- << " texture coordinate arrays" );
+ if ( !(free_tracker & NODES) ) {
+ SG_LOG( SG_TERRAIN, SG_DEBUG,
+ " deleting " << nodes.size() << " nodes" );
+ nodes.clear();
- for ( i = 0; i < (int)vec3_ptrs.size(); ++i ) {
- delete [] vec3_ptrs[i];
- }
- vec3_ptrs.clear();
+ free_tracker |= NODES;
+ } else if ( !(free_tracker & VEC_PTRS) ) {
+ // delete the vector pointers
+ SG_LOG( SG_TERRAIN, SG_DEBUG,
+ " deleting (leaf data) vertex, normal, and "
+ << " texture coordinate arrays" );
- for ( i = 0; i < (int)vec2_ptrs.size(); ++i ) {
- delete [] vec2_ptrs[i];
- }
- vec2_ptrs.clear();
-
- for ( i = 0; i < (int)index_ptrs.size(); ++i ) {
- delete index_ptrs[i];
- }
- index_ptrs.clear();
+ for ( i = 0; i < (int)vec3_ptrs.size(); ++i ) {
+ delete [] vec3_ptrs[i];
+ }
+ vec3_ptrs.clear();
- // delete the terrain branch (this should already have been
- // disconnected from the scene graph)
- ssgDeRefDelete( terra_transform );
+ for ( i = 0; i < (int)vec2_ptrs.size(); ++i ) {
+ delete [] vec2_ptrs[i];
+ }
+ vec2_ptrs.clear();
- if ( gnd_lights_transform ) {
- // delete the terrain lighting branch (this should already have been
- // disconnected from the scene graph)
- ssgDeRefDelete( gnd_lights_transform );
- }
+ for ( i = 0; i < (int)index_ptrs.size(); ++i ) {
+ delete index_ptrs[i];
+ }
+ index_ptrs.clear();
- if ( rwy_lights_transform ) {
+ free_tracker |= VEC_PTRS;
+ } else if ( !(free_tracker & TERRA_NODE) ) {
+ // delete the terrain branch (this should already have been
+ // disconnected from the scene graph)
+ SG_LOG( SG_TERRAIN, SG_DEBUG, "FREEING terra_transform" );
+ if ( fgPartialFreeSSGtree( terra_transform, delete_size ) == 0 ) {
+ ssgDeRefDelete( terra_transform ); // polish off the parent
+ free_tracker |= TERRA_NODE;
+ }
+ } else if ( !(free_tracker & GROUND_LIGHTS) && gnd_lights_transform ) {
+ // delete the terrain lighting branch (this should already have been
+ // disconnected from the scene graph)
+ SG_LOG( SG_TERRAIN, SG_DEBUG, "FREEING gnd_lights_transform" );
+ if ( fgPartialFreeSSGtree( gnd_lights_transform, delete_size ) == 0 ) {
+ ssgDeRefDelete( gnd_lights_transform ); // polish off the parent
+ free_tracker |= GROUND_LIGHTS;
+ }
+ } else if ( !(free_tracker & RWY_LIGHTS) && rwy_lights_transform ) {
// delete the terrain lighting branch (this should already have been
// disconnected from the scene graph)
- ssgDeRefDelete( rwy_lights_transform );
- }
-
- // ADA
- if ( lightmaps_transform ) {
+ SG_LOG( SG_TERRAIN, SG_DEBUG, "FREEING rwy_lights_transform" );
+ if ( fgPartialFreeSSGtree( rwy_lights_transform, delete_size ) == 0 ) {
+ ssgDeRefDelete( rwy_lights_transform ); // polish off the parent
+ free_tracker |= RWY_LIGHTS;
+ }
+ } else if ( !(free_tracker & LIGHTMAPS) && lightmaps_transform ) {
+ // ADA
// delete the terrain lighting branch (this should already have been
// disconnected from the scene graph)
- ssgDeRefDelete( lightmaps_transform );
+ SG_LOG( SG_TERRAIN, SG_DEBUG, "FREEING lightmaps_transform" );
+ if ( fgPartialFreeSSGtree( lightmaps_transform, delete_size ) == 0 ) {
+ ssgDeRefDelete( lightmaps_transform ); // polish off the parent
+ free_tracker |= LIGHTMAPS;
+ }
+ } else {
+ return true;
}
- // ADA
+
+ // if we fall down to here, we still have work todo, return false
+ return false;
}
state( Start ),
current_tile( NULL ),
vis( 16000 ),
- counter_hack(0),
- max_cache_size(100)
+ max_cache_size(100),
+ counter_hack(0)
{
}
if ( t == NULL ) {
// make space in the cache
- while ( tile_cache.get_size() > max_cache_size ) {
+ while ( (int)tile_cache.get_size() > max_cache_size ) {
long index = tile_cache.get_oldest_tile();
if ( index >= 0 ) {
FGTileEntry *old = tile_cache.get_tile( index );
+ old->disconnect_ssg_nodes();
delete_queue.push( old );
tile_cache.clear_entry( index );
} else {
globals->get_scenery()->get_center() );
}
+
int FGTileMgr::update( double lon, double lat, double visibility_meters,
sgdVec3 abs_pos_vector, SGBucket p_current,
SGBucket p_previous, Point3D center ) {
// cout << "Adding ssg nodes for "
}
+ // cout << "delete queue = " << delete_queue.size() << endl;
if ( !delete_queue.empty() ) {
FGTileEntry* e = delete_queue.front();
- delete_queue.pop();
- e->disconnect_ssg_nodes();
- e->free_tile();
- delete e;
+ if ( e->free_tile() ) {
+ delete_queue.pop();
+ delete e;
+ }
}
// no reason to update this if we haven't moved...
schedule_needed(fgGetDouble("/environment/visibility-m"), current_bucket);
}
+
// check and set current tile and scenery center...
void FGTileMgr::setCurrentTile(double longitude, double latitude) {
}
}
+
int FGTileMgr::updateCurrentElevAtPos(sgdVec3 abs_pos_vector, Point3D center) {
sgdVec3 sc;
return hit;
}
+
void FGTileMgr::prep_ssg_nodes(float vis) {
// traverse the potentially viewable tile list and update range
}
+
void FGTileMgr::prep_ssg_nodes(float vis, sgVec3 up, Point3D center) {
// traverse the potentially viewable tile list and update range