#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>
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
"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;
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;
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 );
}
}
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;
+}
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
tile_load_queue.push( tile );
}
+/**
+ *
+ */
+void
+FGTileLoader::remove( FGTileEntry* tile )
+{
+ tile_free_queue.push( tile );
+}
+
/**
*
*/
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
}
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);
}
/**
* 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
/**
* 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
/**
// 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 );
}
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() );
-// 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
#include <Objects/obj.hxx>
#include "tileentry.hxx"
+#include "tilemgr.hxx"
SG_USING_STD(for_each);
SG_USING_STD(mem_fun_ref);
tile_bucket( b ),
terra_transform( new ssgTransform ),
terra_range( new ssgRangeSelector ),
- loaded(false)
+ loaded(false),
+ pending_models(0)
{
nodes.clear();
}
+// 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() {
}
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 );
}
}
<< " 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;
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,
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);
+ }
+ }
+}
//
// 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
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.
*/
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 );
// 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();
* 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 );
/**
*/
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
*/
* 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();
};
}
#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 ),
}
-// 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] );
// 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;
// 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 "
}
}
// forward declaration
class FGTileEntry;
+class FGDeferredModel;
class FGTileMgr {
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: