diff --git a/src/Scenery/newcache.cxx b/src/Scenery/newcache.cxx index e9b848f13..742e1a9ab 100644 --- a/src/Scenery/newcache.cxx +++ b/src/Scenery/newcache.cxx @@ -36,21 +36,26 @@ #include #include +#include +#include #include #include #include
+#include +#include #include #include // for scenery.center #include "newcache.hxx" #include "tileentry.hxx" +#include "tilemgr.hxx" // temp, need to delete later FG_USING_NAMESPACE(std); // a cheesy hack (to be fixed later) extern ssgBranch *terrain; -extern ssgEntity *penguin; +extern ssgBranch *ground; // the tile cache @@ -128,6 +133,70 @@ static void print_refs( ssgSelector *sel, ssgTransform *trans, #endif +static ssgLeaf *gen_lights( const FGBucket &b ) { + + FGTileEntry *t = global_tile_cache.get_tile( b ); + Point3D center = t->get_offset() + scenery.center; + + double lon, lat, elev; + double w = b.get_width(); + double h = b.get_height(); + + double area = b.get_width_m() * b.get_height_m(); + int num = (int)(area / 1000000); // number of point lights to create + cout << "generating " << num << " lights" << endl; + + if ( num <= 0 ) { + return NULL; + } + + // Allocate ssg structure + ssgVertexArray *vl = new ssgVertexArray( num ); + ssgNormalArray *nl = NULL; + ssgTexCoordArray *tl = NULL; + ssgColourArray *cl = new ssgColourArray( 1 ); + + // default to white lights for now + sgVec4 color; + sgSetVec4( color, 1.0, 1.0, 1.0, 1.0 ); + cl->add( color ); + + for ( int i = 0; i < num; ++i ) { + lon = b.get_center_lon() - w * 0.5 + sg_random() * w; + lat = b.get_center_lat() - h * 0.5 + sg_random() * h; + + Point3D geod = Point3D( lon * DEG_TO_RAD, lat * DEG_TO_RAD, 0.0); + Point3D tmp = sgGeodToCart( geod ); + sgdVec3 cart; + sgdSetVec3( cart, tmp.x(), tmp.y(), tmp.z() ); + + if ( ! global_tile_mgr.current_elev_ssg( cart, &elev ) ) { + elev = 0.0; + } + // cout << " lon = " << lon << " lat = " << lat << " elev = " << elev + // << endl; + + geod.setz( elev + 8.0 + sg_random() * 4); + tmp = sgGeodToCart( geod ) - center; + sgVec3 p; + sgSetVec3( p, tmp.x(), tmp.y(), tmp.z() ); + // cout << " x = " << cart[0] << " y = " << cart[1] + // << " z = " << cart[2] << endl; + vl->add( p ); + } + + // 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 FGBucket& b ) { FG_LOG( FG_TERRAIN, FG_INFO, "FILL IN CACHE ENTRY = " << b.gen_index() ); @@ -151,9 +220,10 @@ void FGNewCache::fill_in( const FGBucket& b ) { exit(-1); } - e->select_ptr = new ssgSelector; - e->transform_ptr = new ssgTransform; - e->range_ptr = new ssgRangeSelector; + e->terra_transform = new ssgTransform; + e->terra_range = new ssgRangeSelector; + e->lights_transform = new ssgTransform; + e->lights_range = new ssgRangeSelector; e->tile_bucket = b; FGPath tile_path; @@ -171,7 +241,7 @@ void FGNewCache::fill_in( const FGBucket& b ) { ssgBranch *new_tile = fgObjLoad( tile_base.str(), e, true ); if ( new_tile != NULL ) { - e->range_ptr->addKid( new_tile ); + e->terra_range->addKid( new_tile ); } // load custom objects @@ -207,7 +277,7 @@ void FGNewCache::fill_in( const FGBucket& b ) { } } - e->transform_ptr->addKid( e->range_ptr ); + e->terra_transform->addKid( e->terra_range ); // calculate initial tile offset e->SetOffset( scenery.center ); @@ -215,12 +285,19 @@ void FGNewCache::fill_in( const FGBucket& b ) { sgSetCoord( &sgcoord, e->offset.x(), e->offset.y(), e->offset.z(), 0.0, 0.0, 0.0 ); - e->transform_ptr->setTransform( &sgcoord ); + e->terra_transform->setTransform( &sgcoord ); + terrain->addKid( e->terra_transform ); - e->select_ptr->addKid( e->transform_ptr ); - terrain->addKid( e->select_ptr ); - - e->select_ptr->select(1); + e->lights_transform = NULL; + /* uncomment this section for testing ground lights + ssgLeaf *lights = gen_lights( b ); + if ( lights ) { + e->lights_range->addKid( lights ); + e->lights_transform->addKid( e->lights_range ); + e->lights_transform->setTransform( &sgcoord ); + ground->addKid( e->lights_transform ); + } + */ } diff --git a/src/Scenery/tileentry.cxx b/src/Scenery/tileentry.cxx index 973b918d0..2765868d2 100644 --- a/src/Scenery/tileentry.cxx +++ b/src/Scenery/tileentry.cxx @@ -33,6 +33,10 @@ #include #include +#include +#include
+#include + #include "tileentry.hxx" FG_USING_STD(for_each); @@ -44,7 +48,6 @@ FGTileEntry::FGTileEntry () : ncount(0) { nodes.clear(); - select_ptr = NULL; } @@ -112,16 +115,15 @@ void FGTileEntry::free_tile() { } index_ptrs.clear(); - // delete the ssg branch - - int pcount = select_ptr->getNumParents(); + // delete the terrain branch + int pcount = terra_transform->getNumParents(); if ( pcount > 0 ) { // find the first parent (should only be one) - ssgBranch *parent = select_ptr->getParent( 0 ) ; + ssgBranch *parent = terra_transform->getParent( 0 ) ; if( parent ) { // my_remove_branch( select_ptr ); - parent->removeKid( select_ptr ); - select_ptr = NULL; + parent->removeKid( terra_transform ); + terra_transform = NULL; } else { FG_LOG( FG_TERRAIN, FG_ALERT, "parent pointer is NULL! Dying" ); @@ -132,12 +134,77 @@ void FGTileEntry::free_tile() { "Parent count is zero for an ssg tile! Dying" ); exit(-1); } + + 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 { + FG_LOG( FG_TERRAIN, FG_ALERT, + "parent pointer is NULL! Dying" ); + exit(-1); + } + } else { + FG_LOG( FG_TERRAIN, FG_ALERT, + "Parent count is zero for an ssg light tile! Dying" ); + exit(-1); + } + } } -// when a tile is still in the cache, but not in the immediate draw -// list, it can still remain in the scene graph, but we use a range -// selector to disable it from ever being drawn. -void FGTileEntry::ssg_disable() { - select_ptr->select(0); +// Update the ssg transform node for this tile so it can be +// properly drawn relative to our (0,0,0) point +void FGTileEntry::prep_ssg_node( const Point3D& p, float vis) { + SetOffset( p ); + +// #define USE_UP_AND_COMING_PLIB_FEATURE +#ifdef USE_UP_AND_COMING_PLIB_FEATURE + terra_range->setRange( 0, SG_ZERO ); + terra_range->setRange( 1, vis + bounding_radius ); + lights_range->setRange( 0, SG_ZERO ); + lights_range->setRange( 1, vis + bounding_radius ); +#else + float ranges[2]; + ranges[0] = SG_ZERO; + ranges[1] = vis + bounding_radius; + terra_range->setRanges( ranges, 2 ); + lights_range->setRanges( ranges, 2 ); +#endif + sgVec3 sgTrans; + sgSetVec3( sgTrans, offset.x(), offset.y(), offset.z() ); + terra_transform->setTransform( sgTrans ); + + if ( lights_transform ) { + // we need to lift the lights above the terrain to avoid + // z-buffer fighting. We do this based on our altitude and + // the distance this tile is away from scenery center. + + sgVec3 up; + sgCopyVec3( up, globals->get_current_view()->get_world_up() ); + + double agl; + if ( current_aircraft.fdm_state ) { + agl = current_aircraft.fdm_state->get_Altitude() * FEET_TO_METER + - scenery.cur_elev; + } else { + agl = 0.0; + } + + // sgTrans just happens to be the + // vector from scenery center to the center of this tile which + // is what we want to calculate the distance of + sgVec3 to; + sgCopyVec3( to, sgTrans ); + double dist = sgLengthVec3( to ); + + sgScaleVec3( up, agl / 20.0 + dist / 10000 ); + sgAddVec3( sgTrans, up ); + lights_transform->setTransform( sgTrans ); + } } diff --git a/src/Scenery/tileentry.hxx b/src/Scenery/tileentry.hxx index 95048b079..230b1ecdc 100644 --- a/src/Scenery/tileentry.hxx +++ b/src/Scenery/tileentry.hxx @@ -93,7 +93,6 @@ public: // ssg tree structure for this tile is as follows: // ssgRoot(scene) // - ssgBranch(terrain) - // - ssgSelector(tile) // - ssgTransform(tile) // - ssgRangeSelector(tile) // - ssgEntity(tile) @@ -102,14 +101,13 @@ public: // ... // - kidn(fan) - // selector (turn tile on/off) - ssgSelector *select_ptr; - // pointer to ssg transform for this tile - ssgTransform *transform_ptr; + ssgTransform *terra_transform; + ssgTransform *lights_transform; // pointer to ssg range selector for this tile - ssgRangeSelector *range_ptr; + ssgRangeSelector *terra_range; + ssgRangeSelector *lights_range; public: @@ -134,28 +132,7 @@ public: // Update the ssg transform node for this tile so it can be // properly drawn relative to our (0,0,0) point - inline void prep_ssg_node( const Point3D& p, float vis) { - SetOffset( p ); - -// #define USE_UP_AND_COMING_PLIB_FEATURE -#ifdef USE_UP_AND_COMING_PLIB_FEATURE - range_ptr->setRange( 0, SG_ZERO ); - range_ptr->setRange( 1, vis + bounding_radius ); -#else - float ranges[2]; - ranges[0] = SG_ZERO; - ranges[1] = vis + bounding_radius; - range_ptr->setRanges( ranges, 2 ); -#endif - sgVec3 sgTrans; - sgSetVec3( sgTrans, offset.x(), offset.y(), offset.z() ); - transform_ptr->setTransform( sgTrans ); - } - - // when a tile is still in the cache, but not in the immediate - // draw l ist, it can still remain in the scene graph, but we use - // a range selector to disable it from ever being drawn. - void ssg_disable(); + void prep_ssg_node( const Point3D& p, float vis); }; diff --git a/src/Scenery/tilemgr.cxx b/src/Scenery/tilemgr.cxx index b9af69eb6..1b45d3a46 100644 --- a/src/Scenery/tilemgr.cxx +++ b/src/Scenery/tilemgr.cxx @@ -30,7 +30,8 @@ #endif #include -#include + +#include #include #include @@ -70,7 +71,8 @@ static inline Point3D operator + (const Point3D& a, const sgdVec3 b) // Constructor FGTileMgr::FGTileMgr(): - state( Start ) + state( Start ), + vis( 16000 ) { } @@ -113,11 +115,7 @@ void FGTileMgr::sched_tile( const FGBucket& b ) { // see if tile already exists in the cache FGTileEntry *t = global_tile_cache.get_tile( b ); - if ( t != NULL ) { - // tile exists in cache, reenable it. - // cout << "REENABLING DISABLED TILE" << endl; - t->select_ptr->select( 1 ); - } else { + if ( t == NULL ) { // register a load request load_queue.push_back( b ); } @@ -132,6 +130,8 @@ void FGTileMgr::load_tile( const FGBucket& b ) { if ( t == NULL ) { FG_LOG( FG_TERRAIN, FG_DEBUG, "Loading tile " << b ); global_tile_cache.fill_in( b ); + FGTileEntry *t = global_tile_cache.get_tile( b ); + t->prep_ssg_node( scenery.center, vis); } else { FG_LOG( FG_TERRAIN, FG_DEBUG, "Tile already in cache " << b ); } @@ -153,11 +153,14 @@ static void CurrentNormalInLocalPlane(sgVec3 dst, sgVec3 src) { // explicitely. lat & lon are in radians. view_pos in current world // coordinate translated near (0,0,0) (in meters.) Returns result in // meters. -bool FGTileMgr::current_elev_ssg( sgdVec3 abs_view_pos, sgVec3 view_pos, - double *terrain_elev ) { - sgdVec3 orig, dir; +bool FGTileMgr::current_elev_ssg( sgdVec3 abs_view_pos, double *terrain_elev ) { + sgdVec3 view_pos; + sgdVec3 sc; + sgdSetVec3( sc, scenery.center.x(), scenery.center.y(), scenery.center.z()); + sgdSubVec3( view_pos, abs_view_pos, sc ); - sgdSetVec3(orig, view_pos ); + sgdVec3 orig, dir; + sgdCopyVec3(orig, view_pos ); sgdCopyVec3(dir, abs_view_pos ); hit_list.Intersect( terrain, orig, dir ); @@ -201,8 +204,6 @@ bool FGTileMgr::current_elev_ssg( sgdVec3 abs_view_pos, sgVec3 view_pos, // schedule a needed buckets for loading void FGTileMgr::schedule_needed() { - double vis; - #ifndef FG_OLD_WEATHER if ( WeatherDatabase != NULL ) { vis = WeatherDatabase->getWeatherVisibility(); @@ -214,31 +215,8 @@ void FGTileMgr::schedule_needed() { #endif cout << "visibility = " << vis << endl; - double clat = (int)current_bucket.get_center_lat(); - if ( clat > 0 ) { - clat = (int)clat + 0.5; - } else { - clat = (int)clat - 0.5; - } - double clat_rad = clat * DEG_TO_RAD; - double cos_lat = cos( clat_rad ); - double local_radius = cos_lat * EQUATORIAL_RADIUS_M; - double local_perimeter = 2.0 * local_radius * FG_PI; - double degree_width = local_perimeter / 360.0; - - // cout << "clat = " << clat << endl; - // cout << "clat (radians) = " << clat_rad << endl; - // cout << "cos(lat) = " << cos_lat << endl; - // cout << "local_radius = " << local_radius << endl; - // cout << "local_perimeter = " << local_perimeter << endl; - cout << "degree_width = " << degree_width << endl; - - double perimeter = 2.0 * EQUATORIAL_RADIUS_M * FG_PI; - double degree_height = perimeter / 360.0; - cout << "degree_height = " << degree_height << endl; - - double tile_width = current_bucket.get_width() * degree_width; - double tile_height = current_bucket.get_height() * degree_height; + double tile_width = current_bucket.get_width_m(); + double tile_height = current_bucket.get_height_m(); cout << "tile width = " << tile_width << " tile_height = " << tile_height << endl; @@ -371,7 +349,7 @@ int FGTileMgr::update( double lon, double lat ) { prep_ssg_nodes(); sgSetVec3( tmp_view_pos, 0.0, 0.0, 0.0 ); double tmp_elev; - if ( current_elev_ssg(tmp_abs_view_pos, tmp_view_pos, &tmp_elev) ) { + if ( current_elev_ssg(tmp_abs_view_pos, &tmp_elev) ) { scenery.cur_elev = tmp_elev; } else { scenery.cur_elev = 0.0; @@ -381,7 +359,6 @@ int FGTileMgr::update( double lon, double lat ) { // << " view pos = " << current_view.view_pos << endl; double tmp_elev; if ( current_elev_ssg(globals->get_current_view()->get_abs_view_pos(), - globals->get_current_view()->get_view_pos(), &tmp_elev) ) { scenery.cur_elev = tmp_elev; @@ -418,13 +395,12 @@ void FGTileMgr::prep_ssg_nodes() { // selector and transform FGTileEntry *e; - Point3D p = scenery.center; global_tile_cache.reset_traversal(); while ( ! global_tile_cache.at_end() ) { // cout << "processing a tile" << endl; if ( (e = global_tile_cache.get_current()) ) { - e->prep_ssg_node( p, vis); + e->prep_ssg_node( scenery.center, vis); } else { cout << "warning ... empty tile in cache" << endl; } diff --git a/src/Scenery/tilemgr.hxx b/src/Scenery/tilemgr.hxx index b90c2df84..7be5fe52c 100644 --- a/src/Scenery/tilemgr.hxx +++ b/src/Scenery/tilemgr.hxx @@ -102,6 +102,7 @@ private: FGTileEntry *current_tile; // x and y distance of tiles to load/draw + float vis; int xrange, yrange; // current longitude latitude @@ -137,9 +138,7 @@ public: const sgdVec3 p, const sgdVec3 dir, FGHitList *list ); - bool current_elev_ssg( sgdVec3 abs_view_pos, - sgVec3 view_pos, - double *terrain_elev ); + bool current_elev_ssg( sgdVec3 abs_view_pos, double *terrain_elev ); // Prepare the ssg nodes ... for each tile, set it's proper // transform and update it's range selector based on current