]> git.mxchange.org Git - flightgear.git/commitdiff
Threaded tile paging:
authorcurt <curt>
Sat, 19 May 2001 16:59:43 +0000 (16:59 +0000)
committercurt <curt>
Sat, 19 May 2001 16:59:43 +0000 (16:59 +0000)
- model loading deferred to primary thread
- tile removal deferred to paging thread
- other tweaks and rearrangments.

Airport signs
- first stab at some support for adding taxiway and runway signs.  This
  is non-optimal, but I'm under the gun for a demo.

src/Main/keyboard.cxx
src/Main/main.cxx
src/Objects/obj.cxx
src/Objects/obj.hxx
src/Scenery/FGTileLoader.cxx
src/Scenery/FGTileLoader.hxx
src/Scenery/newcache.cxx
src/Scenery/tileentry.cxx
src/Scenery/tileentry.hxx
src/Scenery/tilemgr.cxx
src/Scenery/tilemgr.hxx

index df0ca50f662ecf21161f24693b307f59878b5fe6..c2dc81145e0de522441eb98da8dc959389ea77e2 100644 (file)
@@ -56,6 +56,7 @@
 #include <Cockpit/panel.hxx>
 #include <Cockpit/panel_io.hxx>
 #include <GUI/gui.h>
+#include <Scenery/scenery.hxx>
 #include <Scenery/tilemgr.hxx>
 #include <Objects/matlib.hxx>
 #include <Time/light.hxx>
@@ -484,6 +485,17 @@ void GLUTkey(unsigned char k, int x, int y) {
                tile_path.append( p.gen_index_str() );
 
                // printf position and attitude information
+               printf( "Lon = %.6f  Lat = %.6f  Ground = %.2f  Alt = %.2f\n",
+                       f->get_Longitude() * SGD_RADIANS_TO_DEGREES,
+                       f->get_Latitude() * SGD_RADIANS_TO_DEGREES,
+                       scenery.cur_elev,
+                       f->get_Altitude() * SG_FEET_TO_METER );
+               printf( "Heading = %.2f  Roll = %.2f  Pitch = %.2f\n",
+                       f->get_Psi() * SGD_RADIANS_TO_DEGREES,
+                       f->get_Phi() * SGD_RADIANS_TO_DEGREES,
+                       f->get_Theta() * SGD_RADIANS_TO_DEGREES );
+
+#if 0
                SG_LOG( SG_INPUT, SG_INFO,
                        "Lon = " << f->get_Longitude() * SGD_RADIANS_TO_DEGREES
                        << "  Lat = " << f->get_Latitude() * SGD_RADIANS_TO_DEGREES
@@ -493,6 +505,8 @@ void GLUTkey(unsigned char k, int x, int y) {
                        "Heading = " << f->get_Psi() * SGD_RADIANS_TO_DEGREES 
                        << "  Roll = " << f->get_Phi() * SGD_RADIANS_TO_DEGREES
                        << "  Pitch = " << f->get_Theta() * SGD_RADIANS_TO_DEGREES );
+#endif
+
                SG_LOG( SG_INPUT, SG_INFO, tile_path.c_str());
            }
            return;
index 74838177b0cfd75525b260bbd19ab4adb11fb620..81dd78176115b76afc36260059f846dfc815bc53 100644 (file)
@@ -1745,7 +1745,7 @@ void fgLoadDCS(void) {
         SG_LOG ( SG_TERRAIN, SG_ALERT, "Finished object processing." );
 
         ship_sel->clrTraversalMaskBits( SSGTRAV_HOT );
-        scene->addKid( ship_sel ); //add selector node to root node
+        scene->addKid( ship_sel ); //add selector node to root node 
     }
 
     return;
index 90bd2ceee507414edddad71d1bbcdf1977a59f1f..d26edcd7693cadc3e46cb9b9e5ca4b311b945430 100644 (file)
@@ -823,7 +823,7 @@ static ssgLeaf *gen_leaf( const string& path,
            newmat = material_lib.find( material );
            if ( newmat == NULL ) {
                SG_LOG( SG_TERRAIN, SG_ALERT, 
-                       "Ack! bad on the fly materia create = "
+                       "Ack! bad on the fly material create = "
                        << material << " in " << path );
            }
        }
@@ -984,3 +984,131 @@ ssgBranch *fgBinObjLoad( const string& path, FGTileEntry *t,
 
     return object;
 }
+
+
+ssgBranch *gen_taxi_sign( const string path, const string content ) {
+    // for demo purposes we assume each element (letter) is 1x1 meter.
+    // Sign is placed 0.25 meters above the ground
+
+    ssgBranch *object = new ssgBranch();
+    object->setName( (char *)content.c_str() );
+
+    double offset = content.length() / 2.0;
+
+    for ( unsigned int i = 0; i < content.length(); ++i ) {
+       string material;
+
+       char item = content[i];
+       if ( item == '<' ) {
+           material = "ArrowL.rgb";
+       } else if ( item == '>' ) {
+           material = "ArrowR.rgb";
+       } else if ( item >= 'A' && item <= 'Z' ) {
+           material = "Letter";
+           material += item;
+           material += ".rgb";
+       } else if ( item >= 'a' && item <= 'z' ) {
+           int tmp = item - 'a';
+           char c = 'A' + tmp;
+           material = "Black";
+           material += c;
+           material += ".rgb";
+       } else {
+           cout << "Unknown taxi sign code = '" << item << "' !!!!" << endl;
+           return NULL;
+       }
+
+       point_list nodes; nodes.clear();
+       point_list normals; normals.clear();
+       point_list texcoords; texcoords.clear();
+       int_list vertex_index; vertex_index.clear();
+       int_list tex_index; tex_index.clear();
+
+       nodes.push_back( Point3D( -offset + i, 0, 0.25 ) );
+       nodes.push_back( Point3D( -offset + i + 1, 0, 0.25 ) );
+       nodes.push_back( Point3D( -offset + i, 0, 1.25 ) );
+       nodes.push_back( Point3D( -offset + i + 1, 0, 1.25 ) );
+
+       normals.push_back( Point3D( 0, -1, 0 ) );
+       normals.push_back( Point3D( 0, -1, 0 ) );
+       normals.push_back( Point3D( 0, -1, 0 ) );
+       normals.push_back( Point3D( 0, -1, 0 ) );
+
+       texcoords.push_back( Point3D( 0, 0, 0 ) );
+       texcoords.push_back( Point3D( 1, 0, 0 ) );
+       texcoords.push_back( Point3D( 0, 1, 0 ) );
+       texcoords.push_back( Point3D( 1, 1, 0 ) );
+
+       vertex_index.push_back( 0 );
+       vertex_index.push_back( 1 );
+       vertex_index.push_back( 2 );
+       vertex_index.push_back( 3 );
+
+       tex_index.push_back( 0 );
+       tex_index.push_back( 1 );
+       tex_index.push_back( 2 );
+       tex_index.push_back( 3 );
+
+       ssgLeaf *leaf = gen_leaf( path, GL_TRIANGLE_STRIP, material,
+                                 nodes, normals, texcoords,
+                                 vertex_index, tex_index,
+                                 false, NULL );
+
+       object->addKid( leaf );
+    }
+
+    return object;
+}
+
+
+ssgBranch *gen_runway_sign( const string path, const string name ) {
+    // for demo purposes we assume each element (letter) is 1x1 meter.
+    // Sign is placed 0.25 meters above the ground
+
+    ssgBranch *object = new ssgBranch();
+    object->setName( (char *)name.c_str() );
+
+    double offset = name.length() / 2.0;
+
+    string material = name + ".rgb";
+
+    point_list nodes; nodes.clear();
+    point_list normals; normals.clear();
+    point_list texcoords; texcoords.clear();
+    int_list vertex_index; vertex_index.clear();
+    int_list tex_index; tex_index.clear();
+
+    nodes.push_back( Point3D( -offset, 0, 0.25 ) );
+    nodes.push_back( Point3D( offset + 1, 0, 0.25 ) );
+    nodes.push_back( Point3D( -offset, 0, 1.25 ) );
+    nodes.push_back( Point3D( offset + 1, 0, 1.25 ) );
+
+    normals.push_back( Point3D( 0, -1, 0 ) );
+    normals.push_back( Point3D( 0, -1, 0 ) );
+    normals.push_back( Point3D( 0, -1, 0 ) );
+    normals.push_back( Point3D( 0, -1, 0 ) );
+
+    texcoords.push_back( Point3D( 0, 0, 0 ) );
+    texcoords.push_back( Point3D( 1, 0, 0 ) );
+    texcoords.push_back( Point3D( 0, 1, 0 ) );
+    texcoords.push_back( Point3D( 1, 1, 0 ) );
+
+    vertex_index.push_back( 0 );
+    vertex_index.push_back( 1 );
+    vertex_index.push_back( 2 );
+    vertex_index.push_back( 3 );
+
+    tex_index.push_back( 0 );
+    tex_index.push_back( 1 );
+    tex_index.push_back( 2 );
+    tex_index.push_back( 3 );
+
+    ssgLeaf *leaf = gen_leaf( path, GL_TRIANGLE_STRIP, material,
+                             nodes, normals, texcoords,
+                             vertex_index, tex_index,
+                             false, NULL );
+
+    object->addKid( leaf );
+
+    return object;
+}
index fe87427e71f21c5d07daa7f848d5fb92b1bd90af..5ad0804e00cdd6d5bd3df967213ad5a9f96deff9 100644 (file)
@@ -67,4 +67,12 @@ ssgBranch *fgAsciiObjLoad(const string& path, FGTileEntry *tile,
 ssgBranch *fgGenTile( const string& path, FGTileEntry *t);
 
 
+// Generate a taxi sign
+ssgBranch *gen_taxi_sign( const string path, const string content );
+
+
+// Generate a runway sign
+ssgBranch *gen_runway_sign( const string path, const string name );
+
+
 #endif // _OBJ_HXX
index a709b57f0fdb1b5b7ccaaa0393c93a2b04bef3ef..8f04c78c8a7fb106011a0637d87ee78025d79fc1 100644 (file)
@@ -89,6 +89,15 @@ FGTileLoader::add( FGTileEntry* tile )
     tile_load_queue.push( tile );
 }
 
+/**
+ * 
+ */
+void
+FGTileLoader::remove( FGTileEntry* tile )
+{
+    tile_free_queue.push( tile );
+}
+
 /**
  * 
  */
@@ -110,6 +119,16 @@ FGTileLoader::update()
         tile->load( tile_path, true );
         FGTileMgr::loaded( tile );
     }
+
+    if ( !tile_free_queue.empty() ) {
+        cout << "freeing next tile ..." << endl;
+        // free the next tile in the queue
+        FGTileEntry* tile = tile_free_queue.front();
+        tile_free_queue.pop();
+       tile->free_tile();
+       delete tile;
+    }
+
 #endif // ENABLE_THREADS
 }
 
@@ -135,7 +154,16 @@ FGTileLoader::LoaderThread::run()
        tile->load( loader->tile_path, true );
        set_cancel( SGThread::CANCEL_DEFERRED );
 
-       FGTileMgr::loaded( tile );
+       FGTileMgr::ready_to_attach( tile );
+
+       // Handle and pending removals
+       while ( !loader->tile_free_queue.empty() ) {
+           cout << "freeing next tile ..." << endl;
+           // free the next tile in the queue
+           FGTileEntry* tile = loader->tile_free_queue.pop();
+           tile->free_tile();
+           delete tile;
+       }
     }
     pthread_cleanup_pop(1);
 }
index 16878e134c07e24b113c7c84b3f354cca3bddc6d..258232a52bc516dfcd71dbd4e81c20090c7bcd6c 100644 (file)
@@ -57,10 +57,15 @@ public:
     /**
      * Add a tile to the end of the load queue.
      * @param tile The tile to be loaded from disk.
-     * @param vis Current visibilty (in feet?) (see FGTileMgr::vis).
      */
     void add( FGTileEntry* tile );
 
+    /**
+     * Remove a tile from memory.
+     * @param tile The tile to be removed from memory.
+     */
+    void remove( FGTileEntry* tile );
+
     /**
      * The tile loader thread will only load one tile per call to the
      * update() method.  This is a way to spread out the work of the
@@ -83,9 +88,11 @@ private:
     /**
      * FIFO queue of tiles to load from data files.
      */
-    SGBlockingQueue< FGTileEntry* > tile_load_queue;
+    SGBlockingQueue< FGTileEntry * > tile_load_queue;
+    SGBlockingQueue< FGTileEntry * > tile_free_queue;
 #else
-    queue< FGTileEntry* > tile_load_queue;
+    queue< FGTileEntry * > tile_load_queue;
+    queue< FGTileEntry * > tile_free_queue;
 #endif
 
     /**
index c347bdd556813461059fcdde20440ee1d067c336..c7e59195e54a1dc79c50b538b3a21da1da89f816 100644 (file)
@@ -62,9 +62,15 @@ FGNewCache::~FGNewCache( void ) {
 // Free a tile cache entry
 void FGNewCache::entry_free( long cache_index ) {
     SG_LOG( SG_TERRAIN, SG_DEBUG, "FREEING CACHE ENTRY = " << cache_index );
-    FGTileEntry *e = tile_cache[cache_index];
-    e->free_tile();
-    delete e;
+    FGTileEntry *tile = tile_cache[cache_index];
+    tile->disconnect_ssg_nodes();
+    tile->sched_removal();
+
+#if 0
+    tile->free_tile();
+    delete tile;
+#endif
+
     tile_cache.erase( cache_index );
 }
 
@@ -166,7 +172,7 @@ void FGNewCache::make_space() {
            long index = current->first;
            FGTileEntry *e = current->second;
 
-           if ( e->is_loaded() ) {
+           if ( e->is_loaded() && e->get_pending_models() == 0 ) {
                // calculate approximate distance from view point
                sgdCopyVec3( abs_view_pos,
                             globals->get_current_view()->get_abs_view_pos() );
index 020c324369abd299a826600c6fe2e1fae7aec168..4bc931ae1f9740a1658d7f592b86a587fcef2fe0 100644 (file)
@@ -1,8 +1,8 @@
-// tile.cxx -- routines to handle a scenery tile
+// tileentry.cxx -- routines to handle a scenery tile
 //
 // Written by Curtis Olson, started May 1998.
 //
-// Copyright (C) 1998, 1999  Curtis L. Olson  - curt@flightgear.org
+// Copyright (C) 1998 - 2001  Curtis L. Olson  - curt@flightgear.org
 //
 // This program is free software; you can redistribute it and/or
 // modify it under the terms of the GNU General Public License as
@@ -51,6 +51,7 @@
 #include <Objects/obj.hxx>
 
 #include "tileentry.hxx"
+#include "tilemgr.hxx"
 
 SG_USING_STD(for_each);
 SG_USING_STD(mem_fun_ref);
@@ -64,7 +65,8 @@ FGTileEntry::FGTileEntry ( const SGBucket& b )
       tile_bucket( b ),
       terra_transform( new ssgTransform ),
       terra_range( new ssgRangeSelector ),
-      loaded(false)
+      loaded(false),
+      pending_models(0)
 {
     nodes.clear();
 
@@ -103,6 +105,12 @@ static void my_remove_branch( ssgBranch * branch ) {
 }
 
 
+// Schedule tile to be freed/removed
+void FGTileEntry::sched_removal() {
+    global_tile_mgr.ready_to_delete( this );
+}
+
+
 // 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() {
@@ -134,45 +142,14 @@ void FGTileEntry::free_tile() {
     }
     index_ptrs.clear();
 
-    // delete the terrain branch
-    int pcount = terra_transform->getNumParents();
-    if ( pcount > 0 ) {
-       // find the first parent (should only be one)
-       ssgBranch *parent = terra_transform->getParent( 0 ) ;
-       if( parent ) {
-           // my_remove_branch( select_ptr );
-           parent->removeKid( terra_transform );
-           terra_transform = NULL;
-       } else {
-           SG_LOG( SG_TERRAIN, SG_ALERT,
-                   "parent pointer is NULL!  Dying" );
-           exit(-1);
-       }
-    } else {
-       SG_LOG( SG_TERRAIN, SG_ALERT,
-               "Parent count is zero for an ssg tile!  Dying" );
-       exit(-1);
-    }
+    // delete the terrain branch (this should already have been
+    // disconnected from the scene graph)
+    ssgDeRefDelete( terra_transform );
 
     if ( lights_transform ) {
-       // delete the terrain lighting branch
-       pcount = lights_transform->getNumParents();
-       if ( pcount > 0 ) {
-           // find the first parent (should only be one)
-           ssgBranch *parent = lights_transform->getParent( 0 ) ;
-           if( parent ) {
-               parent->removeKid( lights_transform );
-               lights_transform = NULL;
-           } else {
-               SG_LOG( SG_TERRAIN, SG_ALERT,
-                       "parent pointer is NULL!  Dying" );
-               exit(-1);
-           }
-       } else {
-           SG_LOG( SG_TERRAIN, SG_ALERT,
-                   "Parent count is zero for an ssg light tile!  Dying" );
-           exit(-1);
-       }
+       // delete the terrain lighting branch (this should already have been
+    // disconnected from the scene graph)
+       ssgDeRefDelete( lights_transform );
     }
 }
 
@@ -389,15 +366,68 @@ FGTileEntry::load( const SGPath& base, bool is_base )
                        << " elevation = " << elev
                        << " heading = " << hdg );
 
+               // object loading is deferred to main render thread,
+               // but lets figure out the paths right now.
+               SGPath custom_path = tile_path;
+               custom_path.append( name );
+
+               // setup transforms
+               Point3D geod( lon * SGD_DEGREES_TO_RADIANS,
+                             lat * SGD_DEGREES_TO_RADIANS,
+                             elev );
+               Point3D world_pos = sgGeodToCart( geod );
+               Point3D offset = world_pos - center;
+               sgMat4 POS;
+               sgMakeTransMat4( POS, offset.x(), offset.y(), offset.z() );
+
+               sgVec3 obj_rt, obj_up;
+               sgSetVec3( obj_rt, 0.0, 1.0, 0.0); // Y axis
+               sgSetVec3( obj_up, 0.0, 0.0, 1.0); // Z axis
+
+               sgMat4 ROT_lon, ROT_lat, ROT_hdg;
+               sgMakeRotMat4( ROT_lon, lon, obj_up );
+               sgMakeRotMat4( ROT_lat, 90 - lat, obj_rt );
+               sgMakeRotMat4( ROT_hdg, hdg, obj_up );
+       
+               sgMat4 TUX;
+               sgCopyMat4( TUX, ROT_hdg );
+               sgPostMultMat4( TUX, ROT_lat );
+               sgPostMultMat4( TUX, ROT_lon );
+               sgPostMultMat4( TUX, POS );
+
+               sgCoord obj_pos;
+               sgSetCoord( &obj_pos, TUX );
+               ssgTransform *obj_trans = new ssgTransform;
+               obj_trans->setTransform( &obj_pos );
+
+               // wire as much of the scene graph together as we can
+               new_tile->addKid( obj_trans );
+
+               // bump up the pending models count
+               pending_models++;
+
+               // push an entry onto the model load queue
+               FGDeferredModel *dm
+                   = new FGDeferredModel( custom_path.str(), tile_path.str(),
+                                          this, obj_trans );
+               FGTileMgr::model_ready( dm );
+           } else if ( token == "OBJECT_TAXI_SIGN" ) {
+               // load object info
+               double lon, lat, elev, hdg;
+               in >> name >> lon >> lat >> elev >> hdg >> ::skipws;
+               SG_LOG( SG_TERRAIN, SG_INFO, "token = " << token
+                       << " name = " << name 
+                       << " pos = " << lon << ", " << lat
+                       << " elevation = " << elev
+                       << " heading = " << hdg );
+
                // load the object itself
                SGPath custom_path = tile_path;
-                ssgTexturePath( (char *)custom_path.c_str() );
                custom_path.append( name );
-               ssgEntity *obj_model = ssgLoad( (char *)custom_path.c_str() );
 
                // setup transforms
                Point3D geod( lon * SGD_DEGREES_TO_RADIANS,
-                             lat *  SGD_DEGREES_TO_RADIANS,
+                             lat * SGD_DEGREES_TO_RADIANS,
                              elev );
                Point3D world_pos = sgGeodToCart( geod );
                Point3D offset = world_pos - center;
@@ -424,8 +454,64 @@ FGTileEntry::load( const SGPath& base, bool is_base )
                ssgTransform *obj_trans = new ssgTransform;
                obj_trans->setTransform( &obj_pos );
 
-               // wire the scene graph together
-               obj_trans->addKid( obj_model );
+               ssgBranch *custom_obj
+                   = gen_taxi_sign( custom_path.str(), name );
+
+               // wire the pieces together
+               if ( (new_tile != NULL) && (custom_obj != NULL) ) {
+                   obj_trans -> addKid( custom_obj );
+               }
+               new_tile->addKid( obj_trans );
+           } else if ( token == "OBJECT_RUNWAY_SIGN" ) {
+               // load object info
+               double lon, lat, elev, hdg;
+               in >> name >> lon >> lat >> elev >> hdg >> ::skipws;
+               SG_LOG( SG_TERRAIN, SG_INFO, "token = " << token
+                       << " name = " << name 
+                       << " pos = " << lon << ", " << lat
+                       << " elevation = " << elev
+                       << " heading = " << hdg );
+
+               // load the object itself
+               SGPath custom_path = tile_path;
+               custom_path.append( name );
+
+               // setup transforms
+               Point3D geod( lon * SGD_DEGREES_TO_RADIANS,
+                             lat * SGD_DEGREES_TO_RADIANS,
+                             elev );
+               Point3D world_pos = sgGeodToCart( geod );
+               Point3D offset = world_pos - center;
+               sgMat4 POS;
+               sgMakeTransMat4( POS, offset.x(), offset.y(), offset.z() );
+
+               sgVec3 obj_rt, obj_up;
+               sgSetVec3( obj_rt, 0.0, 1.0, 0.0); // Y axis
+               sgSetVec3( obj_up, 0.0, 0.0, 1.0); // Z axis
+
+               sgMat4 ROT_lon, ROT_lat, ROT_hdg;
+               sgMakeRotMat4( ROT_lon, lon, obj_up );
+               sgMakeRotMat4( ROT_lat, 90 - lat, obj_rt );
+               sgMakeRotMat4( ROT_hdg, hdg, obj_up );
+       
+               sgMat4 TUX;
+               sgCopyMat4( TUX, ROT_hdg );
+               sgPostMultMat4( TUX, ROT_lat );
+               sgPostMultMat4( TUX, ROT_lon );
+               sgPostMultMat4( TUX, POS );
+
+               sgCoord obj_pos;
+               sgSetCoord( &obj_pos, TUX );
+               ssgTransform *obj_trans = new ssgTransform;
+               obj_trans->setTransform( &obj_pos );
+
+               ssgBranch *custom_obj
+                   = gen_runway_sign( custom_path.str(), name );
+
+               // wire the pieces together
+               if ( (new_tile != NULL) && (custom_obj != NULL) ) {
+                   obj_trans -> addKid( custom_obj );
+               }
                new_tile->addKid( obj_trans );
            } else {
                SG_LOG( SG_TERRAIN, SG_ALERT,
@@ -478,9 +564,66 @@ FGTileEntry::load( const SGPath& base, bool is_base )
 void
 FGTileEntry::add_ssg_nodes( ssgBranch* terrain, ssgBranch* ground )
 {
+    // bump up the ref count so we can remove this later without
+    // having ssg try to free the memory.
+    terra_transform->ref();
     terrain->addKid( terra_transform );
-    if (lights_transform != 0)
+
+    if ( lights_transform != 0 ) {
+       // bump up the ref count so we can remove this later without
+       // having ssg try to free the memory.
+       lights_transform->ref();
        ground->addKid( lights_transform );
+    }
 
     loaded = true;
 }
+
+
+void
+FGTileEntry::disconnect_ssg_nodes()
+{
+    cout << "disconnecting ssg nodes" << endl;
+
+    // find the terrain branch parent
+    int pcount = terra_transform->getNumParents();
+    if ( pcount > 0 ) {
+       // find the first parent (should only be one)
+       ssgBranch *parent = terra_transform->getParent( 0 ) ;
+       if( parent ) {
+           // disconnect the tile (we previously ref()'d it so it
+           // won't get freed now)
+           parent->removeKid( terra_transform );
+       } else {
+           SG_LOG( SG_TERRAIN, SG_ALERT,
+                   "parent pointer is NULL!  Dying" );
+           exit(-1);
+       }
+    } else {
+       SG_LOG( SG_TERRAIN, SG_ALERT,
+               "Parent count is zero for an ssg tile!  Dying" );
+       exit(-1);
+    }
+
+    // find the terrain lighting branch
+    if ( lights_transform ) {
+       pcount = lights_transform->getNumParents();
+       if ( pcount > 0 ) {
+           // find the first parent (should only be one)
+           ssgBranch *parent = lights_transform->getParent( 0 ) ;
+           if( parent ) {
+               // disconnect the light branch (we previously ref()'d
+               // it so it won't get freed now)
+               parent->removeKid( lights_transform );
+           } else {
+               SG_LOG( SG_TERRAIN, SG_ALERT,
+                       "parent pointer is NULL!  Dying" );
+               exit(-1);
+           }
+       } else {
+           SG_LOG( SG_TERRAIN, SG_ALERT,
+                   "Parent count is zero for an ssg light tile!  Dying" );
+           exit(-1);
+       }
+    }
+}
index 53a7f390094ea593ae8c21a0c04d086b610ac263..5199f8f924847c837ba685e9569bb7104a42d02d 100644 (file)
@@ -2,7 +2,7 @@
 //
 // Written by Curtis Olson, started May 1998.
 //
-// Copyright (C) 1998, 1999  Curtis L. Olson  - curt@flightgear.org
+// Copyright (C) 1998 - 2001  Curtis L. Olson  - curt@flightgear.org
 //
 // This program is free software; you can redistribute it and/or
 // modify it under the terms of the GNU General Public License as
@@ -62,6 +62,39 @@ typedef vector < Point3D > point_list;
 typedef point_list::iterator point_list_iterator;
 typedef point_list::const_iterator const_point_list_iterator;
 
+class FGTileEntry;
+
+
+/**
+ * A class to hold deferred model loading info
+ */
+class FGDeferredModel {
+
+private:
+
+    string model_path;
+    string texture_path;
+    FGTileEntry *tile;
+    ssgTransform *obj_trans;
+
+public:
+
+    inline FGDeferredModel() { }
+    inline FGDeferredModel( const string mp, const string tp,
+                    FGTileEntry *t, ssgTransform *ot )
+    {
+       model_path = mp;
+       texture_path = tp;
+       tile = t;
+       obj_trans = ot;
+    }
+    inline ~FGDeferredModel() { }
+    inline string get_model_path() const { return model_path; }
+    inline string get_texture_path() const { return texture_path; }
+    inline FGTileEntry *get_tile() const { return tile; }
+    inline ssgTransform *get_obj_trans() const { return obj_trans; }
+};
+
 
 /**
  * A class to encapsulate everything we need to know about a scenery tile.
@@ -124,6 +157,13 @@ private:
      */
     volatile bool loaded;
 
+    /**
+     * Count of pending models to load for this tile.  This tile
+     * cannot be removed until this number reaches zero (i.e. no
+     * pending models to load for this tile.)
+     */
+    volatile int pending_models;
+
     ssgBranch* obj_load( const std::string& path,
                         ssgVertexArray* lights, bool is_base );
 
@@ -137,6 +177,9 @@ public:
     // Destructor
     ~FGTileEntry();
 
+    // Schedule tile to be freed/removed
+    void sched_removal();
+
     // Clean up the memory used by this tile and delete the arrays
     // used by ssg as well as the whole ssg branch
     void free_tile();
@@ -158,8 +201,7 @@ public:
      * Load tile data from a file.
      * @param base name of directory containing tile data file.
      * @param is_base is this a base terrain object for which we should generate
-     *        random ground light points
-     */
+     *        random ground light points */
     void load( const SGPath& base, bool is_base );
 
     /**
@@ -168,6 +210,16 @@ public:
      */
     inline bool is_loaded() const { return loaded; }
 
+    /**
+     * decrement the pending models count
+     */
+    inline void dec_pending_models() { pending_models--; }
+
+    /**
+     * return the number of remaining pending models for this tile
+     */
+    inline int get_pending_models() const { return pending_models; }
+
     /**
      * Return the "bucket" for this tile
      */
@@ -177,6 +229,12 @@ public:
      * Add terrain mesh and ground lighting to scene graph.
      */
     void add_ssg_nodes( ssgBranch* terrain, ssgBranch* ground );
+
+    /**
+     * disconnect terrain mesh and ground lighting nodes from scene
+     * graph for this tile.
+     */
+    void disconnect_ssg_nodes();
 };
 
 
index d949c6ab225b90edbece8c302414507e80b4ac03..db78a6dbfd7c86047ce5388e2693055067cdd1e9 100644 (file)
@@ -70,11 +70,14 @@ static inline Point3D operator + (const Point3D& a, const sgdVec3 b)
 }
 
 #ifdef ENABLE_THREADS
-SGLockedQueue<FGTileEntry*> FGTileMgr::loaded_queue;
+SGLockedQueue<FGTileEntry *> FGTileMgr::attach_queue;
+SGLockedQueue<FGDeferredModel *> FGTileMgr::model_queue;
 #else
-queue<FGTileEntry*> FGTileMgr::loaded_queue;
+queue<FGTileEntry *> FGTileMgr::attach_queue;
+queue<FGTileDeferredModel *> FGTileMgr::model_queue;
 #endif // ENABLE_THREADS
 
+
 // Constructor
 FGTileMgr::FGTileMgr():
     state( Start ),
@@ -135,25 +138,6 @@ void FGTileMgr::sched_tile( const SGBucket& b ) {
 }
 
 
-// depricated for threading
-#if 0
-// load a tile
-void FGTileMgr::load_tile( const SGBucket& b ) {
-    // see if tile already exists in the cache
-    FGTileEntry *t = tile_cache.get_tile( b );
-
-    if ( t == NULL ) {
-       SG_LOG( SG_TERRAIN, SG_DEBUG, "Loading tile " << b );
-       tile_cache.fill_in( b );
-       t = tile_cache.get_tile( b );
-       t->prep_ssg_node( scenery.center, vis);
-    } else {
-       SG_LOG( SG_TERRAIN, SG_DEBUG, "Tile already in cache " << b );
-    }
-}
-#endif
-
-
 static void CurrentNormalInLocalPlane(sgVec3 dst, sgVec3 src) {
     sgVec3 tmp;
     sgSetVec3(tmp, src[0], src[1], src[2] );
@@ -364,6 +348,28 @@ int FGTileMgr::update( double lon, double lat ) {
     // load in the case of the threaded tile pager)
     loader.update();
 
+    // load the next model in the load queue.  Currently this must
+    // happen in the render thread because model loading can trigger
+    // texture loading which involves use of the opengl api.
+    if ( !model_queue.empty() ) {
+        cout << "loading next model ..." << endl;
+        // load the next tile in the queue
+#ifdef ENABLE_THREADS
+       FGDeferredModel* dm = model_queue.pop();
+#else
+        FGDeferredModel* dm = model_queue.front();
+        model_queue.pop();
+#endif
+       
+       ssgTexturePath( (char *)(dm->get_texture_path().c_str()) );
+       ssgEntity *obj_model
+           = ssgLoad( (char *)(dm->get_model_path().c_str()) );
+       dm->get_obj_trans()->addKid( obj_model );
+       dm->get_tile()->dec_pending_models();
+
+       delete dm;
+    }
+
     if ( scenery.center == Point3D(0.0) ) {
        // initializing
        cout << "initializing scenery current elevation  ... " << endl;
@@ -412,16 +418,15 @@ int FGTileMgr::update( double lon, double lat ) {
         // Notify the tile loader that it can load another tile
         // loader.update();
 
-       if ( !loaded_queue.empty() ) {
+       if ( !attach_queue.empty() ) {
 #ifdef ENABLE_THREADS
-           FGTileEntry* e = loaded_queue.pop();
+           FGTileEntry* e = attach_queue.pop();
 #else
-           FGTileEntry* e = loaded_queue.front();
-            loaded_queue.pop();
+           FGTileEntry* e = attach_queue.front();
+            attach_queue.pop();
 #endif
            e->add_ssg_nodes( terrain, ground );
-           //std::cout << "Adding ssg nodes for "
-           //<< e->get_tile_bucket() << "\n";
+           // cout << "Adding ssg nodes for "
        }
     }
 
index 9d3f746853469685d50d1594ba30bee3e2b0380c..0dfc968ed29eddc83ec3c79f687707917cc4c449 100644 (file)
@@ -53,6 +53,7 @@
 
 // forward declaration
 class FGTileEntry;
+class FGDeferredModel;
 
 
 class FGTileMgr {
@@ -119,20 +120,38 @@ private:
     int counter_hack;
 
     /**
-     * Tiles to add to scene graph.
+     * Work queues.
+     *
+     * attach_queue is the tiles that have been loaded [by the pager]
+     * that can be attached to the scene graph by the render thread.
+     *
+     * model_queue is the set of models that need to be loaded by the
+     * primary render thread.
      */
 #ifdef ENABLE_THREADS
-    static SGLockedQueue<FGTileEntry*> loaded_queue;
+    static SGLockedQueue<FGTileEntry *> attach_queue;
+    static SGLockedQueue<FGDeferredModel *> model_queue;
 #else
-    static queue<FGTileEntry*> loaded_queue;
+    static queue<FGTileEntry *> attach_queue;
+    static queue<FGDeferredModel *> model_queue;
 #endif // ENABLE_THREADS
 
 public:
 
     /**
-     * Add a loaded tile to the scene graph queue.
+     * Add a loaded tile to the 'attach to the scene graph' queue.
      */
-    static void loaded( FGTileEntry* t ) { loaded_queue.push(t); }
+    static void ready_to_attach( FGTileEntry *t ) { attach_queue.push( t ); }
+
+    /**
+     * Tile is detatched from scene graph and is ready to delete
+     */
+    inline void ready_to_delete( FGTileEntry *t ) { loader.remove( t ); }
+
+    /**
+     * Add a pending model to the 'deferred model load' queue
+     */
+    static void model_ready( FGDeferredModel *dm ) { model_queue.push( dm ); }
 
 public: