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:
parent
865fb56c5a
commit
34854ab2af
11 changed files with 508 additions and 92 deletions
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
/**
|
||||
|
|
|
@ -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() );
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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 "
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
|
Loading…
Reference in a new issue