From 834eab9457ee5409a9279ec58d46632ae071c543 Mon Sep 17 00:00:00 2001 From: frohlich Date: Tue, 8 May 2007 06:11:15 +0000 Subject: [PATCH] Modified Files: simgear/bucket/newbucket.hxx simgear/scene/material/mat.cxx simgear/scene/material/matlib.cxx simgear/scene/material/matlib.hxx simgear/scene/model/location.cxx simgear/scene/tgdb/apt_signs.cxx simgear/scene/tgdb/leaf.cxx simgear/scene/tgdb/leaf.hxx simgear/scene/tgdb/obj.cxx simgear/scene/tgdb/obj.hxx simgear/scene/util/SGUpdateVisitor.hxx: Reorganize scenegraph to simplify top level structure. --- simgear/bucket/newbucket.hxx | 20 +- simgear/scene/material/mat.cxx | 1 + simgear/scene/material/matlib.cxx | 10 +- simgear/scene/material/matlib.hxx | 2 +- simgear/scene/model/location.cxx | 1 - simgear/scene/tgdb/apt_signs.cxx | 63 +--- simgear/scene/tgdb/leaf.cxx | 75 ++--- simgear/scene/tgdb/leaf.hxx | 5 +- simgear/scene/tgdb/obj.cxx | 416 +++++++++++++++++++------ simgear/scene/tgdb/obj.hxx | 19 +- simgear/scene/util/SGUpdateVisitor.hxx | 63 +++- 11 files changed, 439 insertions(+), 236 deletions(-) diff --git a/simgear/bucket/newbucket.hxx b/simgear/bucket/newbucket.hxx index 2ba7de55..955ce8b1 100644 --- a/simgear/bucket/newbucket.hxx +++ b/simgear/bucket/newbucket.hxx @@ -31,6 +31,7 @@ #include #include +#include #ifdef SG_HAVE_STD_INCLUDES # include @@ -252,7 +253,24 @@ public: * @return the height of the tile in meters. */ double get_height_m() const; - + + /** + * @return the center of the bucket in geodetic coordinates. + */ + SGGeod get_center() const + { return SGGeod::fromDeg(get_center_lon(), get_center_lat()); } + + /** + * @return the center of the bucket in geodetic coordinates. + */ + SGGeod get_corner(unsigned num) const + { + double lonFac = ((num + 1) & 2) ? 0.5 : -0.5; + double latFac = ((num ) & 2) ? 0.5 : -0.5; + return SGGeod::fromDeg(get_center_lon() + lonFac*get_width(), + get_center_lat() + latFac*get_height()); + } + // Informational methods. /** diff --git a/simgear/scene/material/mat.cxx b/simgear/scene/material/mat.cxx index 8c93886a..d9f5c82f 100644 --- a/simgear/scene/material/mat.cxx +++ b/simgear/scene/material/mat.cxx @@ -266,6 +266,7 @@ SGMaterial::build_state( bool defer_tex_load ) for (unsigned int i = 0; i < _status.size(); i++) { osg::StateSet *stateSet = new osg::StateSet; + stateSet->setUserData(new SGMaterialUserData(this)); // Set up the textured state osg::ShadeModel* shadeModel = new osg::ShadeModel; diff --git a/simgear/scene/material/matlib.cxx b/simgear/scene/material/matlib.cxx index 7a8ea544..bd8a7725 100644 --- a/simgear/scene/material/matlib.cxx +++ b/simgear/scene/material/matlib.cxx @@ -216,7 +216,7 @@ bool SGMaterialLib::load( const string &fg_root, const string& mpath, const char osg::ref_ptr lightStateSet = new osg::StateSet; { - lightStateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); + lightStateSet->setRenderBinDetails(9, "DepthSortedBin"); lightStateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF); // lightStateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON); @@ -552,13 +552,13 @@ void SGMaterialLib::load_next_deferred() { } } -// Return the material from that given leaf -const SGMaterial* SGMaterialLib::findMaterial(const osg::Node* leaf) const +const SGMaterial* +SGMaterialLib::findMaterial(const osg::StateSet* stateSet) const { - if (!leaf) + if (!stateSet) return 0; - const osg::Referenced* base = leaf->getUserData(); + const osg::Referenced* base = stateSet->getUserData(); if (!base) return 0; diff --git a/simgear/scene/material/matlib.hxx b/simgear/scene/material/matlib.hxx index 14a0a8d1..52f414e0 100644 --- a/simgear/scene/material/matlib.hxx +++ b/simgear/scene/material/matlib.hxx @@ -86,7 +86,7 @@ public: material_map_iterator end() { return matlib.end(); } const_material_map_iterator end() const { return matlib.end(); } - const SGMaterial* findMaterial(const osg::Node* leaf) const; + const SGMaterial* findMaterial(const osg::StateSet* stateSet) const; // Destructor ~SGMaterialLib ( void ); diff --git a/simgear/scene/model/location.cxx b/simgear/scene/model/location.cxx index cf9f0192..ec572c8c 100644 --- a/simgear/scene/model/location.cxx +++ b/simgear/scene/model/location.cxx @@ -33,7 +33,6 @@ #include #include #include -#include #include "location.hxx" diff --git a/simgear/scene/tgdb/apt_signs.cxx b/simgear/scene/tgdb/apt_signs.cxx index 543882c7..97fef252 100644 --- a/simgear/scene/tgdb/apt_signs.cxx +++ b/simgear/scene/tgdb/apt_signs.cxx @@ -33,7 +33,6 @@ #include #include -#include #include #include @@ -355,63 +354,27 @@ SGMakeSign(SGMaterialLib *matlib, const string& path, const string& content) return object; } - - - - osg::Node* SGMakeRunwaySign(SGMaterialLib *matlib, const string& path, const string& name) { // for demo purposes we assume each element (letter) is 1x1 meter. // Sign is placed 0.25 meters above the ground - osg::Group *object = new osg::Group; - object->setName(name); - - double width = name.length() / 3.0; - - string material = name; - - point_list nodes; - point_list normals; - point_list texcoords; - int_list vertex_index; - int_list normal_index; - int_list tex_index; - - nodes.push_back( Point3D( -width, 0, 0.25 ) ); - nodes.push_back( Point3D( width + 1, 0, 0.25 ) ); - nodes.push_back( Point3D( -width, 0, 1.25 ) ); - nodes.push_back( Point3D( width + 1, 0, 1.25 ) ); + float width = name.length() / 3.0; - normals.push_back( Point3D( 0, -1, 0 ) ); + osg::Vec3 corner(-width, 0, 0.25f); + osg::Vec3 widthVec(2*width + 1, 0, 0); + osg::Vec3 heightVec(0, 0, 1); + osg::Geometry* geometry; + geometry = osg::createTexturedQuadGeometry(corner, widthVec, heightVec); - texcoords.push_back( Point3D( 0, 0, 0 ) ); - texcoords.push_back( Point3D( 1, 0, 0 ) ); - texcoords.push_back( Point3D( 0, 1, 0 ) ); - texcoords.push_back( Point3D( 1, 1, 0 ) ); - - vertex_index.push_back( 0 ); - vertex_index.push_back( 1 ); - vertex_index.push_back( 2 ); - vertex_index.push_back( 3 ); - - normal_index.push_back( 0 ); - normal_index.push_back( 0 ); - normal_index.push_back( 0 ); - normal_index.push_back( 0 ); - - tex_index.push_back( 0 ); - tex_index.push_back( 1 ); - tex_index.push_back( 2 ); - tex_index.push_back( 3 ); - - osg::Node* leaf = SGMakeLeaf( path, GL_TRIANGLE_STRIP, matlib, material, - nodes, normals, texcoords, - vertex_index, normal_index, tex_index, - false, NULL ); + SGMaterial *mat = matlib->find(name); + if (mat) + geometry->setStateSet(mat->get_state()); - object->addChild(leaf); + osg::Geode* geode = new osg::Geode; + geode->setName(name); + geode->addDrawable(geometry); - return object; + return geode; } diff --git a/simgear/scene/tgdb/leaf.cxx b/simgear/scene/tgdb/leaf.cxx index 1d3e6d94..8dde0fb1 100644 --- a/simgear/scene/tgdb/leaf.cxx +++ b/simgear/scene/tgdb/leaf.cxx @@ -54,22 +54,6 @@ typedef vector < int > int_list; typedef int_list::iterator int_list_iterator; typedef int_list::const_iterator int_point_list_iterator; - -static inline -osg::Vec3 random_pt_inside_tri(const osg::Vec3& n1, const osg::Vec3& n2, - const osg::Vec3& n3 ) -{ - double a = sg_random(); - double b = sg_random(); - if ( a + b > 1.0 ) { - a = 1.0 - a; - b = 1.0 - b; - } - double c = 1 - a - b; - - return n1*a + n2*b + n3*c; -} - /// class to implement the TrinagleFunctor class struct SGRandomSurfacePointsFill { osg::Vec3Array* lights; @@ -97,6 +81,20 @@ struct SGRandomSurfacePointsFill { } } } + + osg::Vec3 random_pt_inside_tri(const osg::Vec3& n1, const osg::Vec3& n2, + const osg::Vec3& n3) + { + double a = sg_random(); + double b = sg_random(); + if ( a + b > 1.0 ) { + a = 1 - a; + b = 1 - b; + } + double c = 1 - a - b; + + return n1*a + n2*b + n3*c; + } }; static void SGGenRandomSurfacePoints( osg::Geometry *leaf, double factor, @@ -109,13 +107,13 @@ static void SGGenRandomSurfacePoints( osg::Geometry *leaf, double factor, } + //////////////////////////////////////////////////////////////////////// // Scenery loaders. //////////////////////////////////////////////////////////////////////// -osg::Node* SGMakeLeaf( const string& path, - const GLenum ty, - SGMaterialLib *matlib, const string& material, +osg::Drawable* SGMakeLeaf( const string& path, + const GLenum ty, SGMaterial *mat, const point_list& nodes, const point_list& normals, const point_list& texcoords, const int_list& node_index, @@ -127,31 +125,6 @@ osg::Node* SGMakeLeaf( const string& path, osg::StateSet *state = 0; float coverage = -1; - SGMaterial *mat = matlib->find( material ); - if ( mat == NULL ) { - // see if this is an on the fly texture - string file = path; - string::size_type pos = file.rfind( "/" ); - file = file.substr( 0, pos ); - // cout << "current file = " << file << endl; - file += "/"; - file += material; - // cout << "current file = " << file << endl; - if ( ! matlib->add_item( file ) ) { - SG_LOG( SG_TERRAIN, SG_ALERT, - "Ack! unknown usemtl name = " << material - << " in " << path ); - } else { - // locate our newly created material - mat = matlib->find( material ); - if ( mat == NULL ) { - SG_LOG( SG_TERRAIN, SG_ALERT, - "Ack! bad on the fly material create = " - << material << " in " << path ); - } - } - } - if ( mat != NULL ) { // set the texture width and height values for this // material @@ -159,10 +132,6 @@ osg::Node* SGMakeLeaf( const string& path, tex_height = mat->get_ysize(); state = mat->get_state(); coverage = mat->get_light_coverage(); - // cout << "(w) = " << tex_width << " (h) = " - // << tex_width << endl; - } else { - coverage = -1; } int i; @@ -240,12 +209,9 @@ osg::Node* SGMakeLeaf( const string& path, geometry->setColorBinding(osg::Geometry::BIND_OVERALL); geometry->setTexCoordArray(0, tl); geometry->addPrimitiveSet(new osg::DrawArrays(ty, 0, vl->size())); - osg::Geode* geode = new osg::Geode; - geode->addDrawable(geometry); // lookup the state record - geode->setStateSet(state); - geode->setUserData( new SGMaterialUserData(mat) ); + geometry->setStateSet(state); if ( calc_lights ) { if ( coverage > 0.0 ) { @@ -254,9 +220,10 @@ osg::Node* SGMakeLeaf( const string& path, << coverage << ", pushing up to 10000"); coverage = 10000; } - SGGenRandomSurfacePoints(geometry, coverage, lights ); + SGGenRandomSurfacePoints(geometry, coverage, lights); } } - return geode; + return geometry; } + diff --git a/simgear/scene/tgdb/leaf.hxx b/simgear/scene/tgdb/leaf.hxx index eb4e663d..61506ec9 100644 --- a/simgear/scene/tgdb/leaf.hxx +++ b/simgear/scene/tgdb/leaf.hxx @@ -46,9 +46,8 @@ class SGMaterialLib; // forward declaration. // Create a ssg leaf -osg::Node* SGMakeLeaf( const string& path, - const GLenum ty, - SGMaterialLib *matlib, const string& material, +osg::Drawable* SGMakeLeaf( const string& path, + const GLenum ty, SGMaterial *mat, const point_list& nodes, const point_list& normals, const point_list& texcoords, const int_list& node_index, diff --git a/simgear/scene/tgdb/obj.cxx b/simgear/scene/tgdb/obj.cxx index 8e900a80..5251a263 100644 --- a/simgear/scene/tgdb/obj.cxx +++ b/simgear/scene/tgdb/obj.cxx @@ -33,6 +33,7 @@ #include STL_STRING #include +#include #include #include #include @@ -40,14 +41,19 @@ #include #include +#include +#include + #include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -64,14 +70,12 @@ struct Leaf { // Generate an ocean tile -bool SGGenTile( const string& path, SGBucket b, - Point3D *center, double *bounding_radius, +bool SGGenTile( const string& path, const SGBucket& b, SGMaterialLib *matlib, osg::Group* group ) { osg::StateSet *state = 0; double tex_width = 1000.0; - // double tex_height; // find Ocean material in the properties list SGMaterial *mat = matlib->find( "Ocean" ); @@ -79,7 +83,6 @@ bool SGGenTile( const string& path, SGBucket b, // set the texture width and height values for this // material tex_width = mat->get_xsize(); - // tex_height = newmat->get_ysize(); // set ssgState state = mat->get_state(); @@ -90,16 +93,14 @@ bool SGGenTile( const string& path, SGBucket b, } // Calculate center point + SGVec3d cartCenter = SGVec3d::fromGeod(b.get_center()); + Point3D center = Point3D(cartCenter[0], cartCenter[1], cartCenter[2]); + double clon = b.get_center_lon(); double clat = b.get_center_lat(); double height = b.get_height(); double width = b.get_width(); - *center = sgGeodToCart( Point3D(clon*SGD_DEGREES_TO_RADIANS, - clat*SGD_DEGREES_TO_RADIANS, - 0.0) ); - // cout << "center = " << center << endl;; - // Caculate corner vertices Point3D geod[4]; geod[0] = Point3D( clon - width/2.0, clat - height/2.0, 0.0 ); @@ -118,14 +119,10 @@ bool SGGenTile( const string& path, SGBucket b, Point3D cart[4], rel[4]; for ( i = 0; i < 4; ++i ) { cart[i] = sgGeodToCart(rad[i]); - rel[i] = cart[i] - *center; + rel[i] = cart[i] - center; // cout << "corner " << i << " = " << cart[i] << endl; } - // Calculate bounding radius - *bounding_radius = center->distance3D( cart[0] ); - // cout << "bounding radius = " << t->bounding_radius << endl; - // Calculate normals Point3D normals[4]; for ( i = 0; i < 4; ++i ) { @@ -252,7 +249,7 @@ bool SGGenTile( const string& path, SGBucket b, * @param material_name The name of the surface's material. */ static void -gen_random_surface_objects (osg::Node *leaf, +gen_random_surface_objects (osg::Drawable *leaf, osg::Group *branch, Point3D *center, SGMaterial *mat ) @@ -320,7 +317,7 @@ class SGLightOffsetTransform : public osg::Transform { public: #define SCALE_FACTOR 0.94 virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix, - osg::NodeVisitor* nv) const + osg::NodeVisitor* nv) const { if (nv && nv->getVisitorType() == osg::NodeVisitor::CULL_VISITOR) { double scaleFactor = SCALE_FACTOR; @@ -349,13 +346,44 @@ public: transform(3,0) = center[0]*(1 - scaleFactor); transform(3,1) = center[1]*(1 - scaleFactor); transform(3,2) = center[2]*(1 - scaleFactor); - matrix.preMult(transform); + matrix.postMult(transform); } return true; } #undef SCALE_FACTOR }; +static SGMaterial* findMaterial(const std::string& material, + const std::string& path, + SGMaterialLib *matlib) +{ + SGMaterial *mat = matlib->find( material ); + if (mat) + return mat; + + // see if this is an on the fly texture + string file = path; + string::size_type pos = file.rfind( "/" ); + file = file.substr( 0, pos ); + // cout << "current file = " << file << endl; + file += "/"; + file += material; + // cout << "current file = " << file << endl; + if ( ! matlib->add_item( file ) ) { + SG_LOG( SG_TERRAIN, SG_ALERT, + "Ack! unknown usemtl name = " << material + << " in " << path ); + } else { + // locate our newly created material + mat = matlib->find( material ); + if ( mat == NULL ) { + SG_LOG( SG_TERRAIN, SG_ALERT, + "Ack! bad on the fly material create = " + << material << " in " << path ); + } + } + return mat; +} //////////////////////////////////////////////////////////////////////// @@ -363,15 +391,14 @@ public: //////////////////////////////////////////////////////////////////////// // Load an Binary obj file -bool SGBinObjLoad( const string& path, const bool is_base, - Point3D *center, - double *bounding_radius, +static bool SGBinObjLoad( const string& path, const bool is_base, + Point3D& center, SGMaterialLib *matlib, bool use_random_objects, - osg::Group *geometry, - osg::Group *_vasi_lights, - osg::Group *_rwy_lights, - osg::Group *_taxi_lights, + osg::Group *local_terrain, + osg::Group *vasi_lights, + osg::Group *rwy_lights, + osg::Group *taxi_lights, osg::Vec3Array *ground_lights ) { SGBinObject obj; @@ -380,37 +407,10 @@ bool SGBinObjLoad( const string& path, const bool is_base, return false; } - // Ok, somehow polygon offset for lights ... - // Could never make the polygon offset for our lights get right. - // So, why not in this way ... - SGLightOffsetTransform* vasi_lights = 0; - if (_vasi_lights) { - vasi_lights = new SGLightOffsetTransform; - _vasi_lights->addChild(vasi_lights); - } - SGLightOffsetTransform *rwy_lights = 0; - if (_rwy_lights) { - rwy_lights = new SGLightOffsetTransform; - _rwy_lights->addChild(rwy_lights); - } - SGLightOffsetTransform *taxi_lights = 0; - if (_taxi_lights) { - taxi_lights = new SGLightOffsetTransform; - _taxi_lights->addChild(taxi_lights); - } - - osg::Group *local_terrain = new osg::Group; - local_terrain->setName( "LocalTerrain" ); - geometry->addChild( local_terrain ); - - geometry->setName(path); - // reference point (center offset/bounding sphere) - *center = obj.get_gbs_center(); - *bounding_radius = obj.get_gbs_radius(); + center = obj.get_gbs_center(); point_list const& nodes = obj.get_wgs84_nodes(); - // point_list const& colors = obj.get_colors(); point_list const& normals = obj.get_normals(); point_list const& texcoords = obj.get_texcoords(); @@ -419,6 +419,9 @@ bool SGBinObjLoad( const string& path, const bool is_base, group_list::size_type i; + osg::Geode* geode = new osg::Geode; + local_terrain->addChild( geode ); + // generate points string_list const& pt_materials = obj.get_pt_materials(); group_list const& pts_v = obj.get_pts_v(); @@ -427,7 +430,7 @@ bool SGBinObjLoad( const string& path, const bool is_base, // cout << "pts_v.size() = " << pts_v.size() << endl; if ( pt_materials[i].substr(0, 3) == "RWY" ) { // airport environment lighting - SGVec3d up(center->x(), center->y(), center->z()); + SGVec3d up(center.x(), center.y(), center.z()); // returns a transform -> lod -> leaf structure osg::Node *branch = SGMakeDirectionalLights( nodes, normals, pts_v[i], pts_n[i], @@ -444,27 +447,30 @@ bool SGBinObjLoad( const string& path, const bool is_base, } } else { // other geometry - material = pt_materials[i]; + SGMaterial *mat = findMaterial( pt_materials[i], path, matlib ); tex_index.clear(); - osg::Node *leaf = SGMakeLeaf( path, GL_POINTS, matlib, material, + osg::Drawable *leaf = SGMakeLeaf( path, GL_POINTS, mat, nodes, normals, texcoords, pts_v[i], pts_n[i], tex_index, false, ground_lights ); - local_terrain->addChild( leaf ); + + + + geode->addDrawable( leaf ); } } // Put all randomly-placed objects under a separate branch // (actually an ssgRangeSelector) named "random-models". osg::Group * random_object_branch = 0; - if (use_random_objects) { - osg::LOD* object_lod = new osg::LOD; - object_lod->setName("random-models"); - geometry->addChild(object_lod); - random_object_branch = new osg::Group; - // Maximum 20km range for random objects - object_lod->addChild(random_object_branch, 0, 20000); - } +// if (use_random_objects) { +// osg::LOD* object_lod = new osg::LOD; +// object_lod->setName("random-models"); +// geometry->addChild(object_lod); +// random_object_branch = new osg::Group; +// // Maximum 20km range for random objects +// object_lod->addChild(random_object_branch, 0, 20000); +// } typedef map > LeafMap; LeafMap leafMap; @@ -499,65 +505,48 @@ bool SGBinObjLoad( const string& path, const bool is_base, LeafMap::iterator lmi = leafMap.begin(); while ( lmi != leafMap.end() ) { + SGMaterial *mat = findMaterial( lmi->first, path, matlib ); list &leaf_list = lmi->second; list::iterator li = leaf_list.begin(); while ( li != leaf_list.end() ) { Leaf &leaf = *li; int ind = leaf.index; if ( leaf.type == GL_TRIANGLES ) { - osg::Node *leaf = SGMakeLeaf( path, GL_TRIANGLES, matlib, - tri_materials[ind], + osg::Drawable *leaf = SGMakeLeaf( path, GL_TRIANGLES, mat, nodes, normals, texcoords, tris_v[ind], tris_n[ind], tris_tc[ind], is_base, ground_lights ); - if ( use_random_objects ) { - SGMaterial *mat = matlib->find( tri_materials[ind] ); - if ( mat == NULL ) { - SG_LOG( SG_INPUT, SG_ALERT, - "Unknown material for random surface objects = " - << tri_materials[ind] ); - } else { + if ( random_object_branch ) { + if ( mat ) { gen_random_surface_objects( leaf, random_object_branch, - center, mat ); + ¢er, mat ); } } - local_terrain->addChild( leaf ); + geode->addDrawable( leaf ); } else if ( leaf.type == GL_TRIANGLE_STRIP ) { - osg::Node *leaf = SGMakeLeaf( path, GL_TRIANGLE_STRIP, - matlib, strip_materials[ind], + osg::Drawable *leaf = SGMakeLeaf( path, GL_TRIANGLE_STRIP, mat, nodes, normals, texcoords, strips_v[ind], strips_n[ind], strips_tc[ind], is_base, ground_lights ); - if ( use_random_objects ) { - SGMaterial *mat = matlib->find( strip_materials[ind] ); - if ( mat == NULL ) { - SG_LOG( SG_INPUT, SG_ALERT, - "Unknown material for random surface objects = " - << strip_materials[ind] ); - } else { + if ( random_object_branch ) { + if ( mat ) { gen_random_surface_objects( leaf, random_object_branch, - center, mat ); + ¢er, mat ); } } - local_terrain->addChild( leaf ); + geode->addDrawable( leaf ); } else { - osg::Node *leaf = SGMakeLeaf( path, GL_TRIANGLE_FAN, - matlib, fan_materials[ind], + osg::Drawable *leaf = SGMakeLeaf( path, GL_TRIANGLE_FAN, mat, nodes, normals, texcoords, fans_v[ind], fans_n[ind], fans_tc[ind], is_base, ground_lights ); - if ( use_random_objects ) { - SGMaterial *mat = matlib->find( fan_materials[ind] ); - if ( mat == NULL ) { - SG_LOG( SG_INPUT, SG_ALERT, - "Unknown material for random surface objects = " - << fan_materials[ind] ); - } else { + if ( random_object_branch ) { + if ( mat ) { gen_random_surface_objects( leaf, random_object_branch, - center, mat ); + ¢er, mat ); } } - local_terrain->addChild( leaf ); + geode->addDrawable( leaf ); } ++li; } @@ -566,3 +555,236 @@ bool SGBinObjLoad( const string& path, const bool is_base, return true; } + + + + +static osg::Node* +gen_lights( SGMaterialLib *matlib, osg::Vec3Array *lights, int inc, float bright ) +{ + // generate a repeatable random seed + sg_srandom( (unsigned)(*lights)[0][0] ); + + // Allocate ssg structure + osg::Vec3Array *vl = new osg::Vec3Array; + osg::Vec4Array *cl = new osg::Vec4Array; + + for ( unsigned i = 0; i < lights->size(); ++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->push_back( (*lights)[i] ); + + // factor = sg_random() ^ 2, range = 0 .. 1 concentrated towards 0 + float factor = sg_random(); + factor *= factor; + + osg::Vec4 color; + if ( zombie > 0.5 ) { + // 50% chance of yellowish + color = osg::Vec4( 0.9, 0.9, 0.3, bright - factor * 0.2 ); + } else if ( zombie > 0.15 ) { + // 35% chance of whitish + color = osg::Vec4( 0.9, 0.9, 0.8, bright - factor * 0.2 ); + } else if ( zombie > 0.05 ) { + // 10% chance of orangish + color = osg::Vec4( 0.9, 0.6, 0.2, bright - factor * 0.2 ); + } else { + // 5% chance of redish + color = osg::Vec4( 0.9, 0.2, 0.2, bright - factor * 0.2 ); + } + cl->push_back( color ); + } + } + + // create ssg leaf + 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); + + // assign state + SGMaterial *mat = matlib->find( "GROUND_LIGHTS" ); + geometry->setStateSet(mat->get_state()); + + return geode; +} + +class SGTileUpdateCallback : public osg::NodeCallback { +public: + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + assert(dynamic_cast(node)); + assert(dynamic_cast(nv)); + + osg::Switch* lightSwitch = static_cast(node); + SGUpdateVisitor* updateVisitor = static_cast(nv); + + // The current sun angle in degree + float sun_angle = updateVisitor->getSunAngleDeg(); + + // vasi is always on + lightSwitch->setValue(0, true); + if (sun_angle > 85 || updateVisitor->getVisibility() < 5000) { + // runway and taxi + lightSwitch->setValue(1, true); + lightSwitch->setValue(2, true); + } else { + // runway and taxi + lightSwitch->setValue(1, false); + lightSwitch->setValue(2, false); + } + + // ground lights + if ( sun_angle > 95 ) + lightSwitch->setValue(5, true); + else + lightSwitch->setValue(5, false); + if ( sun_angle > 92 ) + lightSwitch->setValue(4, true); + else + lightSwitch->setValue(4, false); + if ( sun_angle > 89 ) + lightSwitch->setValue(3, true); + else + lightSwitch->setValue(3, false); + + traverse(node, nv); + } +}; + +class SGRunwayLightFogUpdateCallback : public osg::StateAttribute::Callback { +public: + virtual void operator () (osg::StateAttribute* sa, osg::NodeVisitor* nv) + { + assert(dynamic_cast(nv)); + assert(dynamic_cast(sa)); + SGUpdateVisitor* updateVisitor = static_cast(nv); + osg::Fog* fog = static_cast(sa); + fog->setMode(osg::Fog::EXP2); + fog->setColor(updateVisitor->getFogColor().osg()); + fog->setDensity(updateVisitor->getRunwayFogExp2Density()); + } +}; + +class SGTaxiLightFogUpdateCallback : public osg::StateAttribute::Callback { +public: + virtual void operator () (osg::StateAttribute* sa, osg::NodeVisitor* nv) + { + assert(dynamic_cast(nv)); + assert(dynamic_cast(sa)); + SGUpdateVisitor* updateVisitor = static_cast(nv); + osg::Fog* fog = static_cast(sa); + fog->setMode(osg::Fog::EXP2); + fog->setColor(updateVisitor->getFogColor().osg()); + fog->setDensity(updateVisitor->getTaxiFogExp2Density()); + } +}; + +class SGGroundLightFogUpdateCallback : public osg::StateAttribute::Callback { +public: + virtual void operator () (osg::StateAttribute* sa, osg::NodeVisitor* nv) + { + assert(dynamic_cast(nv)); + assert(dynamic_cast(sa)); + SGUpdateVisitor* updateVisitor = static_cast(nv); + osg::Fog* fog = static_cast(sa); + fog->setMode(osg::Fog::EXP2); + fog->setColor(updateVisitor->getFogColor().osg()); + fog->setDensity(updateVisitor->getGroundLightsFogExp2Density()); + } +}; + + +osg::Node* +SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool calc_lights, bool use_random_objects) +{ + osg::Group* vasiLights = new osg::Group; + osg::StateSet* stateSet = vasiLights->getOrCreateStateSet(); + osg::Fog* fog = new osg::Fog; + fog->setUpdateCallback(new SGRunwayLightFogUpdateCallback); + stateSet->setAttribute(fog); + + osg::Group* rwyLights = new osg::Group; + stateSet = rwyLights->getOrCreateStateSet(); + fog = new osg::Fog; + fog->setUpdateCallback(new SGRunwayLightFogUpdateCallback); + stateSet->setAttribute(fog); + + osg::Group* taxiLights = new osg::Group; + stateSet = taxiLights->getOrCreateStateSet(); + fog = new osg::Fog; + fog->setUpdateCallback(new SGTaxiLightFogUpdateCallback); + stateSet->setAttribute(fog); + + osg::Group* groundLights0 = new osg::Group; + stateSet = groundLights0->getOrCreateStateSet(); + fog = new osg::Fog; + fog->setUpdateCallback(new SGGroundLightFogUpdateCallback); + stateSet->setAttribute(fog); + + osg::Group* groundLights1 = new osg::Group; + stateSet = groundLights1->getOrCreateStateSet(); + fog = new osg::Fog; + fog->setUpdateCallback(new SGGroundLightFogUpdateCallback); + stateSet->setAttribute(fog); + + osg::Group* groundLights2 = new osg::Group; + stateSet = groundLights2->getOrCreateStateSet(); + fog = new osg::Fog; + fog->setUpdateCallback(new SGGroundLightFogUpdateCallback); + stateSet->setAttribute(fog); + + osg::Switch* lightSwitch = new osg::Switch; + lightSwitch->setUpdateCallback(new SGTileUpdateCallback); + lightSwitch->addChild(vasiLights, true); + lightSwitch->addChild(rwyLights, true); + lightSwitch->addChild(taxiLights, true); + lightSwitch->addChild(groundLights0, true); + lightSwitch->addChild(groundLights1, true); + lightSwitch->addChild(groundLights2, true); + + osg::Group* lightGroup = new SGLightOffsetTransform; + lightGroup->addChild(lightSwitch); + unsigned nodeMask = ~0u; + nodeMask &= ~SG_NODEMASK_CASTSHADOW_BIT; + nodeMask &= ~SG_NODEMASK_RECIEVESHADOW_BIT; + nodeMask &= ~SG_NODEMASK_PICK_BIT; + nodeMask &= ~SG_NODEMASK_TERRAIN_BIT; + lightGroup->setNodeMask(nodeMask); + + osg::Group* terrainGroup = new osg::Group; + + osg::ref_ptr light_pts = new osg::Vec3Array; + Point3D center; + SGBinObjLoad(path, calc_lights, center, matlib, use_random_objects, + terrainGroup, vasiLights, rwyLights, taxiLights, light_pts.get()); + + if ( light_pts->size() ) { + osg::Node *lights; + + lights = gen_lights( matlib, light_pts.get(), 4, 0.7 ); + groundLights0->addChild( lights ); + + lights = gen_lights( matlib, light_pts.get(), 2, 0.85 ); + groundLights1->addChild( lights ); + + lights = gen_lights( matlib, light_pts.get(), 1, 1.0 ); + groundLights2->addChild( lights ); + } + + // The toplevel transform for that tile. + osg::MatrixTransform* transform = new osg::MatrixTransform; + transform->setName(path); + transform->setMatrix(osg::Matrix::translate(osg::Vec3d(center[0], center[1], center[2]))); + transform->addChild(terrainGroup); + transform->addChild(lightGroup); + + return transform; +} diff --git a/simgear/scene/tgdb/obj.hxx b/simgear/scene/tgdb/obj.hxx index 5e3ae30a..34080c0c 100644 --- a/simgear/scene/tgdb/obj.hxx +++ b/simgear/scene/tgdb/obj.hxx @@ -45,23 +45,12 @@ SG_USING_STD(string); class SGBucket; class SGMaterialLib; - -// Load a Binary obj file -bool SGBinObjLoad( const string& path, const bool is_base, - Point3D *center, - double *bounding_radius, - SGMaterialLib *matlib, - bool use_random_objects, - osg::Group *geometry, - osg::Group *vasi_lights, - osg::Group *rwy_lights, - osg::Group *taxi_lights, - osg::Vec3Array *ground_lights ); - // Generate an ocean tile -bool SGGenTile( const string& path, SGBucket b, - Point3D *center, double *bounding_radius, +bool SGGenTile( const string& path, const SGBucket& b, SGMaterialLib *matlib, osg::Group *geometry ); +osg::Node* +SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool calc_lights, bool use_random_objects); + #endif // _SG_OBJ_HXX diff --git a/simgear/scene/util/SGUpdateVisitor.hxx b/simgear/scene/util/SGUpdateVisitor.hxx index 68f8ecdb..74d60e99 100644 --- a/simgear/scene/util/SGUpdateVisitor.hxx +++ b/simgear/scene/util/SGUpdateVisitor.hxx @@ -29,12 +29,14 @@ class SGUpdateVisitor : public osgUtil::UpdateVisitor { public: - SGUpdateVisitor() + SGUpdateVisitor() : + mVisibility(-1) { // Need to traverse all children, else some LOD nodes do not get updated // Note that the broad number of updates is not done due to // the update callback in the global position node. setTraversalMode(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN); + setVisibility(10000); } void setViewData(const SGVec3d& globalEyePos, const SGQuatd& globalViewOrientation) @@ -48,15 +50,32 @@ public: mHorizLocalDown = mGlobalHorizLocalOr.backTransform(SGVec3d(0, 0, 1)); } - void setSceneryCenter(const SGVec3d& sceneryCenter) - { - mSceneryCenter = sceneryCenter; - } - void setVisibility(double visibility) { + if (mVisibility == visibility) + return; mVisibility = visibility; mSqrVisibility = visibility*visibility; + + double m_log01 = -log( 0.01 ); + double sqrt_m_log01 = sqrt( m_log01 ); + double fog_exp_density = m_log01 / visibility; + double fog_exp2_density = sqrt_m_log01 / visibility; + double ground_exp2_punch_through = sqrt_m_log01 / (visibility * 1.5); + double rwy_exp2_punch_through, taxi_exp2_punch_through; + if ( visibility < 8000 ) { + rwy_exp2_punch_through = sqrt_m_log01 / (visibility * 2.5); + taxi_exp2_punch_through = sqrt_m_log01 / (visibility * 1.5); + } else { + rwy_exp2_punch_through = sqrt_m_log01 / ( 8000 * 2.5 ); + taxi_exp2_punch_through = sqrt_m_log01 / ( 8000 * 1.5 ); + } + + mFogExpDensity = fog_exp_density; + mFogExp2Density = fog_exp2_density; + mRunwayFogExp2Density = rwy_exp2_punch_through; + mTaxiFogExp2Density = taxi_exp2_punch_through; + mGroundLightsFogExp2Density = ground_exp2_punch_through; } double getVisibility() const @@ -64,6 +83,17 @@ public: double getSqrVisibility() const { return mSqrVisibility; } + double getFogExpDensity() const + { return mFogExpDensity; } + double getFogExp2Density() const + { return mFogExp2Density; } + double getRunwayFogExp2Density() const + { return mRunwayFogExp2Density; } + double getTaxiFogExp2Density() const + { return mTaxiFogExp2Density; } + double getGroundLightsFogExp2Density() const + { return mGroundLightsFogExp2Density; } + const SGVec3d& getGlobalEyePos() const { return mGlobalEyePos; } const SGGeod& getGeodEyePos() const @@ -80,11 +110,15 @@ public: { return mHorizLocalDown; } void setLight(const SGVec3f& direction, const SGVec4f& ambient, - const SGVec4f& diffuse, const SGVec4f& specular) + const SGVec4f& diffuse, const SGVec4f& specular, + const SGVec4f& fogColor, double sunAngleDeg) { mLightDirection = direction; mAmbientLight = ambient; mDiffuseLight = diffuse; + mSpecularLight = specular; + mFogColor = fogColor; + mSunAngleDeg = sunAngleDeg; } const SGVec3f& getLightDirection() const @@ -95,6 +129,11 @@ public: { return mDiffuseLight; } const SGVec4f& getSpecularLight() const { return mSpecularLight; } + const SGVec4f& getFogColor() const + { return mFogColor; } + + double getSunAngleDeg() const + { return mSunAngleDeg; } private: SGGeod mGlobalGeodEyePos; @@ -105,15 +144,21 @@ private: SGVec3d mHorizLocalEast; SGVec3d mHorizLocalDown; - SGVec3d mSceneryCenter; - double mVisibility; double mSqrVisibility; + double mFogExpDensity; + double mFogExp2Density; + double mRunwayFogExp2Density; + double mTaxiFogExp2Density; + double mGroundLightsFogExp2Density; SGVec3f mLightDirection; SGVec4f mAmbientLight; SGVec4f mDiffuseLight; SGVec4f mSpecularLight; + SGVec4f mFogColor; + + double mSunAngleDeg; }; #endif -- 2.39.5