slightly more conducive to future threading.
// cout << "----> updating fog params" << endl;
// for GL_FOG_EXP
- fog_exp_density = -log(0.01 / actual_visibility);
+ fog_exp_density = -log(0.01) / actual_visibility;
// for GL_FOG_EXP2
fog_exp2_density = sqrt( -log(0.01) ) / actual_visibility;
ssgGetLight( 0 ) -> setPosition( l->sun_vec );
// GL_LIGHT_MODEL_AMBIENT has a default non-zero value so if
- // we only set GL_AMBIENT we will never get a completely dark
- // scene. Thus instead of playing with GL_AMBIENT, we just
- // set that to black and instead modify GL_LIGHT_MODEL_AMBIENT.
+ // we only update GL_AMBIENT for our lights we will never get
+ // a completely dark scene. So, we set GL_LIGHT_MODEL_AMBIENT
+ // explicitely to black.
GLfloat black[4] = { 0.0, 0.0, 0.0, 1.0 };
GLfloat white[4] = { 1.0, 1.0, 1.0, 1.0 };
glLightModelfv( GL_LIGHT_MODEL_AMBIENT, black );
// Load an Ascii obj file
-static ssgBranch *fgAsciiObjLoad( const string& path, FGTileEntry *t,
+ssgBranch *fgAsciiObjLoad( const string& path, FGTileEntry *t,
ssgVertexArray *lights, const bool is_base)
{
FGNewMat *newmat = NULL;
// Load an Binary obj file
-static ssgBranch *fgBinObjLoad( const string& path, FGTileEntry *t,
+ssgBranch *fgBinObjLoad( const string& path, FGTileEntry *t,
ssgVertexArray *lights, const bool is_base)
{
int i;
return object;
}
-
-
-// Load an obj file
-ssgBranch *fgObjLoad( const string& path, FGTileEntry *t,
- ssgVertexArray *lights, const bool is_base)
-{
- ssgBranch *result = NULL;
-
- // try loading binary format
- result = fgBinObjLoad( path, t, lights, is_base );
- if ( result == NULL ) {
- // next try the older ascii format
- result = fgAsciiObjLoad( path, t, lights, is_base );
- if ( result == NULL ) {
- // default to an ocean tile
- result = fgGenTile( path, t );
- }
- }
-
- return result;
-}
#define FG_MAX_NODES 4000
-// Load a .obj file
-ssgBranch *fgObjLoad(const string& path, FGTileEntry *tile,
- ssgVertexArray *lights, const bool is_base);
+// Load a binary object file
+ssgBranch *fgBinObjLoad(const string& path, FGTileEntry *tile,
+ ssgVertexArray *lights, const bool is_base);
+// Load an ascii object file
+ssgBranch *fgAsciiObjLoad(const string& path, FGTileEntry *tile,
+ ssgVertexArray *lights, const bool is_base);
-#endif // _OBJ_HXX
+// Generate an ocean tile
+ssgBranch *fgGenTile( const string& path, FGTileEntry *t);
+#endif // _OBJ_HXX
#include <simgear/bucket/newbucket.hxx>
#include <simgear/debug/logstream.hxx>
-#include <simgear/math/sg_geodesy.hxx>
-#include <simgear/math/sg_random.h>
-#include <simgear/misc/sgstream.hxx>
#include <simgear/misc/sg_path.hxx>
#include <Main/globals.hxx>
-#include <Objects/matlib.hxx>
-#include <Objects/newmat.hxx>
-#include <Objects/obj.hxx>
#include <Scenery/scenery.hxx> // for scenery.center
#include "newcache.hxx"
SG_USING_NAMESPACE(std);
-// a cheesy hack (to be fixed later)
-extern ssgBranch *terrain;
-extern ssgBranch *ground;
-
// the tile cache
FGNewCache global_tile_cache;
// Initialize the tile cache subsystem
void FGNewCache::init( void ) {
+ // This is a hack that should really get cleaned up at some point
+ extern ssgBranch *terrain;
+
SG_LOG( SG_TERRAIN, SG_INFO, "Initializing the tile cache." );
// expand cache if needed. For best results ... i.e. to avoid
}
-#if 0
-static void print_refs( ssgSelector *sel, ssgTransform *trans,
- ssgRangeSelector *range)
-{
- cout << "selector -> " << sel->getRef()
- << " transform -> " << trans->getRef()
- << " range -> " << range->getRef() << endl;
-}
-#endif
-
-
-static ssgLeaf *gen_lights( ssgVertexArray *lights, int inc, float bright ) {
- // generate a repeatable random seed
- float *p1 = lights->get( 0 );
- unsigned int *seed = (unsigned int *)p1;
- sg_srandom( *seed );
-
- int size = lights->getNum() / inc;
-
- // Allocate ssg structure
- ssgVertexArray *vl = new ssgVertexArray( size + 1 );
- ssgNormalArray *nl = NULL;
- ssgTexCoordArray *tl = NULL;
- ssgColourArray *cl = new ssgColourArray( size + 1 );
-
- sgVec4 color;
- for ( int i = 0; i < lights->getNum(); ++i ) {
- // this loop is slightly less efficient than it otherwise
- // could be, but we want a red light to always be red, and a
- // yellow light to always be yellow, etc. so we are trying to
- // preserve the random sequence.
- float zombie = sg_random();
- if ( i % inc == 0 ) {
- vl->add( lights->get(i) );
-
- // factor = sg_random() ^ 2, range = 0 .. 1 concentrated towards 0
- float factor = sg_random();
- factor *= factor;
-
- if ( zombie > 0.5 ) {
- // 50% chance of yellowish
- sgSetVec4( color, 0.9, 0.9, 0.3, bright - factor * 0.2 );
- } else if ( zombie > 0.15 ) {
- // 35% chance of whitish
- sgSetVec4( color, 0.9, 0.9, 0.8, bright - factor * 0.2 );
- } else if ( zombie > 0.05 ) {
- // 10% chance of orangish
- sgSetVec4( color, 0.9, 0.6, 0.2, bright - factor * 0.2 );
- } else {
- // 5% chance of redish
- sgSetVec4( color, 0.9, 0.2, 0.2, bright - factor * 0.2 );
- }
- cl->add( color );
- }
- }
-
- // create ssg leaf
- ssgLeaf *leaf =
- new ssgVtxTable ( GL_POINTS, vl, nl, tl, cl );
-
- // assign state
- FGNewMat *newmat = material_lib.find( "LIGHTS" );
- leaf->setState( newmat->get_state() );
-
- return leaf;
-}
-
-
// Fill in a tile cache entry with real data for the specified bucket
void FGNewCache::fill_in( const SGBucket& b ) {
- SG_LOG( SG_TERRAIN, SG_INFO, "FILL IN CACHE ENTRY = " << b.gen_index() );
+ SG_LOG( SG_TERRAIN, SG_DEBUG, "FILL IN CACHE ENTRY = " << b.gen_index() );
// clear out a distant entry in the cache if needed.
make_space();
// create the entry
- FGTileEntry *e = new FGTileEntry;
+ FGTileEntry *e = new FGTileEntry( b );
// register it in the cache
long tile_index = b.gen_index();
tile_cache[tile_index] = e;
- // update the contents
- e->center = Point3D( 0.0 );
- if ( e->vec3_ptrs.size() || e->vec2_ptrs.size() || e->index_ptrs.size() ) {
- SG_LOG( SG_TERRAIN, SG_ALERT,
- "Attempting to overwrite existing or"
- << " not properly freed leaf data." );
- exit(-1);
- }
-
- e->terra_transform = new ssgTransform;
- e->terra_range = new ssgRangeSelector;
- e->tile_bucket = b;
-
SGPath tile_path;
if ( globals->get_fg_scenery() != (string)"" ) {
tile_path.set( globals->get_fg_scenery() );
tile_path.set( globals->get_fg_root() );
tile_path.append( "Scenery" );
}
- tile_path.append( b.gen_base_path() );
- // fgObjLoad will generate ground lighting for us ...
- ssgVertexArray *light_pts = new ssgVertexArray( 100 );
-
// Load the appropriate data file
- SGPath tile_base = tile_path;
- tile_base.append( b.gen_index_str() );
- ssgBranch *new_tile = fgObjLoad( tile_base.str(), e, light_pts, true );
-
- if ( new_tile != NULL ) {
- e->terra_range->addKid( new_tile );
- }
-
- // load custom objects
- SG_LOG( SG_TERRAIN, SG_DEBUG, "CUSTOM OBJECTS" );
-
- SGPath index_path = tile_path;
- index_path.append( b.gen_index_str() );
- index_path.concat( ".ind" );
-
- SG_LOG( SG_TERRAIN, SG_DEBUG, "Looking in " << index_path.str() );
-
- sg_gzifstream in( index_path.str() );
-
- if ( in.is_open() ) {
- string token, name;
-
- while ( ! in.eof() ) {
- in >> token;
- in >> name;
-#if defined ( macintosh ) || defined ( _MSC_VER )
- in >> ::skipws;
-#else
- in >> skipws;
-#endif
- SG_LOG( SG_TERRAIN, SG_DEBUG, "token = " << token
- << " name = " << name );
-
- SGPath custom_path = tile_path;
- custom_path.append( name );
- ssgBranch *custom_obj =
- fgObjLoad( custom_path.str(), e, NULL, false );
- if ( (new_tile != NULL) && (custom_obj != NULL) ) {
- new_tile -> addKid( custom_obj );
- }
- }
- }
-
- e->terra_transform->addKid( e->terra_range );
-
- // calculate initial tile offset
- e->SetOffset( scenery.center );
- sgCoord sgcoord;
- sgSetCoord( &sgcoord,
- e->offset.x(), e->offset.y(), e->offset.z(),
- 0.0, 0.0, 0.0 );
- e->terra_transform->setTransform( &sgcoord );
- terrain->addKid( e->terra_transform );
-
- e->lights_transform = NULL;
- e->lights_range = NULL;
- /* uncomment this section for testing ground lights */
- if ( light_pts->getNum() ) {
- SG_LOG( SG_TERRAIN, SG_DEBUG, "generating lights" );
- e->lights_transform = new ssgTransform;
- e->lights_range = new ssgRangeSelector;
- e->lights_brightness = new ssgSelector;
- ssgLeaf *lights;
-
- lights = gen_lights( light_pts, 4, 0.7 );
- e->lights_brightness->addKid( lights );
-
- lights = gen_lights( light_pts, 2, 0.85 );
- e->lights_brightness->addKid( lights );
-
- lights = gen_lights( light_pts, 1, 1.0 );
- e->lights_brightness->addKid( lights );
-
- e->lights_range->addKid( e->lights_brightness );
- e->lights_transform->addKid( e->lights_range );
- e->lights_transform->setTransform( &sgcoord );
- ground->addKid( e->lights_transform );
- }
- /* end of ground light section */
+ e->load( tile_path, true );
}
// Ensure at least one entry is free in the cache
void FGNewCache::make_space() {
- SG_LOG( SG_TERRAIN, SG_INFO, "Make space in cache" );
+ SG_LOG( SG_TERRAIN, SG_DEBUG, "Make space in cache" );
SG_LOG( SG_TERRAIN, SG_DEBUG, "cache entries = " << tile_cache.size() );
- SG_LOG( SG_TERRAIN, SG_INFO, "max size = " << max_cache_size );
+ SG_LOG( SG_TERRAIN, SG_DEBUG, "max size = " << max_cache_size );
if ( (int)tile_cache.size() < max_cache_size ) {
// space in the cache, return
public:
// Constructor
- FGNewCache( void );
+ FGNewCache();
// Destructor
- ~FGNewCache( void );
+ ~FGNewCache();
// Initialize the tile cache subsystem
void init( void );
#include STL_FUNCTIONAL
#include STL_ALGORITHM
+#include STL_STRING
#include <simgear/bucket/newbucket.hxx>
#include <simgear/debug/logstream.hxx>
+#include <simgear/math/sg_random.h>
+#include <simgear/misc/sgstream.hxx>
#include <Aircraft/aircraft.hxx>
#include <Include/general.hxx>
#include <Main/globals.hxx>
#include <Scenery/scenery.hxx>
#include <Time/light.hxx>
+#include <Objects/matlib.hxx>
+#include <Objects/newmat.hxx>
+#include <Objects/obj.hxx>
#include "tileentry.hxx"
SG_USING_STD(for_each);
SG_USING_STD(mem_fun_ref);
+SG_USING_STD(string);
// Constructor
-FGTileEntry::FGTileEntry ()
- : ncount(0)
+FGTileEntry::FGTileEntry ( const SGBucket& b )
+ : ncount( 0 ),
+ center( Point3D( 0.0 ) ),
+ tile_bucket( b ),
+ terra_transform( new ssgTransform ),
+ terra_range( new ssgRangeSelector )
{
nodes.clear();
+
+ // update the contents
+ // if ( vec3_ptrs.size() || vec2_ptrs.size() || index_ptrs.size() ) {
+ // SG_LOG( SG_TERRAIN, SG_ALERT,
+ // "Attempting to overwrite existing or"
+ // << " not properly freed leaf data." );
+ // exit(-1);
+ // }
}
}
}
}
+
+
+ssgLeaf* FGTileEntry::gen_lights( ssgVertexArray *lights, int inc, float bright ) {
+ // generate a repeatable random seed
+ float *p1 = lights->get( 0 );
+ unsigned int *seed = (unsigned int *)p1;
+ sg_srandom( *seed );
+
+ int size = lights->getNum() / inc;
+
+ // Allocate ssg structure
+ ssgVertexArray *vl = new ssgVertexArray( size + 1 );
+ ssgNormalArray *nl = NULL;
+ ssgTexCoordArray *tl = NULL;
+ ssgColourArray *cl = new ssgColourArray( size + 1 );
+
+ sgVec4 color;
+ for ( int i = 0; i < lights->getNum(); ++i ) {
+ // this loop is slightly less efficient than it otherwise
+ // could be, but we want a red light to always be red, and a
+ // yellow light to always be yellow, etc. so we are trying to
+ // preserve the random sequence.
+ float zombie = sg_random();
+ if ( i % inc == 0 ) {
+ vl->add( lights->get(i) );
+
+ // factor = sg_random() ^ 2, range = 0 .. 1 concentrated towards 0
+ float factor = sg_random();
+ factor *= factor;
+
+ if ( zombie > 0.5 ) {
+ // 50% chance of yellowish
+ sgSetVec4( color, 0.9, 0.9, 0.3, bright - factor * 0.2 );
+ } else if ( zombie > 0.15 ) {
+ // 35% chance of whitish
+ sgSetVec4( color, 0.9, 0.9, 0.8, bright - factor * 0.2 );
+ } else if ( zombie > 0.05 ) {
+ // 10% chance of orangish
+ sgSetVec4( color, 0.9, 0.6, 0.2, bright - factor * 0.2 );
+ } else {
+ // 5% chance of redish
+ sgSetVec4( color, 0.9, 0.2, 0.2, bright - factor * 0.2 );
+ }
+ cl->add( color );
+ }
+ }
+
+ // create ssg leaf
+ ssgLeaf *leaf =
+ new ssgVtxTable ( GL_POINTS, vl, nl, tl, cl );
+
+ // assign state
+ FGNewMat *newmat = material_lib.find( "LIGHTS" );
+ leaf->setState( newmat->get_state() );
+
+ return leaf;
+}
+
+
+ssgBranch*
+FGTileEntry::obj_load( const std::string& path,
+ ssgVertexArray* lights, bool is_base )
+{
+ ssgBranch* result = 0;
+
+ // try loading binary format
+ result = fgBinObjLoad( path, this, lights, is_base );
+ if ( result == NULL ) {
+ // next try the older ascii format
+ result = fgAsciiObjLoad( path, this, lights, is_base );
+ if ( result == NULL ) {
+ // default to an ocean tile
+ result = fgGenTile( path, this );
+ }
+ }
+
+ return result;
+}
+
+
+void
+FGTileEntry::load( SGPath& tile_path, bool is_base )
+{
+ // a cheesy hack (to be fixed later)
+ extern ssgBranch *terrain;
+ extern ssgBranch *ground;
+
+ string index_str = tile_bucket.gen_index_str();
+
+ // Generate name of file to load.
+ tile_path.append( tile_bucket.gen_base_path() );
+ SGPath basename = tile_path;
+ basename.append( index_str );
+ string path = basename.str();
+
+ SG_LOG( SG_TERRAIN, SG_INFO, "Loading tile " << path );
+
+ // fgObjLoad will generate ground lighting for us ...
+ ssgVertexArray *light_pts = new ssgVertexArray( 100 );
+
+ ssgBranch* new_tile = obj_load( path, light_pts, is_base );
+ if ( new_tile != NULL ) {
+ terra_range->addKid( new_tile );
+ }
+
+ // load custom objects
+ SG_LOG( SG_TERRAIN, SG_DEBUG, "CUSTOM OBJECTS" );
+
+ SGPath index_path = tile_path;
+ index_path.append( index_str );
+ index_path.concat( ".ind" );
+
+ SG_LOG( SG_TERRAIN, SG_DEBUG, "Looking in " << index_path.str() );
+
+ sg_gzifstream in( index_path.str() );
+
+ if ( in.is_open() ) {
+ string token, name;
+
+ while ( ! in.eof() ) {
+ in >> token >> name >> ::skipws;
+ SG_LOG( SG_TERRAIN, SG_DEBUG, "token = " << token
+ << " name = " << name );
+
+ SGPath custom_path = tile_path;
+ custom_path.append( name );
+ ssgBranch *custom_obj = obj_load( custom_path.str(), NULL, false );
+ if ( (new_tile != NULL) && (custom_obj != NULL) ) {
+ new_tile -> addKid( custom_obj );
+ }
+ }
+ }
+
+ terra_transform->addKid( terra_range );
+
+ // calculate initial tile offset
+ SetOffset( scenery.center );
+ sgCoord sgcoord;
+ sgSetCoord( &sgcoord,
+ offset.x(), offset.y(), offset.z(),
+ 0.0, 0.0, 0.0 );
+ terra_transform->setTransform( &sgcoord );
+ terrain->addKid( terra_transform );
+
+ lights_transform = NULL;
+ lights_range = NULL;
+ /* uncomment this section for testing ground lights */
+ if ( light_pts->getNum() ) {
+ SG_LOG( SG_TERRAIN, SG_DEBUG, "generating lights" );
+ lights_transform = new ssgTransform;
+ lights_range = new ssgRangeSelector;
+ lights_brightness = new ssgSelector;
+ ssgLeaf *lights;
+
+ lights = gen_lights( light_pts, 4, 0.7 );
+ lights_brightness->addKid( lights );
+
+ lights = gen_lights( light_pts, 2, 0.85 );
+ lights_brightness->addKid( lights );
+
+ lights = gen_lights( light_pts, 1, 1.0 );
+ lights_brightness->addKid( lights );
+
+ lights_range->addKid( lights_brightness );
+ lights_transform->addKid( lights_range );
+ lights_transform->setTransform( &sgcoord );
+ ground->addKid( lights_transform );
+ }
+ /* end of ground light section */
+}
typedef point_list::const_iterator const_point_list_iterator;
-// Scenery tile class
+/**
+ * A class to encapsulate everything we need to know about a scenery tile.
+ */
class FGTileEntry {
public:
free_vec2_list vec2_ptrs;
free_index_list index_ptrs;
+private:
+
// ssg tree structure for this tile is as follows:
// ssgRoot(scene)
// - ssgBranch(terrain)
// want based on lighting conditions.
ssgSelector *lights_brightness;
+ ssgBranch* obj_load( const std::string& path,
+ ssgVertexArray* lights, bool is_base );
+
+ ssgLeaf* gen_lights( ssgVertexArray *lights, int inc, float bright );
+
public:
// Constructor
- FGTileEntry();
+ FGTileEntry( const SGBucket& b );
// Destructor
~FGTileEntry();
// Update the ssg transform node for this tile so it can be
// properly drawn relative to our (0,0,0) point
void prep_ssg_node( const Point3D& p, float vis);
+
+ /**
+ * 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
+ */
+ void load( SGPath& base, bool is_base );
};