1
0
Fork 0

(Hopefully) fixed bug which caused corrupt entries to be loaded into the

scene graph when a tile shift occured while the tile load queue was not
  empty.
This commit is contained in:
curt 1999-07-04 07:37:30 +00:00
parent 6efea97fb0
commit e5a87cf9fa
5 changed files with 194 additions and 62 deletions

View file

@ -129,34 +129,39 @@ FGTileCache::exists( const FGBucket& p )
void
FGTileCache::fill_in( int index, const FGBucket& p )
{
// cout << "FILL IN CACHE ENTRY = " << index << endl;
// Load the appropriate data file and build tile fragment list
FGPath tile_path( current_options.get_fg_root() );
tile_path.append( "Scenery" );
tile_path.append( p.gen_base_path() );
tile_path.append( p.gen_index_str() );
tile_cache[index].mark_loaded();
tile_cache[index].tile_bucket = p;
tile_cache[index].branch_ptr = new ssgTransform;
tile_cache[index].select_ptr = new ssgSelector;
tile_cache[index].transform_ptr = new ssgTransform;
tile_cache[index].range_ptr = new ssgRangeSelector;
ssgBranch *new_tile = fgObjLoad( tile_path.str(), &tile_cache[index] );
if ( new_tile != NULL ) {
tile_cache[index].range_ptr->addKid( new_tile );
}
tile_cache[index].branch_ptr->addKid( tile_cache[index].range_ptr );
terrain->addKid( tile_cache[index].branch_ptr );
tile_cache[index].transform_ptr->addKid( tile_cache[index].range_ptr );
tile_cache[index].select_ptr->addKid( tile_cache[index].transform_ptr );
terrain->addKid( tile_cache[index].select_ptr );
// cout << " ncount before = " << tile_cache[index].ncount << "\n";
// cout << " fragments before = " << tile_cache[index].fragment_list.size()
// << "\n";
string apt_path = tile_path.str();
apt_path += ".apt";
fgAptGenerate( apt_path, &tile_cache[index] );
// cout << " ncount after = " << tile_cache[index].ncount << "\n";
// cout << " fragments after = " << tile_cache[index].fragment_list.size()
// << "\n";
if ( tile_cache[index].is_scheduled_for_cache() ) {
// cout << "FOUND ONE SCHEDULED FOR CACHE" << endl;
// load, but not needed now so disable
tile_cache[index].mark_loaded();
tile_cache[index].ssg_disable();
tile_cache[index].select_ptr->select(0);
} else {
// cout << "FOUND ONE READY TO LOAD" << endl;
tile_cache[index].mark_loaded();
tile_cache[index].select_ptr->select(1);
}
}

View file

@ -89,17 +89,17 @@ FGTileEntry::free_tile()
// delete the ssg branch
// make sure we have a sane number of parents
int pcount = branch_ptr->getNumParents();
int pcount = select_ptr->getNumParents();
if ( pcount > 0 ) {
// find the first parent (should only be one)
ssgBranch *parent = branch_ptr->getParent( 0 ) ;
ssgBranch *parent = select_ptr->getParent( 0 ) ;
// find the number of kids this parent has
int kcount = parent->getNumKids();
// find the kid that matches our original branch_ptr
// find the kid that matches our original select_ptr
bool found_kid = false;
for ( int i = 0; i < kcount; ++i ) {
ssgEntity *kid = parent->getKid( i );
if ( kid == branch_ptr ) {
if ( kid == select_ptr ) {
FG_LOG( FG_TERRAIN, FG_INFO,
"Found a kid to delete " << kid);
found_kid = true;
@ -118,3 +118,37 @@ FGTileEntry::free_tile()
}
// when a tile is still in the cache, but not in the immediate draw l
// ist, it can still remain in the scene graph, but we use a range
// selector to disable it from ever being drawn.
void
FGTileEntry::ssg_disable() {
// cout << "TILE STATE = " << state << endl;
if ( state == Scheduled_for_use ) {
state = Scheduled_for_cache;
} else if ( (state == Loaded) || (state == Cached) ) {
state = Cached;
// cout << "DISABLING SSG NODE" << endl;
select_ptr->select(0);
#if 0
// set a really tiny range
// cout << "SETTING TINY RANGE" << endl;
float ranges[2];
ranges[0] = 0.0f;
ranges[1] = 0.00001f;
range_ptr->setRanges( ranges, 2 );
// transform to a long way away
// cout << "MOVING FAR AWAY" << endl;
sgCoord sgcoord;
sgSetCoord( &sgcoord, 999999.0, 999999.0, 999999.0, 0.0, 0.0, 0.0 );
transform_ptr->setTransform( &sgcoord );
#endif
} else {
FG_LOG( FG_TERRAIN, FG_ALERT,
"Trying to disable an unused tile! Dying" );
exit(-1);
}
// cout << "TILE STATE = " << state << endl;
}

View file

@ -73,8 +73,10 @@ private:
// Tile state
enum tile_state {
Unused = 0,
Scheduled = 1,
Loaded = 2
Scheduled_for_use = 1,
Scheduled_for_cache = 2,
Loaded = 3,
Cached = 4
};
public:
@ -112,6 +114,7 @@ public:
// ssg tree structure for this tile is as follows:
// ssgRoot(scene)
// - ssgBranch(terrain)
// - ssgSelector(tile)
// - ssgTransform(tile)
// - ssgRangeSelector(tile)
// - ssgEntity(tile)
@ -120,11 +123,14 @@ public:
// ...
// - kidn(fan)
// pointer to ssg range selector for this tile
ssgRangeSelector *range_ptr;
// selector (turn tile on/off)
ssgSelector *select_ptr;
// pointer to ssg transform for this tile
ssgTransform *branch_ptr;
ssgTransform *transform_ptr;
// pointer to ssg range selector for this tile
ssgRangeSelector *range_ptr;
public:
@ -189,11 +195,24 @@ public:
}
inline bool is_unused() const { return state == Unused; }
inline bool is_scheduled_for_use() const {
return state == Scheduled_for_use;
}
inline bool is_scheduled_for_cache() const {
return state == Scheduled_for_cache;
}
inline bool is_loaded() const { return state == Loaded; }
inline void mark_unused() { state = Unused; }
inline void mark_scheduled() { state = Scheduled; }
inline void mark_scheduled_for_use() { state = Scheduled_for_use; }
inline void mark_scheduled_for_cache() { state = Scheduled_for_use; }
inline void mark_loaded() { state = Loaded; }
// when a tile is still in the cache, but not in the immediate
// draw l ist, it can still remain in the scene graph, but we use
// a range selector to disable it from ever being drawn.
void ssg_disable();
};

View file

@ -61,6 +61,9 @@
#endif
extern ssgRoot *scene;
// the tile manager
FGTileMgr global_tile_mgr;
@ -93,21 +96,40 @@ int FGTileMgr::init( void ) {
// schedule a tile for loading
void FGTileMgr::sched_tile( const FGBucket& b, int *index ) {
static void disable_tile( int cache_index ) {
// see if tile already exists in the cache
*index = global_tile_cache.exists( b );
if ( *index < 0 ) {
// find the next availabel cache entry and mark it as scheduled
*index = global_tile_cache.next_avail();
FGTileEntry *t = global_tile_cache.get_tile( *index );
t->mark_scheduled();
// cout << "DISABLING CACHE ENTRY = " << cache_index << endl;
FGTileEntry *t = global_tile_cache.get_tile( cache_index );
t->ssg_disable();
}
// schedule a tile for loading
int FGTileMgr::sched_tile( const FGBucket& b ) {
// see if tile already exists in the cache
int cache_index = global_tile_cache.exists( b );
if ( cache_index >= 0 ) {
// tile exists in cache, reenable it.
// cout << "REENABLING DISABLED TILE" << endl;
FGTileEntry *t = global_tile_cache.get_tile( cache_index );
t->select_ptr->select( 1 );
t->mark_loaded();
} else {
// find the next available cache entry and mark it as
// scheduled
cache_index = global_tile_cache.next_avail();
FGTileEntry *t = global_tile_cache.get_tile( cache_index );
t->mark_scheduled_for_use();
// register a load request
FGLoadRec request;
request.b = b;
request.index = *index;
request.cache_index = cache_index;
load_queue.push_back( request );
}
return cache_index;
}
@ -340,6 +362,40 @@ FGTileMgr::current_elev( double lon, double lat, const Point3D& abs_view_pos ) {
}
// Determine scenery altitude via ssg. Normally this just happens
// when we render the scene, but we'd also like to be able to do this
// explicitely. lat & lon are in radians. view_pos in current world
// coordinate translated near (0,0,0) (in meters.) Returns result in
// meters.
double
FGTileMgr::current_elev_ssg( const Point3D& abs_view_pos,
const Point3D& view_pos )
{
ssgHit *results ;
// cout << "view pos = " << view_pos << endl;
// cout << "abs view pos = " << abs_view_pos << endl;
sgMat4 m;
sgMakeTransMat4( m, view_pos.x(), view_pos.y(), view_pos.z() );
sgVec3 s;
sgSetVec3(s, -abs_view_pos.x(), -abs_view_pos.y(), -abs_view_pos.z() );
int num_hits = ssgLOS ( scene, s, m, &results ) ;
for ( int i = 0 ; i < num_hits ; i++ ) {
ssgHit *h = &(results [ i ]) ;
cout << "got a hit!" << endl;
/* Do something with 'h' */
}
FG_LOG( FG_TERRAIN, FG_INFO, "(ssg) no terrain intersection found" );
return 0.0;
}
// given the current lon/lat, fill in the array of local chunks. If
// the chunk isn't already in the cache, then read it from disk.
int FGTileMgr::update( void ) {
@ -368,7 +424,7 @@ int FGTileMgr::update( void ) {
} else if ( (state == Start) || (state == Inited) ) {
state = Running;
// First time through or we have teleporte, initialize the
// First time through or we have teleported, initialize the
// system and load all relavant tiles
FG_LOG( FG_TERRAIN, FG_INFO, "Updating Tile list for " << p1 );
@ -389,7 +445,7 @@ int FGTileMgr::update( void ) {
p2 = fgBucketOffset( f->get_Longitude() * RAD_TO_DEG,
f->get_Latitude() * RAD_TO_DEG,
0, 0 );
sched_tile( p2, &tiles[(dh*tile_diameter) + dw]);
tiles[(dh*tile_diameter) + dw] = sched_tile( p2 );
for ( i = 3; i <= tile_diameter; i = i + 2 ) {
int span = i / 2;
@ -399,7 +455,7 @@ int FGTileMgr::update( void ) {
p2 = fgBucketOffset( f->get_Longitude() * RAD_TO_DEG,
f->get_Latitude() * RAD_TO_DEG,
j, -span );
sched_tile( p2, &tiles[((dh-span)*tile_diameter) + dw+j]);
tiles[((dh-span)*tile_diameter) + dw+j] = sched_tile( p2 );
}
// top row
@ -407,7 +463,7 @@ int FGTileMgr::update( void ) {
p2 = fgBucketOffset( f->get_Longitude() * RAD_TO_DEG,
f->get_Latitude() * RAD_TO_DEG,
j, span );
sched_tile( p2, &tiles[((dh+span)*tile_diameter) + dw+j]);
tiles[((dh+span)*tile_diameter) + dw+j] = sched_tile( p2 );
}
// middle rows
@ -415,11 +471,11 @@ int FGTileMgr::update( void ) {
p2 = fgBucketOffset( f->get_Longitude() * RAD_TO_DEG,
f->get_Latitude() * RAD_TO_DEG,
-span, j );
sched_tile( p2, &tiles[((dh+j)*tile_diameter) + dw-span]);
tiles[((dh+j)*tile_diameter) + dw-span] = sched_tile( p2 );
p2 = fgBucketOffset( f->get_Longitude() * RAD_TO_DEG,
f->get_Latitude() * RAD_TO_DEG,
span, j );
sched_tile( p2, &tiles[((dh+j)*tile_diameter) + dw+span]);
tiles[((dh+j)*tile_diameter) + dw+span] = sched_tile( p2 );
}
}
@ -430,7 +486,7 @@ int FGTileMgr::update( void ) {
p2 = fgBucketOffset( f->get_Longitude() * RAD_TO_DEG,
f->get_Latitude() * RAD_TO_DEG,
i - dw, j -dh );
sched_tile( p2, &tiles[(j*tile_diameter) + i]);
tiles[(j*tile_diameter) + i] = sched_tile( p2 );
}
} */
@ -443,7 +499,7 @@ int FGTileMgr::update( void ) {
FGLoadRec pending = load_queue.front();
load_queue.pop_front();
load_tile( pending.b, pending.index );
load_tile( pending.b, pending.cache_index );
}
}
@ -451,6 +507,18 @@ int FGTileMgr::update( void ) {
// We've moved to a new bucket, we need to scroll our
// structures, and load in the new tiles
#if 0
// make sure load queue is flushed before doing shift
while ( load_queue.size() ) {
FG_LOG( FG_TERRAIN, FG_INFO,
"Load queue not empty, flushing queue before tile shift." );
FGLoadRec pending = load_queue.front();
load_queue.pop_front();
load_tile( pending.b, pending.index );
}
#endif
// CURRENTLY THIS ASSUMES WE CAN ONLY MOVE TO ADJACENT TILES.
// AT ULTRA HIGH SPEEDS THIS ASSUMPTION MAY NOT BE VALID IF
// THE AIRCRAFT CAN SKIP A TILE IN A SINGLE ITERATION.
@ -460,66 +528,66 @@ int FGTileMgr::update( void ) {
if ( (p1.get_lon() > p_last.get_lon()) ||
( (p1.get_lon() == p_last.get_lon()) && (p1.get_x() > p_last.get_x()) ) ) {
FG_LOG( FG_TERRAIN, FG_INFO,
" Loading " << tile_diameter << "tiles" );
" Loading " << tile_diameter << " tiles" );
for ( j = 0; j < tile_diameter; j++ ) {
// scrolling East
disable_tile( tiles[(j*tile_diameter) + 0] );
for ( i = 0; i < tile_diameter - 1; i++ ) {
tiles[(j*tile_diameter) + i] =
tiles[(j*tile_diameter) + i + 1];
}
// load in new column
// fgBucketOffset(&p_last, &p2, dw + 1, j - dh);
p2 = fgBucketOffset( last_lon, last_lat, dw + 1, j - dh );
sched_tile( p2, &tiles[(j*tile_diameter) +
tile_diameter - 1]);
tiles[(j*tile_diameter) + tile_diameter - 1] = sched_tile( p2 );
}
} else if ( (p1.get_lon() < p_last.get_lon()) ||
( (p1.get_lon() == p_last.get_lon()) && (p1.get_x() < p_last.get_x()) ) ) {
( (p1.get_lon() == p_last.get_lon()) &&
(p1.get_x() < p_last.get_x()) ) ) {
FG_LOG( FG_TERRAIN, FG_INFO,
" Loading " << tile_diameter << "tiles" );
" Loading " << tile_diameter << " tiles" );
for ( j = 0; j < tile_diameter; j++ ) {
// scrolling West
disable_tile( tiles[(j*tile_diameter) + tile_diameter - 1] );
for ( i = tile_diameter - 1; i > 0; i-- ) {
tiles[(j*tile_diameter) + i] =
tiles[(j*tile_diameter) + i - 1];
}
// load in new column
// fgBucketOffset(&p_last, &p2, -dw - 1, j - dh);
p2 = fgBucketOffset( last_lon, last_lat, -dw - 1, j - dh );
sched_tile( p2, &tiles[(j*tile_diameter) + 0]);
tiles[(j*tile_diameter) + 0] = sched_tile( p2 );
}
}
if ( (p1.get_lat() > p_last.get_lat()) ||
( (p1.get_lat() == p_last.get_lat()) && (p1.get_y() > p_last.get_y()) ) ) {
FG_LOG( FG_TERRAIN, FG_INFO,
" Loading " << tile_diameter << "tiles" );
" Loading " << tile_diameter << " tiles" );
for ( i = 0; i < tile_diameter; i++ ) {
// scrolling North
disable_tile( tiles[0 + i] );
for ( j = 0; j < tile_diameter - 1; j++ ) {
tiles[(j * tile_diameter) + i] =
tiles[((j+1) * tile_diameter) + i];
}
// load in new column
// fgBucketOffset(&p_last, &p2, i - dw, dh + 1);
p2 = fgBucketOffset( last_lon, last_lat, i - dw, dh + 1);
sched_tile( p2, &tiles[((tile_diameter-1) *
tile_diameter) + i]);
tiles[((tile_diameter-1) * tile_diameter) + i] =
sched_tile( p2 );
}
} else if ( (p1.get_lat() < p_last.get_lat()) ||
( (p1.get_lat() == p_last.get_lat()) && (p1.get_y() < p_last.get_y()) ) ) {
FG_LOG( FG_TERRAIN, FG_INFO,
" Loading " << tile_diameter << "tiles" );
" Loading " << tile_diameter << " tiles" );
for ( i = 0; i < tile_diameter; i++ ) {
// scrolling South
disable_tile( tiles[((tile_diameter-1) * tile_diameter) + i] );
for ( j = tile_diameter - 1; j > 0; j-- ) {
tiles[(j * tile_diameter) + i] =
tiles[((j-1) * tile_diameter) + i];
}
// load in new column
// fgBucketOffset(&p_last, &p2, i - dw, -dh - 1);
p2 = fgBucketOffset( last_lon, last_lat, i - dw, -dh - 1);
sched_tile( p2, &tiles[0 + i]);
tiles[0 + i] = sched_tile( p2 );
}
}
}
@ -529,7 +597,7 @@ int FGTileMgr::update( void ) {
FGLoadRec pending = load_queue.front();
load_queue.pop_front();
load_tile( pending.b, pending.index );
load_tile( pending.b, pending.cache_index );
}
// find our current elevation (feed in the current bucket to save work)
@ -538,7 +606,11 @@ int FGTileMgr::update( void ) {
scenery.cur_elev =
current_elev( f->get_Longitude(), f->get_Latitude(), tmp_abs_view_pos );
// cout << "current elevation == " << scenery.cur_elev << endl;
// double junk = current_elev_ssg( current_view.abs_view_pos,
// current_view.view_pos );
// cout << "current elevation (ssg) == " <<
p_last = p1;
last_lon = f->get_Longitude() * RAD_TO_DEG;
last_lat = f->get_Latitude() * RAD_TO_DEG;
@ -765,7 +837,7 @@ void FGTileMgr::prep_ssg_nodes( void ) {
sgSetCoord( &sgcoord,
t->offset.x(), t->offset.y(), t->offset.z(),
0.0, 0.0, 0.0 );
t->branch_ptr->setTransform( &sgcoord );
t->transform_ptr->setTransform( &sgcoord );
}
}
}

View file

@ -55,7 +55,7 @@ class FGLoadRec {
public:
FGBucket b;
int index;
int cache_index;
};
@ -80,7 +80,7 @@ private:
list < FGLoadRec > load_queue;
// schedule a tile for loading
void sched_tile( const FGBucket& b, int *index );
int sched_tile( const FGBucket& b );
// load a tile
void load_tile( const FGBucket& b, int cache_index );
@ -105,8 +105,10 @@ public:
// render the scene, but we'd also like to be able to do this
// explicitely. lat & lon are in radians. abs_view_pos in
// meters. Returns result in meters.
double current_elev_new( const FGBucket& p );
double current_elev( double lon, double lat, const Point3D& abs_view_pos );
double current_elev_ssg( const Point3D& abs_view_pos,
const Point3D& view_pos );
double current_elev_new( const FGBucket& p );
// Prepare the ssg nodes ... for each tile, set it's proper
// transform and update it's range selector based on current