1
0
Fork 0

Threaded tile paging:

- 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.
This commit is contained in:
curt 2001-05-19 16:59:43 +00:00
parent 865fb56c5a
commit 34854ab2af
11 changed files with 508 additions and 92 deletions

View 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;

View 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;

View 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;
}

View 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

View 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);
}

View 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
/**

View 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() );

View 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,14 @@ FGTileEntry::load( const SGPath& base, bool is_base )
<< " elevation = " << elev
<< " heading = " << hdg );
// load the object itself
// object loading is deferred to main render thread,
// but lets figure out the paths right now.
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 +400,118 @@ 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 );
// 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;
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_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);
}
}
}

View 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();
};

View 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 "
}
}

View 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: