2001-05-19 16:59:43 +00:00
|
|
|
// tileentry.cxx -- routines to handle a scenery tile
|
1999-06-12 21:15:27 +00:00
|
|
|
//
|
|
|
|
// Written by Curtis Olson, started May 1998.
|
|
|
|
//
|
2004-11-19 22:10:41 +00:00
|
|
|
// Copyright (C) 1998 - 2001 Curtis L. Olson - http://www.flightgear.org/~curt
|
1999-06-12 21:15:27 +00:00
|
|
|
//
|
|
|
|
// This program is free software; you can redistribute it and/or
|
|
|
|
// modify it under the terms of the GNU General Public License as
|
|
|
|
// published by the Free Software Foundation; either version 2 of the
|
|
|
|
// License, or (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This program is distributed in the hope that it will be useful, but
|
|
|
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
// General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
// along with this program; if not, write to the Free Software
|
2006-02-21 01:16:04 +00:00
|
|
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
1999-06-12 21:15:27 +00:00
|
|
|
//
|
|
|
|
// $Id$
|
|
|
|
|
|
|
|
|
2001-05-15 22:30:39 +00:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include <config.h>
|
|
|
|
#endif
|
|
|
|
|
2000-02-15 03:30:01 +00:00
|
|
|
#include <simgear/compiler.h>
|
2004-10-10 19:19:23 +00:00
|
|
|
#include <plib/ul.h>
|
2003-08-29 16:46:21 +00:00
|
|
|
#include <Main/main.hxx>
|
|
|
|
|
|
|
|
|
2003-05-14 18:33:56 +00:00
|
|
|
#include STL_STRING
|
|
|
|
|
2006-10-29 19:30:21 +00:00
|
|
|
#include <osg/Array>
|
|
|
|
#include <osg/Geometry>
|
|
|
|
#include <osg/Geode>
|
|
|
|
#include <osg/LOD>
|
|
|
|
#include <osg/MatrixTransform>
|
|
|
|
#include <osg/NodeCallback>
|
|
|
|
#include <osg/Switch>
|
|
|
|
|
2000-02-16 23:01:03 +00:00
|
|
|
#include <simgear/bucket/newbucket.hxx>
|
|
|
|
#include <simgear/debug/logstream.hxx>
|
2003-12-30 05:57:25 +00:00
|
|
|
#include <simgear/math/polar3d.hxx>
|
2001-05-16 06:00:02 +00:00
|
|
|
#include <simgear/math/sg_geodesy.hxx>
|
2001-03-29 01:42:31 +00:00
|
|
|
#include <simgear/math/sg_random.h>
|
|
|
|
#include <simgear/misc/sgstream.hxx>
|
2003-05-12 21:34:29 +00:00
|
|
|
#include <simgear/scene/material/mat.hxx>
|
|
|
|
#include <simgear/scene/material/matlib.hxx>
|
2003-05-14 19:22:24 +00:00
|
|
|
#include <simgear/scene/tgdb/apt_signs.hxx>
|
2003-05-28 21:01:55 +00:00
|
|
|
#include <simgear/scene/tgdb/obj.hxx>
|
Mathias:
I have done a patch to eliminate the jitter of 3D-objects near the viewpoint
(for example 3D cockpit objects).
The problem is the roundoff accuracy of the float values used in the
scenegraph together with the transforms of the eyepoint relative to the
scenery center.
The solution will be to move the scenery center near the view point.
This way floats relative accuracy is enough to show a stable picture.
To get that right I have introduced a transform node for the scenegraph which
is responsible for that shift and uses double values as long as possible.
The scenery subsystem now has a list of all those transforms required to place
objects in the world and will tell all those transforms that the scenery
center has changed when the set_scenery_center() of the scenery subsystem is
called.
The problem was not solvable by SGModelPlacement and SGLocation, since not all
objects, especially the scenery, are placed using these classes.
The first approach was to have the scenery center exactly at the eyepoint.
This works well for the cockpit.
But then the ground jitters a bit below the aircraft. With our default views
you can't see that, but that F-18 has a camera view below the left engine
intake with the nose gear and the ground in its field of view, here I could
see that.
Having the scenery center constant will still have this roundoff problems, but
like it is now too, the roundoff error here is exactly the same in each
frame, so you will not notice any jitter.
The real solution is now to keep the scenery center constant as long as it is
in a ball of 30m radius around the view point. If the scenery center is
outside this ball, just put it at the view point.
As a sideeffect of now beeing able to switch the scenery center in the whole
scenegraph with one function call, I was able to remove a one half of a
problem when switching views, where the scenery center was far off for one or
two frames past switching from one view to the next. Also included is a fix
to the other half of this problem, where the view position was not yet copied
into a view when it is switched (at least under glut). This was responsible
for the 'Error: ...' messages of the cloud subsystem when views were
switched.
2005-04-29 14:38:24 +00:00
|
|
|
#include <simgear/scene/model/placementtrans.hxx>
|
1999-06-12 21:15:27 +00:00
|
|
|
|
2000-12-04 05:24:38 +00:00
|
|
|
#include <Aircraft/aircraft.hxx>
|
2000-12-05 14:27:27 +00:00
|
|
|
#include <Include/general.hxx>
|
2003-05-14 20:48:31 +00:00
|
|
|
#include <Main/fg_props.hxx>
|
2000-12-04 05:24:38 +00:00
|
|
|
#include <Main/globals.hxx>
|
2001-07-22 19:51:16 +00:00
|
|
|
#include <Main/viewer.hxx>
|
2000-12-04 05:24:38 +00:00
|
|
|
#include <Scenery/scenery.hxx>
|
2000-12-04 23:25:05 +00:00
|
|
|
#include <Time/light.hxx>
|
2000-12-04 05:24:38 +00:00
|
|
|
|
1999-06-12 21:15:27 +00:00
|
|
|
#include "tileentry.hxx"
|
2001-05-19 16:59:43 +00:00
|
|
|
#include "tilemgr.hxx"
|
1999-06-12 21:15:27 +00:00
|
|
|
|
2003-05-14 18:33:56 +00:00
|
|
|
SG_USING_STD(string);
|
|
|
|
|
1999-06-12 21:15:27 +00:00
|
|
|
|
|
|
|
// Constructor
|
2001-03-29 01:42:31 +00:00
|
|
|
FGTileEntry::FGTileEntry ( const SGBucket& b )
|
2003-05-14 20:48:31 +00:00
|
|
|
: center( Point3D( 0.0 ) ),
|
2001-03-29 01:42:31 +00:00
|
|
|
tile_bucket( b ),
|
2006-10-29 19:30:21 +00:00
|
|
|
terra_transform( new SGPlacementTransform ),
|
|
|
|
vasi_lights_transform( new SGPlacementTransform ),
|
|
|
|
rwy_lights_transform( new SGPlacementTransform ),
|
|
|
|
taxi_lights_transform( new SGPlacementTransform ),
|
|
|
|
terra_range( new osg::LOD ),
|
|
|
|
vasi_lights_selector( new osg::Switch ),
|
|
|
|
rwy_lights_selector( new osg::Switch ),
|
|
|
|
taxi_lights_selector( new osg::Switch ),
|
2001-05-19 16:59:43 +00:00
|
|
|
loaded(false),
|
2002-07-25 23:59:04 +00:00
|
|
|
pending_models(0),
|
2003-12-30 15:12:04 +00:00
|
|
|
is_inner_ring(false),
|
2002-07-25 23:59:04 +00:00
|
|
|
free_tracker(0)
|
1999-06-12 21:15:27 +00:00
|
|
|
{
|
2001-03-29 01:42:31 +00:00
|
|
|
// 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);
|
|
|
|
// }
|
1999-06-12 21:15:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Destructor
|
2000-12-03 20:15:46 +00:00
|
|
|
FGTileEntry::~FGTileEntry () {
|
1999-06-12 21:15:27 +00:00
|
|
|
// cout << "nodes = " << nodes.size() << endl;;
|
|
|
|
// delete[] nodes;
|
|
|
|
}
|
|
|
|
|
2006-10-29 19:30:21 +00:00
|
|
|
static void WorldCoordinate( osg::Matrix& obj_pos, Point3D center, double lat,
|
2001-05-23 22:28:38 +00:00
|
|
|
double lon, double elev, double hdg )
|
|
|
|
{
|
|
|
|
double lon_rad = lon * SGD_DEGREES_TO_RADIANS;
|
|
|
|
double lat_rad = lat * SGD_DEGREES_TO_RADIANS;
|
|
|
|
double hdg_rad = hdg * SGD_DEGREES_TO_RADIANS;
|
|
|
|
|
|
|
|
// setup transforms
|
|
|
|
Point3D geod( lon_rad, lat_rad, elev );
|
2002-09-23 15:27:46 +00:00
|
|
|
|
2001-05-23 22:28:38 +00:00
|
|
|
Point3D world_pos = sgGeodToCart( geod );
|
|
|
|
Point3D offset = world_pos - center;
|
|
|
|
|
|
|
|
sgMat4 mat;
|
|
|
|
|
|
|
|
SGfloat sin_lat = (SGfloat)sin( lat_rad );
|
|
|
|
SGfloat cos_lat = (SGfloat)cos( lat_rad );
|
|
|
|
SGfloat cos_lon = (SGfloat)cos( lon_rad );
|
|
|
|
SGfloat sin_lon = (SGfloat)sin( lon_rad );
|
|
|
|
SGfloat sin_hdg = (SGfloat)sin( hdg_rad ) ;
|
|
|
|
SGfloat cos_hdg = (SGfloat)cos( hdg_rad ) ;
|
|
|
|
|
|
|
|
mat[0][0] = cos_hdg * (SGfloat)sin_lat * (SGfloat)cos_lon - sin_hdg * (SGfloat)sin_lon;
|
|
|
|
mat[0][1] = cos_hdg * (SGfloat)sin_lat * (SGfloat)sin_lon + sin_hdg * (SGfloat)cos_lon;
|
2002-09-23 15:27:46 +00:00
|
|
|
mat[0][2] = -cos_hdg * (SGfloat)cos_lat;
|
|
|
|
mat[0][3] = SG_ZERO;
|
2001-05-23 22:28:38 +00:00
|
|
|
|
|
|
|
mat[1][0] = -sin_hdg * (SGfloat)sin_lat * (SGfloat)cos_lon - cos_hdg * (SGfloat)sin_lon;
|
|
|
|
mat[1][1] = -sin_hdg * (SGfloat)sin_lat * (SGfloat)sin_lon + cos_hdg * (SGfloat)cos_lon;
|
2002-09-23 15:27:46 +00:00
|
|
|
mat[1][2] = sin_hdg * (SGfloat)cos_lat;
|
|
|
|
mat[1][3] = SG_ZERO;
|
2001-05-23 22:28:38 +00:00
|
|
|
|
|
|
|
mat[2][0] = (SGfloat)cos_lat * (SGfloat)cos_lon;
|
|
|
|
mat[2][1] = (SGfloat)cos_lat * (SGfloat)sin_lon;
|
2002-09-23 15:27:46 +00:00
|
|
|
mat[2][2] = (SGfloat)sin_lat;
|
2001-05-23 22:28:38 +00:00
|
|
|
mat[2][3] = SG_ZERO;
|
|
|
|
|
|
|
|
mat[3][0] = offset.x();
|
|
|
|
mat[3][1] = offset.y();
|
|
|
|
mat[3][2] = offset.z();
|
|
|
|
mat[3][3] = SG_ONE ;
|
|
|
|
|
2006-10-29 19:30:21 +00:00
|
|
|
for (unsigned i = 0; i < 4; ++i)
|
|
|
|
for (unsigned j = 0; j < 4; ++j)
|
|
|
|
obj_pos(i, j) = mat[i][j];
|
2001-05-23 22:28:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-10-29 19:30:21 +00:00
|
|
|
// recurse an ssg tree and call removeChild() on every node from the
|
1999-10-26 03:45:33 +00:00
|
|
|
// bottom up. Leaves the original branch in existance, but empty so
|
|
|
|
// it can be removed by the calling routine.
|
2006-10-29 19:30:21 +00:00
|
|
|
// static void my_remove_branch( osg::Group * branch ) {
|
|
|
|
// branch->removeChildren(0, branch->getNumChildren());
|
|
|
|
// }
|
1999-10-26 03:45:33 +00:00
|
|
|
|
2001-05-19 16:59:43 +00:00
|
|
|
|
2002-07-25 23:59:04 +00:00
|
|
|
// Free "n" leaf elements of an ssg tree. returns the number of
|
|
|
|
// elements freed. An empty branch node is considered a leaf. This
|
|
|
|
// is intended to spread the load of freeing a complex tile out over
|
|
|
|
// several frames.
|
2006-10-29 19:30:21 +00:00
|
|
|
static int fgPartialFreeSSGtree( osg::Group *b, int n ) {
|
2002-07-29 05:07:38 +00:00
|
|
|
int num_deletes = 0;
|
|
|
|
|
2006-10-29 19:30:21 +00:00
|
|
|
b->removeChildren(0, b->getNumChildren());
|
|
|
|
|
|
|
|
// if ( n > 0 ) {
|
|
|
|
// // we still have some delete budget left
|
|
|
|
// // if ( b->getNumChilds() > 100 ) {
|
|
|
|
// // cout << "large family = " << b->getNumChilds() << endl;
|
|
|
|
// // }
|
|
|
|
// // deleting in reverse would help if my plib patch get's
|
|
|
|
// // applied, but for now it will make things slower.
|
|
|
|
// // for ( int i = b->getNumChilds() - 1; i >= 0 ; --i ) {
|
|
|
|
// for ( int i = 0; i < b->getNumChildren(); ++i ) {
|
|
|
|
// ssgEntity *kid = b->getChild(i);
|
|
|
|
// if ( kid->isAKindOf( ssgTypeBranch() ) && kid->getRef() <= 1 ) {
|
|
|
|
// int result = fgPartialFreeSSGtree( (osg::Group *)kid, n );
|
|
|
|
// num_deletes += result;
|
|
|
|
// n -= result;
|
|
|
|
// if ( n < 0 ) {
|
|
|
|
// break;
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// // remove the kid if (a) it is now empty -or- (b) it's ref
|
|
|
|
// // count is > zero at which point we don't care if it's
|
|
|
|
// // empty, we don't want to touch it's contents.
|
|
|
|
// if ( kid->getNumChildren() == 0 || kid->getRef() > 1 ) {
|
|
|
|
// b->removeChild( kid );
|
|
|
|
// num_deletes++;
|
|
|
|
// n--;
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// }
|
2002-07-29 05:07:38 +00:00
|
|
|
|
|
|
|
return num_deletes;
|
2002-07-25 23:59:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-06-23 00:30:04 +00:00
|
|
|
// Clean up the memory used by this tile and delete the arrays used by
|
1999-06-29 14:57:00 +00:00
|
|
|
// ssg as well as the whole ssg branch
|
2002-07-25 23:59:04 +00:00
|
|
|
bool FGTileEntry::free_tile() {
|
|
|
|
int delete_size = 100;
|
2001-03-24 06:03:11 +00:00
|
|
|
SG_LOG( SG_TERRAIN, SG_DEBUG,
|
2002-09-23 15:27:46 +00:00
|
|
|
"FREEING TILE = (" << tile_bucket << ")" );
|
1999-10-27 00:52:25 +00:00
|
|
|
|
2002-08-06 18:50:12 +00:00
|
|
|
SG_LOG( SG_TERRAIN, SG_DEBUG, "(start) free_tracker = " << free_tracker );
|
|
|
|
|
2002-07-25 23:59:04 +00:00
|
|
|
if ( !(free_tracker & NODES) ) {
|
|
|
|
free_tracker |= NODES;
|
|
|
|
} else if ( !(free_tracker & VEC_PTRS) ) {
|
|
|
|
free_tracker |= VEC_PTRS;
|
|
|
|
} else if ( !(free_tracker & TERRA_NODE) ) {
|
|
|
|
// delete the terrain branch (this should already have been
|
|
|
|
// disconnected from the scene graph)
|
|
|
|
SG_LOG( SG_TERRAIN, SG_DEBUG, "FREEING terra_transform" );
|
2006-10-29 19:30:21 +00:00
|
|
|
if ( fgPartialFreeSSGtree( terra_transform.get(), delete_size ) == 0 ) {
|
2006-02-08 10:25:56 +00:00
|
|
|
terra_transform = 0;
|
2002-07-25 23:59:04 +00:00
|
|
|
free_tracker |= TERRA_NODE;
|
|
|
|
}
|
2006-10-29 19:30:21 +00:00
|
|
|
} else if ( !(free_tracker & GROUND_LIGHTS) && gnd_lights_transform.get() ) {
|
2002-07-25 23:59:04 +00:00
|
|
|
// delete the terrain lighting branch (this should already have been
|
|
|
|
// disconnected from the scene graph)
|
|
|
|
SG_LOG( SG_TERRAIN, SG_DEBUG, "FREEING gnd_lights_transform" );
|
2006-10-29 19:30:21 +00:00
|
|
|
if ( fgPartialFreeSSGtree( gnd_lights_transform.get(), delete_size ) == 0 ) {
|
2006-02-08 10:25:56 +00:00
|
|
|
gnd_lights_transform = 0;
|
2002-07-25 23:59:04 +00:00
|
|
|
free_tracker |= GROUND_LIGHTS;
|
|
|
|
}
|
2006-10-29 19:30:21 +00:00
|
|
|
} else if ( !(free_tracker & VASI_LIGHTS) && vasi_lights_selector.get() ) {
|
2003-09-24 19:59:25 +00:00
|
|
|
// delete the runway lighting branch (this should already have
|
|
|
|
// been disconnected from the scene graph)
|
|
|
|
SG_LOG( SG_TERRAIN, SG_DEBUG, "FREEING vasi_lights_selector" );
|
2006-10-29 19:30:21 +00:00
|
|
|
if ( fgPartialFreeSSGtree( vasi_lights_selector.get(), delete_size ) == 0 ) {
|
2006-02-08 10:25:56 +00:00
|
|
|
vasi_lights_selector = 0;
|
2003-09-24 19:59:25 +00:00
|
|
|
free_tracker |= VASI_LIGHTS;
|
|
|
|
}
|
2006-10-29 19:30:21 +00:00
|
|
|
} else if ( !(free_tracker & RWY_LIGHTS) && rwy_lights_selector.get() ) {
|
2002-11-01 21:56:48 +00:00
|
|
|
// delete the runway lighting branch (this should already have
|
|
|
|
// been disconnected from the scene graph)
|
2003-05-14 20:48:31 +00:00
|
|
|
SG_LOG( SG_TERRAIN, SG_DEBUG, "FREEING rwy_lights_selector" );
|
2006-10-29 19:30:21 +00:00
|
|
|
if ( fgPartialFreeSSGtree( rwy_lights_selector.get(), delete_size ) == 0 ) {
|
2006-02-08 10:25:56 +00:00
|
|
|
rwy_lights_selector = 0;
|
2002-07-25 23:59:04 +00:00
|
|
|
free_tracker |= RWY_LIGHTS;
|
|
|
|
}
|
2006-10-29 19:30:21 +00:00
|
|
|
} else if ( !(free_tracker & TAXI_LIGHTS) && taxi_lights_selector.get() ) {
|
2002-11-01 21:56:48 +00:00
|
|
|
// delete the taxi lighting branch (this should already have been
|
|
|
|
// disconnected from the scene graph)
|
2003-05-14 20:48:31 +00:00
|
|
|
SG_LOG( SG_TERRAIN, SG_DEBUG, "FREEING taxi_lights_selector" );
|
2006-10-29 19:30:21 +00:00
|
|
|
if ( fgPartialFreeSSGtree( taxi_lights_selector.get(), delete_size ) == 0 ) {
|
2006-02-08 10:25:56 +00:00
|
|
|
taxi_lights_selector = 0;
|
2002-11-01 21:56:48 +00:00
|
|
|
free_tracker |= TAXI_LIGHTS;
|
|
|
|
}
|
2003-05-08 03:29:49 +00:00
|
|
|
} else if ( !(free_tracker & LIGHTMAPS) ) {
|
|
|
|
free_tracker |= LIGHTMAPS;
|
2002-07-25 23:59:04 +00:00
|
|
|
} else {
|
|
|
|
return true;
|
2001-09-19 22:30:41 +00:00
|
|
|
}
|
2002-07-25 23:59:04 +00:00
|
|
|
|
2002-08-06 18:50:12 +00:00
|
|
|
SG_LOG( SG_TERRAIN, SG_DEBUG, "(end) free_tracker = " << free_tracker );
|
|
|
|
|
2002-07-25 23:59:04 +00:00
|
|
|
// if we fall down to here, we still have work todo, return false
|
|
|
|
return false;
|
1999-06-12 21:15:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-12-04 05:24:38 +00:00
|
|
|
// Update the ssg transform node for this tile so it can be
|
|
|
|
// properly drawn relative to our (0,0,0) point
|
2002-04-07 15:24:32 +00:00
|
|
|
void FGTileEntry::prep_ssg_node( const Point3D& p, sgVec3 up, float vis) {
|
2001-04-06 18:30:07 +00:00
|
|
|
if ( !loaded ) return;
|
|
|
|
|
2002-10-30 21:59:05 +00:00
|
|
|
// visibility can change from frame to frame so we update the
|
|
|
|
// range selector cutoff's each time.
|
2006-10-29 19:30:21 +00:00
|
|
|
terra_range->setRange( 0, 0, vis + bounding_radius );
|
2002-10-30 21:59:05 +00:00
|
|
|
|
2006-10-29 19:30:21 +00:00
|
|
|
if ( gnd_lights_range.get() ) {
|
|
|
|
gnd_lights_range->setRange( 0, 0, vis * 1.5 + bounding_radius );
|
2002-04-07 15:24:32 +00:00
|
|
|
}
|
2002-10-09 03:40:23 +00:00
|
|
|
|
2006-10-29 19:30:21 +00:00
|
|
|
SGVec3d lt_trans(center.x(), center.y(), center.z());
|
2000-12-04 05:24:38 +00:00
|
|
|
|
2003-09-20 09:38:32 +00:00
|
|
|
FGLight *l = (FGLight *)(globals->get_subsystem("lighting"));
|
2006-10-29 19:30:21 +00:00
|
|
|
if ( gnd_lights_transform.get() ) {
|
2002-09-23 15:27:46 +00:00
|
|
|
// 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.
|
2000-12-04 05:24:38 +00:00
|
|
|
|
2002-04-16 06:33:56 +00:00
|
|
|
// we expect 'up' to be a unit vector coming in, but since we
|
|
|
|
// modify the value of lift_vec, we need to create a local
|
|
|
|
// copy.
|
2006-10-29 19:30:21 +00:00
|
|
|
SGVec3f lift_vec(up);
|
|
|
|
|
2002-09-23 15:27:46 +00:00
|
|
|
double agl;
|
2005-08-14 12:57:12 +00:00
|
|
|
agl = globals->get_current_view()->getAltitudeASL_ft()*SG_FEET_TO_METER
|
|
|
|
- globals->get_current_view()->getSGLocation()->get_cur_elev_m();
|
2000-12-04 05:24:38 +00:00
|
|
|
|
Mathias:
I have done a patch to eliminate the jitter of 3D-objects near the viewpoint
(for example 3D cockpit objects).
The problem is the roundoff accuracy of the float values used in the
scenegraph together with the transforms of the eyepoint relative to the
scenery center.
The solution will be to move the scenery center near the view point.
This way floats relative accuracy is enough to show a stable picture.
To get that right I have introduced a transform node for the scenegraph which
is responsible for that shift and uses double values as long as possible.
The scenery subsystem now has a list of all those transforms required to place
objects in the world and will tell all those transforms that the scenery
center has changed when the set_scenery_center() of the scenery subsystem is
called.
The problem was not solvable by SGModelPlacement and SGLocation, since not all
objects, especially the scenery, are placed using these classes.
The first approach was to have the scenery center exactly at the eyepoint.
This works well for the cockpit.
But then the ground jitters a bit below the aircraft. With our default views
you can't see that, but that F-18 has a camera view below the left engine
intake with the nose gear and the ground in its field of view, here I could
see that.
Having the scenery center constant will still have this roundoff problems, but
like it is now too, the roundoff error here is exactly the same in each
frame, so you will not notice any jitter.
The real solution is now to keep the scenery center constant as long as it is
in a ball of 30m radius around the view point. If the scenery center is
outside this ball, just put it at the view point.
As a sideeffect of now beeing able to switch the scenery center in the whole
scenegraph with one function call, I was able to remove a one half of a
problem when switching views, where the scenery center was far off for one or
two frames past switching from one view to the next. Also included is a fix
to the other half of this problem, where the view position was not yet copied
into a view when it is switched (at least under glut). This was responsible
for the 'Error: ...' messages of the cloud subsystem when views were
switched.
2005-04-29 14:38:24 +00:00
|
|
|
// Compute the distance of the scenery center from the view position.
|
|
|
|
double dist = center.distance3D(p);
|
2002-09-23 15:27:46 +00:00
|
|
|
|
|
|
|
if ( general.get_glDepthBits() > 16 ) {
|
2006-10-29 19:30:21 +00:00
|
|
|
lift_vec *= 10.0 + agl / 100.0 + dist / 10000;
|
2002-09-23 15:27:46 +00:00
|
|
|
} else {
|
2006-10-29 19:30:21 +00:00
|
|
|
lift_vec *= 10.0 + agl / 20.0 + dist / 5000;
|
2002-09-23 15:27:46 +00:00
|
|
|
}
|
|
|
|
|
2006-10-29 19:30:21 +00:00
|
|
|
gnd_lights_transform->setTransform( lt_trans + toVec3d(lift_vec) );
|
2002-09-23 15:27:46 +00:00
|
|
|
|
|
|
|
// select which set of lights based on sun angle
|
2003-09-20 09:38:32 +00:00
|
|
|
float sun_angle = l->get_sun_angle() * SGD_RADIANS_TO_DEGREES;
|
2002-09-23 15:27:46 +00:00
|
|
|
if ( sun_angle > 95 ) {
|
2006-10-29 19:30:21 +00:00
|
|
|
gnd_lights_brightness->setSingleChildOn(2);
|
2002-09-23 15:27:46 +00:00
|
|
|
} else if ( sun_angle > 92 ) {
|
2006-10-29 19:30:21 +00:00
|
|
|
gnd_lights_brightness->setSingleChildOn(1);
|
2002-09-23 15:27:46 +00:00
|
|
|
} else if ( sun_angle > 89 ) {
|
2006-10-29 19:30:21 +00:00
|
|
|
gnd_lights_brightness->setSingleChildOn(0);
|
2002-09-23 15:27:46 +00:00
|
|
|
} else {
|
2006-10-29 19:30:21 +00:00
|
|
|
gnd_lights_brightness->setAllChildrenOff();
|
2002-09-23 15:27:46 +00:00
|
|
|
}
|
2000-12-04 05:24:38 +00:00
|
|
|
}
|
2001-09-19 22:30:41 +00:00
|
|
|
|
2006-10-29 19:30:21 +00:00
|
|
|
if ( rwy_lights_transform.get() ) {
|
2003-05-14 20:48:31 +00:00
|
|
|
// turn runway lights on/off based on sun angle and visibility
|
2003-09-20 09:38:32 +00:00
|
|
|
float sun_angle = l->get_sun_angle() * SGD_RADIANS_TO_DEGREES;
|
2003-05-14 20:48:31 +00:00
|
|
|
if ( sun_angle > 85 ||
|
|
|
|
(fgGetDouble("/environment/visibility-m") < 5000.0) ) {
|
2006-10-29 19:30:21 +00:00
|
|
|
rwy_lights_selector->setAllChildrenOn();
|
2003-05-14 20:48:31 +00:00
|
|
|
} else {
|
2006-10-29 19:30:21 +00:00
|
|
|
rwy_lights_selector->setAllChildrenOff();
|
2003-05-14 20:48:31 +00:00
|
|
|
}
|
2002-03-04 02:36:06 +00:00
|
|
|
}
|
|
|
|
|
2006-10-29 19:30:21 +00:00
|
|
|
if ( taxi_lights_transform.get() ) {
|
2003-05-14 20:48:31 +00:00
|
|
|
// turn taxi lights on/off based on sun angle and visibility
|
2003-09-20 09:38:32 +00:00
|
|
|
float sun_angle = l->get_sun_angle() * SGD_RADIANS_TO_DEGREES;
|
2003-05-14 20:48:31 +00:00
|
|
|
if ( sun_angle > 85 ||
|
|
|
|
(fgGetDouble("/environment/visibility-m") < 5000.0) ) {
|
2006-10-29 19:30:21 +00:00
|
|
|
taxi_lights_selector->setAllChildrenOn();
|
2003-05-14 20:48:31 +00:00
|
|
|
} else {
|
2006-10-29 19:30:21 +00:00
|
|
|
taxi_lights_selector->setAllChildrenOff();
|
2003-12-30 05:57:25 +00:00
|
|
|
}
|
|
|
|
}
|
1999-07-04 07:37:30 +00:00
|
|
|
}
|
2001-03-29 01:42:31 +00:00
|
|
|
|
|
|
|
|
2006-10-29 19:30:21 +00:00
|
|
|
osg::Node*
|
|
|
|
FGTileEntry::gen_lights( SGMaterialLib *matlib, osg::Vec3Array *lights,
|
|
|
|
int inc, float bright )
|
2003-05-14 18:33:56 +00:00
|
|
|
{
|
2001-03-29 01:42:31 +00:00
|
|
|
// generate a repeatable random seed
|
2006-10-29 19:30:21 +00:00
|
|
|
sg_srandom( (unsigned)(*lights)[0][0] );
|
2001-03-29 01:42:31 +00:00
|
|
|
|
|
|
|
// Allocate ssg structure
|
2006-10-29 19:30:21 +00:00
|
|
|
osg::Vec3Array *vl = new osg::Vec3Array;
|
|
|
|
osg::Vec4Array *cl = new osg::Vec4Array;
|
2001-03-29 01:42:31 +00:00
|
|
|
|
2006-10-29 19:30:21 +00:00
|
|
|
for ( unsigned i = 0; i < lights->size(); ++i ) {
|
2002-09-23 15:27:46 +00:00
|
|
|
// 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 ) {
|
2006-10-29 19:30:21 +00:00
|
|
|
vl->push_back( (*lights)[i] );
|
2002-09-23 15:27:46 +00:00
|
|
|
|
|
|
|
// factor = sg_random() ^ 2, range = 0 .. 1 concentrated towards 0
|
|
|
|
float factor = sg_random();
|
|
|
|
factor *= factor;
|
|
|
|
|
2006-10-29 19:30:21 +00:00
|
|
|
osg::Vec4 color;
|
2002-09-23 15:27:46 +00:00
|
|
|
if ( zombie > 0.5 ) {
|
|
|
|
// 50% chance of yellowish
|
2006-10-29 19:30:21 +00:00
|
|
|
color = osg::Vec4( 0.9, 0.9, 0.3, bright - factor * 0.2 );
|
2002-09-23 15:27:46 +00:00
|
|
|
} else if ( zombie > 0.15 ) {
|
|
|
|
// 35% chance of whitish
|
2006-10-29 19:30:21 +00:00
|
|
|
color = osg::Vec4( 0.9, 0.9, 0.8, bright - factor * 0.2 );
|
2002-09-23 15:27:46 +00:00
|
|
|
} else if ( zombie > 0.05 ) {
|
|
|
|
// 10% chance of orangish
|
2006-10-29 19:30:21 +00:00
|
|
|
color = osg::Vec4( 0.9, 0.6, 0.2, bright - factor * 0.2 );
|
2002-09-23 15:27:46 +00:00
|
|
|
} else {
|
|
|
|
// 5% chance of redish
|
2006-10-29 19:30:21 +00:00
|
|
|
color = osg::Vec4( 0.9, 0.2, 0.2, bright - factor * 0.2 );
|
2002-09-23 15:27:46 +00:00
|
|
|
}
|
2006-10-29 19:30:21 +00:00
|
|
|
cl->push_back( color );
|
2002-09-23 15:27:46 +00:00
|
|
|
}
|
2001-03-29 01:42:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// create ssg leaf
|
2006-10-29 19:30:21 +00:00
|
|
|
osg::Geometry* geometry = new osg::Geometry;
|
|
|
|
geometry->setVertexArray(vl);
|
|
|
|
geometry->setColorArray(cl);
|
|
|
|
geometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
|
|
|
|
geometry->addPrimitiveSet(new osg::DrawArrays(GL_POINTS, 0, vl->size()));
|
|
|
|
osg::Geode* geode = new osg::Geode;
|
|
|
|
geode->addDrawable(geometry);
|
2001-03-29 01:42:31 +00:00
|
|
|
|
|
|
|
// assign state
|
2003-05-14 18:33:56 +00:00
|
|
|
SGMaterial *mat = matlib->find( "GROUND_LIGHTS" );
|
2006-10-29 19:30:21 +00:00
|
|
|
geode->setStateSet(mat->get_state());
|
2001-03-29 01:42:31 +00:00
|
|
|
|
2006-10-29 19:30:21 +00:00
|
|
|
return geode;
|
2001-03-29 01:42:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-05-14 18:33:56 +00:00
|
|
|
bool FGTileEntry::obj_load( const string& path,
|
2006-10-29 19:30:21 +00:00
|
|
|
osg::Group *geometry,
|
|
|
|
osg::Group *vasi_lights,
|
|
|
|
osg::Group *rwy_lights,
|
|
|
|
osg::Group *taxi_lights,
|
|
|
|
osg::Vec3Array *ground_lights, bool is_base )
|
2001-03-29 01:42:31 +00:00
|
|
|
{
|
2002-09-23 15:27:46 +00:00
|
|
|
Point3D c; // returned center point
|
|
|
|
double br; // returned bounding radius
|
2001-03-29 01:42:31 +00:00
|
|
|
|
2003-05-14 20:48:31 +00:00
|
|
|
bool use_random_objects =
|
|
|
|
fgGetBool("/sim/rendering/random-objects", true);
|
|
|
|
|
2001-03-29 01:42:31 +00:00
|
|
|
// try loading binary format
|
2006-10-29 19:30:21 +00:00
|
|
|
if ( SGBinObjLoad( path, is_base,
|
2003-05-14 20:48:31 +00:00
|
|
|
&c, &br, globals->get_matlib(), use_random_objects,
|
2003-09-24 19:59:25 +00:00
|
|
|
geometry, vasi_lights, rwy_lights, taxi_lights,
|
|
|
|
ground_lights ) )
|
2002-03-03 20:29:31 +00:00
|
|
|
{
|
2002-09-23 15:27:46 +00:00
|
|
|
if ( is_base ) {
|
|
|
|
center = c;
|
|
|
|
bounding_radius = br;
|
|
|
|
}
|
2001-03-29 01:42:31 +00:00
|
|
|
}
|
|
|
|
|
2002-10-09 03:40:23 +00:00
|
|
|
return (geometry != NULL);
|
2001-03-29 01:42:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-12-02 21:46:33 +00:00
|
|
|
typedef enum {
|
|
|
|
OBJECT,
|
|
|
|
OBJECT_SHARED,
|
|
|
|
OBJECT_STATIC,
|
2006-04-14 14:50:11 +00:00
|
|
|
OBJECT_SIGN,
|
2005-12-02 21:46:33 +00:00
|
|
|
OBJECT_RUNWAY_SIGN
|
|
|
|
} object_type;
|
|
|
|
|
|
|
|
|
|
|
|
// storage class for deferred object processing in FGTileEntry::load()
|
|
|
|
struct Object {
|
2005-12-03 10:20:35 +00:00
|
|
|
Object(object_type t, const string& token, const SGPath& p, istream& in)
|
2005-12-02 21:46:33 +00:00
|
|
|
: type(t), path(p)
|
|
|
|
{
|
|
|
|
in >> name;
|
|
|
|
if (type != OBJECT)
|
|
|
|
in >> lon >> lat >> elev >> hdg;
|
|
|
|
in >> ::skipeol;
|
|
|
|
|
|
|
|
if (type == OBJECT)
|
2005-12-03 10:20:35 +00:00
|
|
|
SG_LOG(SG_TERRAIN, SG_INFO, " " << token << " " << name);
|
2005-12-02 21:46:33 +00:00
|
|
|
else
|
2005-12-03 10:20:35 +00:00
|
|
|
SG_LOG(SG_TERRAIN, SG_INFO, " " << token << " " << name << " lon=" <<
|
|
|
|
lon << " lat=" << lat << " elev=" << elev << " hdg=" << hdg);
|
2005-12-02 21:46:33 +00:00
|
|
|
}
|
|
|
|
object_type type;
|
|
|
|
string name;
|
|
|
|
SGPath path;
|
|
|
|
double lon, lat, elev, hdg;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2001-03-29 01:42:31 +00:00
|
|
|
void
|
Melchior FRANZ:
Wouldn't it be better to prepare the whole list of paths (or two
separate ones for Terrain/Objects if necessary) in FGGlobals::set_fg_scenery,
and to pass the vector<string>s to FGTileEntry::load? It doesn't seem to make
a lot of sense to split the path up, modify it, mount it together to one string
again, and then let FGTileEntry::load split it up again.
Here we go:
Main/globals.cxx
================
As fg_scenery is now a string_list, we don't need initialization. Furthermore,
this list is cleared with every set_fg_scenery() call.
ctor: create default dir from fg_root if necessary. Otherwise check all paths
of --fg-scenery/FG_SCENERY: If the path doesn't exist, ignore it. If it contains
a dir Terrain and/or Objects, then only add that to the list. If it contains
neither, then use the path as is.
Scenery/tileentry.cxx
=====================
Trivial: don't split a "base path", but use the given path_list as is.
(I considered a variable name "path_list" better suited than "search".)
Scenery/FGTileLoader.cxx
========================
No more fiddling with sub-paths. This has to be delivered by get_fg_scenery
already.
2004-06-08 15:32:09 +00:00
|
|
|
FGTileEntry::load( const string_list &path_list, bool is_base )
|
2001-03-29 01:42:31 +00:00
|
|
|
{
|
2003-08-08 20:11:22 +00:00
|
|
|
bool found_tile_base = false;
|
2001-03-29 01:42:31 +00:00
|
|
|
|
2005-12-02 21:46:33 +00:00
|
|
|
SGPath object_base;
|
|
|
|
vector<const Object*> objects;
|
2001-03-29 01:42:31 +00:00
|
|
|
|
2005-12-03 10:20:35 +00:00
|
|
|
string index_str = tile_bucket.gen_index_str();
|
|
|
|
SG_LOG( SG_TERRAIN, SG_INFO, "Loading tile " << index_str );
|
|
|
|
|
2005-12-02 21:46:33 +00:00
|
|
|
// scan and parse all files and store information
|
2005-12-03 10:20:35 +00:00
|
|
|
for (unsigned int i = 0; i < path_list.size(); i++) {
|
|
|
|
// If we found a terrain tile in Terrain/, we have to process the
|
|
|
|
// Objects/ dir in the same group, too, before we can stop scanning.
|
|
|
|
// FGGlobals::set_fg_scenery() inserts an empty string to path_list
|
|
|
|
// as marker.
|
|
|
|
if (path_list[i].empty()) {
|
|
|
|
if (found_tile_base)
|
|
|
|
break;
|
|
|
|
else
|
|
|
|
continue;
|
|
|
|
}
|
2003-10-01 22:49:06 +00:00
|
|
|
|
|
|
|
bool has_base = false;
|
2001-03-29 01:42:31 +00:00
|
|
|
|
Melchior FRANZ:
Wouldn't it be better to prepare the whole list of paths (or two
separate ones for Terrain/Objects if necessary) in FGGlobals::set_fg_scenery,
and to pass the vector<string>s to FGTileEntry::load? It doesn't seem to make
a lot of sense to split the path up, modify it, mount it together to one string
again, and then let FGTileEntry::load split it up again.
Here we go:
Main/globals.cxx
================
As fg_scenery is now a string_list, we don't need initialization. Furthermore,
this list is cleared with every set_fg_scenery() call.
ctor: create default dir from fg_root if necessary. Otherwise check all paths
of --fg-scenery/FG_SCENERY: If the path doesn't exist, ignore it. If it contains
a dir Terrain and/or Objects, then only add that to the list. If it contains
neither, then use the path as is.
Scenery/tileentry.cxx
=====================
Trivial: don't split a "base path", but use the given path_list as is.
(I considered a variable name "path_list" better suited than "search".)
Scenery/FGTileLoader.cxx
========================
No more fiddling with sub-paths. This has to be delivered by get_fg_scenery
already.
2004-06-08 15:32:09 +00:00
|
|
|
SGPath tile_path = path_list[i];
|
2003-08-08 20:11:22 +00:00
|
|
|
tile_path.append( tile_bucket.gen_base_path() );
|
2002-09-23 15:27:46 +00:00
|
|
|
|
2003-08-08 20:11:22 +00:00
|
|
|
SGPath basename = tile_path;
|
|
|
|
basename.append( index_str );
|
2002-09-23 15:27:46 +00:00
|
|
|
|
2005-12-03 10:20:35 +00:00
|
|
|
SG_LOG( SG_TERRAIN, SG_INFO, " Trying " << basename.str() );
|
2002-09-23 15:27:46 +00:00
|
|
|
|
|
|
|
|
2003-08-08 20:11:22 +00:00
|
|
|
// Check for master .stg (scene terra gear) file
|
|
|
|
SGPath stg_name = basename;
|
|
|
|
stg_name.concat( ".stg" );
|
|
|
|
|
|
|
|
sg_gzifstream in( stg_name.str() );
|
2005-12-02 21:46:33 +00:00
|
|
|
if ( !in.is_open() )
|
|
|
|
continue;
|
2003-08-08 20:11:22 +00:00
|
|
|
|
2005-12-02 21:46:33 +00:00
|
|
|
while ( ! in.eof() ) {
|
|
|
|
string token;
|
|
|
|
in >> token;
|
2003-08-08 20:11:22 +00:00
|
|
|
|
2005-12-02 21:46:33 +00:00
|
|
|
if ( token[0] == '#' ) {
|
|
|
|
in >> ::skipeol;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
// Load only once (first found)
|
|
|
|
if ( token == "OBJECT_BASE" ) {
|
|
|
|
string name;
|
|
|
|
in >> name >> ::skipws;
|
2005-12-03 10:20:35 +00:00
|
|
|
SG_LOG( SG_TERRAIN, SG_INFO, " " << token << " " << name );
|
2005-12-02 21:46:33 +00:00
|
|
|
|
|
|
|
if (!found_tile_base) {
|
|
|
|
found_tile_base = true;
|
|
|
|
has_base = true;
|
|
|
|
|
|
|
|
object_base = tile_path;
|
|
|
|
object_base.append(name);
|
|
|
|
|
|
|
|
} else
|
2005-12-03 10:20:35 +00:00
|
|
|
SG_LOG(SG_TERRAIN, SG_INFO, " (skipped)");
|
2005-12-02 21:46:33 +00:00
|
|
|
|
|
|
|
// Load only if base is not in another file
|
|
|
|
} else if ( token == "OBJECT" ) {
|
|
|
|
if (!found_tile_base || has_base)
|
|
|
|
objects.push_back(new Object(OBJECT, token, tile_path, in));
|
|
|
|
else {
|
|
|
|
string name;
|
|
|
|
in >> name >> ::skipeol;
|
2005-12-03 10:20:35 +00:00
|
|
|
SG_LOG(SG_TERRAIN, SG_INFO, " " << token << " "
|
|
|
|
<< name << " (skipped)");
|
2004-12-08 14:45:47 +00:00
|
|
|
}
|
2003-08-08 20:11:22 +00:00
|
|
|
|
2005-12-02 21:46:33 +00:00
|
|
|
// Always OK to load
|
|
|
|
} else if ( token == "OBJECT_STATIC" ) {
|
|
|
|
objects.push_back(new Object(OBJECT_STATIC, token, tile_path, in));
|
2002-09-23 15:27:46 +00:00
|
|
|
|
2005-12-02 21:46:33 +00:00
|
|
|
} else if ( token == "OBJECT_SHARED" ) {
|
|
|
|
objects.push_back(new Object(OBJECT_SHARED, token, tile_path, in));
|
|
|
|
|
2006-04-14 14:50:11 +00:00
|
|
|
} else if ( token == "OBJECT_SIGN" ) {
|
|
|
|
objects.push_back(new Object(OBJECT_SIGN, token, tile_path, in));
|
2005-12-02 21:46:33 +00:00
|
|
|
|
|
|
|
} else if ( token == "OBJECT_RUNWAY_SIGN" ) {
|
|
|
|
objects.push_back(new Object(OBJECT_RUNWAY_SIGN, token, tile_path, in));
|
|
|
|
|
|
|
|
} else {
|
|
|
|
SG_LOG( SG_TERRAIN, SG_DEBUG,
|
|
|
|
"Unknown token '" << token << "' in " << stg_name.str() );
|
|
|
|
in >> ::skipws;
|
2002-09-23 15:27:46 +00:00
|
|
|
}
|
|
|
|
}
|
2003-08-08 20:11:22 +00:00
|
|
|
}
|
|
|
|
|
2005-12-02 21:46:33 +00:00
|
|
|
|
|
|
|
// obj_load() will generate ground lighting for us ...
|
2006-10-29 19:30:21 +00:00
|
|
|
osg::ref_ptr<osg::Vec3Array> light_pts = new osg::Vec3Array;
|
|
|
|
osg::Group* new_tile = new osg::Group;
|
2005-12-02 21:46:33 +00:00
|
|
|
|
|
|
|
|
|
|
|
if (found_tile_base) {
|
|
|
|
// load tile if found ...
|
2006-10-29 19:30:21 +00:00
|
|
|
osg::ref_ptr<osg::Group> geometry = new osg::Group;
|
|
|
|
if ( obj_load( object_base.str(), geometry.get(),
|
|
|
|
NULL, NULL, NULL, light_pts.get(), true ) ) {
|
|
|
|
new_tile -> addChild( geometry.get() );
|
2005-12-02 21:46:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
// ... or generate an ocean tile on the fly
|
2005-12-03 10:20:35 +00:00
|
|
|
SG_LOG(SG_TERRAIN, SG_INFO, " Generating ocean tile");
|
2006-10-29 19:30:21 +00:00
|
|
|
osg::ref_ptr<osg::Group> geometry = new osg::Group;
|
2002-03-11 22:50:23 +00:00
|
|
|
Point3D c;
|
|
|
|
double br;
|
2006-10-29 19:30:21 +00:00
|
|
|
if ( SGGenTile( path_list[0], tile_bucket, &c, &br,
|
|
|
|
globals->get_matlib(), geometry.get() ) ) {
|
2002-03-11 22:50:23 +00:00
|
|
|
center = c;
|
|
|
|
bounding_radius = br;
|
2006-10-29 19:30:21 +00:00
|
|
|
new_tile -> addChild( geometry.get() );
|
2002-03-11 22:50:23 +00:00
|
|
|
} else {
|
|
|
|
SG_LOG( SG_TERRAIN, SG_ALERT,
|
|
|
|
"Warning: failed to generate ocean tile!" );
|
|
|
|
}
|
2001-06-22 20:35:39 +00:00
|
|
|
}
|
|
|
|
|
2005-12-02 21:46:33 +00:00
|
|
|
|
|
|
|
// now that we have a valid center, process all the objects
|
2005-12-03 10:20:35 +00:00
|
|
|
for (unsigned int j = 0; j < objects.size(); j++) {
|
2005-12-02 21:46:33 +00:00
|
|
|
const Object *obj = objects[j];
|
|
|
|
|
|
|
|
if (obj->type == OBJECT) {
|
|
|
|
SGPath custom_path = obj->path;
|
|
|
|
custom_path.append( obj->name );
|
|
|
|
|
2006-10-29 19:30:21 +00:00
|
|
|
osg::ref_ptr<osg::Group> geometry = new osg::Group;
|
|
|
|
osg::ref_ptr<osg::Group> vasi_lights = new osg::Group;
|
|
|
|
osg::ref_ptr<osg::Group> rwy_lights = new osg::Group;
|
|
|
|
osg::ref_ptr<osg::Group> taxi_lights = new osg::Group;
|
2005-12-02 21:46:33 +00:00
|
|
|
|
|
|
|
if ( obj_load( custom_path.str(),
|
2006-10-29 19:30:21 +00:00
|
|
|
geometry.get(), vasi_lights.get(), rwy_lights.get(),
|
|
|
|
taxi_lights.get(), NULL, false ) ) {
|
|
|
|
|
|
|
|
if ( geometry -> getNumChildren() > 0 ) {
|
|
|
|
new_tile -> addChild( geometry.get() );
|
2005-12-02 21:46:33 +00:00
|
|
|
}
|
|
|
|
|
2006-10-29 19:30:21 +00:00
|
|
|
if ( vasi_lights -> getNumChildren() > 0 )
|
|
|
|
vasi_lights_transform -> addChild( vasi_lights.get() );
|
2005-12-02 21:46:33 +00:00
|
|
|
|
2006-10-29 19:30:21 +00:00
|
|
|
if ( rwy_lights -> getNumChildren() > 0 )
|
|
|
|
rwy_lights_transform -> addChild( rwy_lights.get() );
|
2005-12-02 21:46:33 +00:00
|
|
|
|
2006-10-29 19:30:21 +00:00
|
|
|
if ( taxi_lights -> getNumChildren() > 0 )
|
|
|
|
taxi_lights_transform -> addChild( taxi_lights.get() );
|
2005-12-02 21:46:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} else if (obj->type == OBJECT_SHARED || obj->type == OBJECT_STATIC) {
|
|
|
|
// object loading is deferred to main render thread,
|
|
|
|
// but lets figure out the paths right now.
|
|
|
|
SGPath custom_path;
|
|
|
|
if ( obj->type == OBJECT_STATIC ) {
|
|
|
|
custom_path = obj->path;
|
|
|
|
} else {
|
|
|
|
custom_path = globals->get_fg_root();
|
|
|
|
}
|
|
|
|
custom_path.append( obj->name );
|
|
|
|
|
2006-10-29 19:30:21 +00:00
|
|
|
osg::Matrix obj_pos;
|
|
|
|
WorldCoordinate( obj_pos, center, obj->lat, obj->lon, obj->elev, obj->hdg );
|
2005-12-02 21:46:33 +00:00
|
|
|
|
2006-10-29 19:30:21 +00:00
|
|
|
osg::MatrixTransform *obj_trans = new osg::MatrixTransform;
|
|
|
|
obj_trans->setMatrix( obj_pos );
|
2005-12-02 21:46:33 +00:00
|
|
|
|
|
|
|
// wire as much of the scene graph together as we can
|
2006-10-29 19:30:21 +00:00
|
|
|
new_tile->addChild( obj_trans );
|
2005-12-02 21:46:33 +00:00
|
|
|
pending_models++;
|
|
|
|
|
|
|
|
// push an entry onto the model load queue
|
|
|
|
FGDeferredModel *dm
|
|
|
|
= new FGDeferredModel( custom_path.str(),
|
|
|
|
obj->path.str(),
|
|
|
|
tile_bucket,
|
2006-03-09 09:04:03 +00:00
|
|
|
this, obj_trans,
|
|
|
|
obj->type == OBJECT_SHARED );
|
2005-12-02 21:46:33 +00:00
|
|
|
FGTileMgr::model_ready( dm );
|
|
|
|
|
|
|
|
|
2006-04-14 14:50:11 +00:00
|
|
|
} else if (obj->type == OBJECT_SIGN || obj->type == OBJECT_RUNWAY_SIGN) {
|
2005-12-02 21:46:33 +00:00
|
|
|
// load the object itself
|
|
|
|
SGPath custom_path = obj->path;
|
|
|
|
custom_path.append( obj->name );
|
|
|
|
|
2006-10-29 19:30:21 +00:00
|
|
|
osg::Matrix obj_pos;
|
|
|
|
WorldCoordinate( obj_pos, center, obj->lat, obj->lon, obj->elev, obj->hdg );
|
2005-12-02 21:46:33 +00:00
|
|
|
|
2006-10-29 19:30:21 +00:00
|
|
|
osg::MatrixTransform *obj_trans = new osg::MatrixTransform;
|
|
|
|
obj_trans->setMatrix( obj_pos );
|
2005-12-02 21:46:33 +00:00
|
|
|
|
2006-10-29 19:30:21 +00:00
|
|
|
osg::Node *custom_obj = 0;
|
|
|
|
if (obj->type == OBJECT_SIGN)
|
|
|
|
custom_obj = SGMakeSign(globals->get_matlib(), custom_path.str(), obj->name);
|
|
|
|
else
|
|
|
|
custom_obj = SGMakeRunwaySign(globals->get_matlib(), custom_path.str(), obj->name);
|
2005-12-02 21:46:33 +00:00
|
|
|
|
|
|
|
// wire the pieces together
|
|
|
|
if ( custom_obj != NULL ) {
|
2006-10-29 19:30:21 +00:00
|
|
|
obj_trans -> addChild( custom_obj );
|
2005-12-02 21:46:33 +00:00
|
|
|
}
|
2006-10-29 19:30:21 +00:00
|
|
|
new_tile->addChild( obj_trans );
|
2005-12-02 21:46:33 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
delete obj;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-06-22 20:35:39 +00:00
|
|
|
if ( new_tile != NULL ) {
|
2006-10-29 19:30:21 +00:00
|
|
|
terra_range->addChild( new_tile );
|
2001-03-29 01:42:31 +00:00
|
|
|
}
|
|
|
|
|
2006-10-29 19:30:21 +00:00
|
|
|
terra_transform->addChild( terra_range.get() );
|
2001-03-29 01:42:31 +00:00
|
|
|
|
|
|
|
// calculate initial tile offset
|
2006-10-29 19:30:21 +00:00
|
|
|
SGVec3d sgdTrans(center.x(), center.y(), center.z());
|
Mathias:
I have done a patch to eliminate the jitter of 3D-objects near the viewpoint
(for example 3D cockpit objects).
The problem is the roundoff accuracy of the float values used in the
scenegraph together with the transforms of the eyepoint relative to the
scenery center.
The solution will be to move the scenery center near the view point.
This way floats relative accuracy is enough to show a stable picture.
To get that right I have introduced a transform node for the scenegraph which
is responsible for that shift and uses double values as long as possible.
The scenery subsystem now has a list of all those transforms required to place
objects in the world and will tell all those transforms that the scenery
center has changed when the set_scenery_center() of the scenery subsystem is
called.
The problem was not solvable by SGModelPlacement and SGLocation, since not all
objects, especially the scenery, are placed using these classes.
The first approach was to have the scenery center exactly at the eyepoint.
This works well for the cockpit.
But then the ground jitters a bit below the aircraft. With our default views
you can't see that, but that F-18 has a camera view below the left engine
intake with the nose gear and the ground in its field of view, here I could
see that.
Having the scenery center constant will still have this roundoff problems, but
like it is now too, the roundoff error here is exactly the same in each
frame, so you will not notice any jitter.
The real solution is now to keep the scenery center constant as long as it is
in a ball of 30m radius around the view point. If the scenery center is
outside this ball, just put it at the view point.
As a sideeffect of now beeing able to switch the scenery center in the whole
scenegraph with one function call, I was able to remove a one half of a
problem when switching views, where the scenery center was far off for one or
two frames past switching from one view to the next. Also included is a fix
to the other half of this problem, where the view position was not yet copied
into a view when it is switched (at least under glut). This was responsible
for the 'Error: ...' messages of the cloud subsystem when views were
switched.
2005-04-29 14:38:24 +00:00
|
|
|
terra_transform->setTransform( sgdTrans );
|
|
|
|
|
2002-03-01 18:08:30 +00:00
|
|
|
// Add ground lights to scene graph if any exist
|
|
|
|
gnd_lights_transform = NULL;
|
|
|
|
gnd_lights_range = NULL;
|
2006-10-29 19:30:21 +00:00
|
|
|
if ( light_pts->size() ) {
|
2002-09-23 15:27:46 +00:00
|
|
|
SG_LOG( SG_TERRAIN, SG_DEBUG, "generating lights" );
|
2006-10-29 19:30:21 +00:00
|
|
|
gnd_lights_transform = new SGPlacementTransform;
|
|
|
|
gnd_lights_range = new osg::LOD;
|
|
|
|
gnd_lights_brightness = new osg::Switch;
|
|
|
|
osg::Node *lights;
|
2001-03-29 01:42:31 +00:00
|
|
|
|
2006-10-29 19:30:21 +00:00
|
|
|
lights = gen_lights( globals->get_matlib(), light_pts.get(), 4, 0.7 );
|
|
|
|
gnd_lights_brightness->addChild( lights );
|
2001-03-29 01:42:31 +00:00
|
|
|
|
2006-10-29 19:30:21 +00:00
|
|
|
lights = gen_lights( globals->get_matlib(), light_pts.get(), 2, 0.85 );
|
|
|
|
gnd_lights_brightness->addChild( lights );
|
2001-03-29 01:42:31 +00:00
|
|
|
|
2006-10-29 19:30:21 +00:00
|
|
|
lights = gen_lights( globals->get_matlib(), light_pts.get(), 1, 1.0 );
|
|
|
|
gnd_lights_brightness->addChild( lights );
|
2001-03-29 01:42:31 +00:00
|
|
|
|
2006-10-29 19:30:21 +00:00
|
|
|
gnd_lights_range->addChild( gnd_lights_brightness.get() );
|
|
|
|
gnd_lights_transform->addChild( gnd_lights_range.get() );
|
Mathias:
I have done a patch to eliminate the jitter of 3D-objects near the viewpoint
(for example 3D cockpit objects).
The problem is the roundoff accuracy of the float values used in the
scenegraph together with the transforms of the eyepoint relative to the
scenery center.
The solution will be to move the scenery center near the view point.
This way floats relative accuracy is enough to show a stable picture.
To get that right I have introduced a transform node for the scenegraph which
is responsible for that shift and uses double values as long as possible.
The scenery subsystem now has a list of all those transforms required to place
objects in the world and will tell all those transforms that the scenery
center has changed when the set_scenery_center() of the scenery subsystem is
called.
The problem was not solvable by SGModelPlacement and SGLocation, since not all
objects, especially the scenery, are placed using these classes.
The first approach was to have the scenery center exactly at the eyepoint.
This works well for the cockpit.
But then the ground jitters a bit below the aircraft. With our default views
you can't see that, but that F-18 has a camera view below the left engine
intake with the nose gear and the ground in its field of view, here I could
see that.
Having the scenery center constant will still have this roundoff problems, but
like it is now too, the roundoff error here is exactly the same in each
frame, so you will not notice any jitter.
The real solution is now to keep the scenery center constant as long as it is
in a ball of 30m radius around the view point. If the scenery center is
outside this ball, just put it at the view point.
As a sideeffect of now beeing able to switch the scenery center in the whole
scenegraph with one function call, I was able to remove a one half of a
problem when switching views, where the scenery center was far off for one or
two frames past switching from one view to the next. Also included is a fix
to the other half of this problem, where the view position was not yet copied
into a view when it is switched (at least under glut). This was responsible
for the 'Error: ...' messages of the cloud subsystem when views were
switched.
2005-04-29 14:38:24 +00:00
|
|
|
gnd_lights_transform->setTransform( sgdTrans );
|
2002-03-04 02:36:06 +00:00
|
|
|
}
|
|
|
|
|
2003-09-24 19:59:25 +00:00
|
|
|
// Update vasi lights transform
|
2006-10-29 19:30:21 +00:00
|
|
|
if ( vasi_lights_transform->getNumChildren() > 0 ) {
|
Mathias:
I have done a patch to eliminate the jitter of 3D-objects near the viewpoint
(for example 3D cockpit objects).
The problem is the roundoff accuracy of the float values used in the
scenegraph together with the transforms of the eyepoint relative to the
scenery center.
The solution will be to move the scenery center near the view point.
This way floats relative accuracy is enough to show a stable picture.
To get that right I have introduced a transform node for the scenegraph which
is responsible for that shift and uses double values as long as possible.
The scenery subsystem now has a list of all those transforms required to place
objects in the world and will tell all those transforms that the scenery
center has changed when the set_scenery_center() of the scenery subsystem is
called.
The problem was not solvable by SGModelPlacement and SGLocation, since not all
objects, especially the scenery, are placed using these classes.
The first approach was to have the scenery center exactly at the eyepoint.
This works well for the cockpit.
But then the ground jitters a bit below the aircraft. With our default views
you can't see that, but that F-18 has a camera view below the left engine
intake with the nose gear and the ground in its field of view, here I could
see that.
Having the scenery center constant will still have this roundoff problems, but
like it is now too, the roundoff error here is exactly the same in each
frame, so you will not notice any jitter.
The real solution is now to keep the scenery center constant as long as it is
in a ball of 30m radius around the view point. If the scenery center is
outside this ball, just put it at the view point.
As a sideeffect of now beeing able to switch the scenery center in the whole
scenegraph with one function call, I was able to remove a one half of a
problem when switching views, where the scenery center was far off for one or
two frames past switching from one view to the next. Also included is a fix
to the other half of this problem, where the view position was not yet copied
into a view when it is switched (at least under glut). This was responsible
for the 'Error: ...' messages of the cloud subsystem when views were
switched.
2005-04-29 14:38:24 +00:00
|
|
|
vasi_lights_transform->setTransform( sgdTrans );
|
2003-09-24 19:59:25 +00:00
|
|
|
}
|
|
|
|
|
2003-05-14 20:48:31 +00:00
|
|
|
// Update runway lights transform
|
2006-10-29 19:30:21 +00:00
|
|
|
if ( rwy_lights_transform->getNumChildren() > 0 ) {
|
Mathias:
I have done a patch to eliminate the jitter of 3D-objects near the viewpoint
(for example 3D cockpit objects).
The problem is the roundoff accuracy of the float values used in the
scenegraph together with the transforms of the eyepoint relative to the
scenery center.
The solution will be to move the scenery center near the view point.
This way floats relative accuracy is enough to show a stable picture.
To get that right I have introduced a transform node for the scenegraph which
is responsible for that shift and uses double values as long as possible.
The scenery subsystem now has a list of all those transforms required to place
objects in the world and will tell all those transforms that the scenery
center has changed when the set_scenery_center() of the scenery subsystem is
called.
The problem was not solvable by SGModelPlacement and SGLocation, since not all
objects, especially the scenery, are placed using these classes.
The first approach was to have the scenery center exactly at the eyepoint.
This works well for the cockpit.
But then the ground jitters a bit below the aircraft. With our default views
you can't see that, but that F-18 has a camera view below the left engine
intake with the nose gear and the ground in its field of view, here I could
see that.
Having the scenery center constant will still have this roundoff problems, but
like it is now too, the roundoff error here is exactly the same in each
frame, so you will not notice any jitter.
The real solution is now to keep the scenery center constant as long as it is
in a ball of 30m radius around the view point. If the scenery center is
outside this ball, just put it at the view point.
As a sideeffect of now beeing able to switch the scenery center in the whole
scenegraph with one function call, I was able to remove a one half of a
problem when switching views, where the scenery center was far off for one or
two frames past switching from one view to the next. Also included is a fix
to the other half of this problem, where the view position was not yet copied
into a view when it is switched (at least under glut). This was responsible
for the 'Error: ...' messages of the cloud subsystem when views were
switched.
2005-04-29 14:38:24 +00:00
|
|
|
rwy_lights_transform->setTransform( sgdTrans );
|
2001-03-29 01:42:31 +00:00
|
|
|
}
|
2001-09-19 22:30:41 +00:00
|
|
|
|
2003-05-14 20:48:31 +00:00
|
|
|
// Update taxi lights transform
|
2006-10-29 19:30:21 +00:00
|
|
|
if ( taxi_lights_transform->getNumChildren() > 0 ) {
|
Mathias:
I have done a patch to eliminate the jitter of 3D-objects near the viewpoint
(for example 3D cockpit objects).
The problem is the roundoff accuracy of the float values used in the
scenegraph together with the transforms of the eyepoint relative to the
scenery center.
The solution will be to move the scenery center near the view point.
This way floats relative accuracy is enough to show a stable picture.
To get that right I have introduced a transform node for the scenegraph which
is responsible for that shift and uses double values as long as possible.
The scenery subsystem now has a list of all those transforms required to place
objects in the world and will tell all those transforms that the scenery
center has changed when the set_scenery_center() of the scenery subsystem is
called.
The problem was not solvable by SGModelPlacement and SGLocation, since not all
objects, especially the scenery, are placed using these classes.
The first approach was to have the scenery center exactly at the eyepoint.
This works well for the cockpit.
But then the ground jitters a bit below the aircraft. With our default views
you can't see that, but that F-18 has a camera view below the left engine
intake with the nose gear and the ground in its field of view, here I could
see that.
Having the scenery center constant will still have this roundoff problems, but
like it is now too, the roundoff error here is exactly the same in each
frame, so you will not notice any jitter.
The real solution is now to keep the scenery center constant as long as it is
in a ball of 30m radius around the view point. If the scenery center is
outside this ball, just put it at the view point.
As a sideeffect of now beeing able to switch the scenery center in the whole
scenegraph with one function call, I was able to remove a one half of a
problem when switching views, where the scenery center was far off for one or
two frames past switching from one view to the next. Also included is a fix
to the other half of this problem, where the view position was not yet copied
into a view when it is switched (at least under glut). This was responsible
for the 'Error: ...' messages of the cloud subsystem when views were
switched.
2005-04-29 14:38:24 +00:00
|
|
|
taxi_lights_transform->setTransform( sgdTrans );
|
2002-11-01 21:56:48 +00:00
|
|
|
}
|
2004-10-10 17:41:11 +00:00
|
|
|
}
|
2001-05-16 06:00:02 +00:00
|
|
|
|
2001-04-16 20:03:52 +00:00
|
|
|
void
|
2006-10-29 19:30:21 +00:00
|
|
|
FGTileEntry::add_ssg_nodes( osg::Group *terrain_branch,
|
|
|
|
osg::Group *gnd_lights_branch,
|
|
|
|
osg::Group *vasi_lights_branch,
|
|
|
|
osg::Group *rwy_lights_branch,
|
|
|
|
osg::Group *taxi_lights_branch )
|
2001-04-16 20:03:52 +00:00
|
|
|
{
|
2001-05-19 16:59:43 +00:00
|
|
|
// bump up the ref count so we can remove this later without
|
|
|
|
// having ssg try to free the memory.
|
2006-10-29 19:30:21 +00:00
|
|
|
terrain_branch->addChild( terra_transform.get() );
|
2001-05-19 16:59:43 +00:00
|
|
|
|
2001-05-30 18:21:03 +00:00
|
|
|
SG_LOG( SG_TERRAIN, SG_DEBUG,
|
|
|
|
"connected a tile into scene graph. terra_transform = "
|
2006-10-29 19:30:21 +00:00
|
|
|
<< terra_transform.get() );
|
2001-05-30 18:21:03 +00:00
|
|
|
SG_LOG( SG_TERRAIN, SG_DEBUG, "num parents now = "
|
|
|
|
<< terra_transform->getNumParents() );
|
|
|
|
|
2006-10-29 19:30:21 +00:00
|
|
|
if ( gnd_lights_transform.get() != NULL ) {
|
2002-09-23 15:27:46 +00:00
|
|
|
// bump up the ref count so we can remove this later without
|
|
|
|
// having ssg try to free the memory.
|
2006-10-29 19:30:21 +00:00
|
|
|
gnd_lights_branch->addChild( gnd_lights_transform.get() );
|
2002-03-03 23:20:55 +00:00
|
|
|
}
|
|
|
|
|
2006-10-29 19:30:21 +00:00
|
|
|
if ( vasi_lights_transform.get() != NULL ) {
|
2003-09-24 19:59:25 +00:00
|
|
|
// bump up the ref count so we can remove this later without
|
|
|
|
// having ssg try to free the memory.
|
2006-10-29 19:30:21 +00:00
|
|
|
vasi_lights_selector->addChild( vasi_lights_transform.get() );
|
|
|
|
vasi_lights_branch->addChild( vasi_lights_selector.get() );
|
2003-09-24 19:59:25 +00:00
|
|
|
}
|
|
|
|
|
2006-10-29 19:30:21 +00:00
|
|
|
if ( rwy_lights_transform.get() != NULL ) {
|
2002-09-23 15:27:46 +00:00
|
|
|
// bump up the ref count so we can remove this later without
|
|
|
|
// having ssg try to free the memory.
|
2006-10-29 19:30:21 +00:00
|
|
|
rwy_lights_selector->addChild( rwy_lights_transform.get() );
|
|
|
|
rwy_lights_branch->addChild( rwy_lights_selector.get() );
|
2001-05-19 16:59:43 +00:00
|
|
|
}
|
2001-04-06 18:30:07 +00:00
|
|
|
|
2006-10-29 19:30:21 +00:00
|
|
|
if ( taxi_lights_transform.get() != NULL ) {
|
2002-11-01 21:56:48 +00:00
|
|
|
// bump up the ref count so we can remove this later without
|
|
|
|
// having ssg try to free the memory.
|
2006-10-29 19:30:21 +00:00
|
|
|
taxi_lights_selector->addChild( taxi_lights_transform.get() );
|
|
|
|
taxi_lights_branch->addChild( taxi_lights_selector.get() );
|
2002-11-01 21:56:48 +00:00
|
|
|
}
|
|
|
|
|
2001-04-06 18:30:07 +00:00
|
|
|
loaded = true;
|
2001-03-29 01:42:31 +00:00
|
|
|
}
|
2001-05-19 16:59:43 +00:00
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
FGTileEntry::disconnect_ssg_nodes()
|
|
|
|
{
|
2002-08-07 02:53:01 +00:00
|
|
|
SG_LOG( SG_TERRAIN, SG_DEBUG, "disconnecting ssg nodes" );
|
2001-05-19 16:59:43 +00:00
|
|
|
|
2001-05-30 18:21:03 +00:00
|
|
|
if ( ! loaded ) {
|
2002-08-07 02:53:01 +00:00
|
|
|
SG_LOG( SG_TERRAIN, SG_DEBUG, "removing a not-fully loaded tile!" );
|
2001-05-30 18:21:03 +00:00
|
|
|
} else {
|
2006-10-29 19:30:21 +00:00
|
|
|
SG_LOG( SG_TERRAIN, SG_DEBUG, "removing a fully loaded tile! terra_transform = " << terra_transform.get() );
|
2001-05-30 18:21:03 +00:00
|
|
|
}
|
|
|
|
|
2001-05-19 16:59:43 +00:00
|
|
|
// find the terrain branch parent
|
|
|
|
int pcount = terra_transform->getNumParents();
|
|
|
|
if ( pcount > 0 ) {
|
2002-09-23 15:27:46 +00:00
|
|
|
// find the first parent (should only be one)
|
2006-10-29 19:30:21 +00:00
|
|
|
osg::Group *parent = terra_transform->getParent( 0 ) ;
|
2002-09-23 15:27:46 +00:00
|
|
|
if( parent ) {
|
|
|
|
// disconnect the tile (we previously ref()'d it so it
|
|
|
|
// won't get freed now)
|
2006-10-29 19:30:21 +00:00
|
|
|
parent->removeChild( terra_transform.get() );
|
2002-09-23 15:27:46 +00:00
|
|
|
} else {
|
|
|
|
SG_LOG( SG_TERRAIN, SG_ALERT,
|
|
|
|
"parent pointer is NULL! Dying" );
|
|
|
|
exit(-1);
|
|
|
|
}
|
2001-05-19 16:59:43 +00:00
|
|
|
} else {
|
2002-09-23 15:27:46 +00:00
|
|
|
SG_LOG( SG_TERRAIN, SG_ALERT,
|
|
|
|
"Parent count is zero for an ssg tile! Dying" );
|
|
|
|
exit(-1);
|
2001-05-19 16:59:43 +00:00
|
|
|
}
|
|
|
|
|
2002-03-04 02:36:06 +00:00
|
|
|
// find the ground lighting branch
|
2006-10-29 19:30:21 +00:00
|
|
|
if ( gnd_lights_transform.get() ) {
|
2002-09-23 15:27:46 +00:00
|
|
|
pcount = gnd_lights_transform->getNumParents();
|
|
|
|
if ( pcount > 0 ) {
|
|
|
|
// find the first parent (should only be one)
|
2006-10-29 19:30:21 +00:00
|
|
|
osg::Group *parent = gnd_lights_transform->getParent( 0 ) ;
|
2002-09-23 15:27:46 +00:00
|
|
|
if( parent ) {
|
|
|
|
// disconnect the light branch (we previously ref()'d
|
|
|
|
// it so it won't get freed now)
|
2006-10-29 19:30:21 +00:00
|
|
|
parent->removeChild( gnd_lights_transform.get() );
|
2002-09-23 15:27:46 +00:00
|
|
|
} 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);
|
|
|
|
}
|
2001-05-19 16:59:43 +00:00
|
|
|
}
|
2001-09-19 22:30:41 +00:00
|
|
|
|
2003-09-24 19:59:25 +00:00
|
|
|
// find the vasi lighting branch
|
2006-10-29 19:30:21 +00:00
|
|
|
if ( vasi_lights_transform.get() ) {
|
2003-09-24 19:59:25 +00:00
|
|
|
pcount = vasi_lights_transform->getNumParents();
|
|
|
|
if ( pcount > 0 ) {
|
|
|
|
// find the first parent (should only be one)
|
2006-10-29 19:30:21 +00:00
|
|
|
osg::Group *parent = vasi_lights_transform->getParent( 0 ) ;
|
2003-09-24 19:59:25 +00:00
|
|
|
if( parent ) {
|
|
|
|
// disconnect the light branch (we previously ref()'d
|
|
|
|
// it so it won't get freed now)
|
2006-10-29 19:30:21 +00:00
|
|
|
parent->removeChild( vasi_lights_transform.get() );
|
2003-09-24 19:59:25 +00:00
|
|
|
} 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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-03-04 02:36:06 +00:00
|
|
|
// find the runway lighting branch
|
2006-10-29 19:30:21 +00:00
|
|
|
if ( rwy_lights_transform.get() ) {
|
2002-09-23 15:27:46 +00:00
|
|
|
pcount = rwy_lights_transform->getNumParents();
|
|
|
|
if ( pcount > 0 ) {
|
|
|
|
// find the first parent (should only be one)
|
2006-10-29 19:30:21 +00:00
|
|
|
osg::Group *parent = rwy_lights_transform->getParent( 0 ) ;
|
2002-09-23 15:27:46 +00:00
|
|
|
if( parent ) {
|
|
|
|
// disconnect the light branch (we previously ref()'d
|
|
|
|
// it so it won't get freed now)
|
2006-10-29 19:30:21 +00:00
|
|
|
parent->removeChild( rwy_lights_transform.get() );
|
2002-09-23 15:27:46 +00:00
|
|
|
} else {
|
|
|
|
SG_LOG( SG_TERRAIN, SG_ALERT,
|
|
|
|
"parent pointer is NULL! Dying" );
|
|
|
|
exit(-1);
|
|
|
|
}
|
2002-11-01 21:56:48 +00:00
|
|
|
} else {
|
|
|
|
SG_LOG( SG_TERRAIN, SG_ALERT,
|
|
|
|
"Parent count is zero for an ssg light tile! Dying" );
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// find the taxi lighting branch
|
2006-10-29 19:30:21 +00:00
|
|
|
if ( taxi_lights_transform.get() ) {
|
2002-11-01 21:56:48 +00:00
|
|
|
pcount = taxi_lights_transform->getNumParents();
|
|
|
|
if ( pcount > 0 ) {
|
|
|
|
// find the first parent (should only be one)
|
2006-10-29 19:30:21 +00:00
|
|
|
osg::Group *parent = taxi_lights_transform->getParent( 0 ) ;
|
2002-11-01 21:56:48 +00:00
|
|
|
if( parent ) {
|
|
|
|
// disconnect the light branch (we previously ref()'d
|
|
|
|
// it so it won't get freed now)
|
2006-10-29 19:30:21 +00:00
|
|
|
parent->removeChild( taxi_lights_transform.get() );
|
2002-11-01 21:56:48 +00:00
|
|
|
} else {
|
|
|
|
SG_LOG( SG_TERRAIN, SG_ALERT,
|
|
|
|
"parent pointer is NULL! Dying" );
|
|
|
|
exit(-1);
|
|
|
|
}
|
2002-09-23 15:27:46 +00:00
|
|
|
} else {
|
|
|
|
SG_LOG( SG_TERRAIN, SG_ALERT,
|
|
|
|
"Parent count is zero for an ssg light tile! Dying" );
|
|
|
|
exit(-1);
|
|
|
|
}
|
2002-03-04 02:36:06 +00:00
|
|
|
}
|
2001-05-19 16:59:43 +00:00
|
|
|
}
|