diff --git a/src/Scenery/tilecache.cxx b/src/Scenery/tilecache.cxx index c996087f2..1e0411d22 100644 --- a/src/Scenery/tilecache.cxx +++ b/src/Scenery/tilecache.cxx @@ -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); + } } diff --git a/src/Scenery/tileentry.cxx b/src/Scenery/tileentry.cxx index 1af8fb4c7..bd246f1e9 100644 --- a/src/Scenery/tileentry.cxx +++ b/src/Scenery/tileentry.cxx @@ -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; +} diff --git a/src/Scenery/tileentry.hxx b/src/Scenery/tileentry.hxx index 81f67b639..8a5ec4c0a 100644 --- a/src/Scenery/tileentry.hxx +++ b/src/Scenery/tileentry.hxx @@ -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(); }; diff --git a/src/Scenery/tilemgr.cxx b/src/Scenery/tilemgr.cxx index e296d0a28..6e315a41e 100644 --- a/src/Scenery/tilemgr.cxx +++ b/src/Scenery/tilemgr.cxx @@ -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 ); } } } diff --git a/src/Scenery/tilemgr.hxx b/src/Scenery/tilemgr.hxx index 0f7ee3815..9a659ca58 100644 --- a/src/Scenery/tilemgr.hxx +++ b/src/Scenery/tilemgr.hxx @@ -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