#include STL_STRING
#include <osg/Depth>
+#include <osg/Fog>
#include <osg/Geode>
#include <osg/Geometry>
#include <osg/Group>
#include <osg/MatrixTransform>
#include <osg/StateSet>
+#include <osgUtil/Optimizer>
+#include <osgDB/WriteFile>
+
#include <simgear/bucket/newbucket.hxx>
#include <simgear/io/sg_binobj.hxx>
#include <simgear/math/sg_geodesy.hxx>
+#include <simgear/math/sg_random.h>
#include <simgear/math/sg_types.hxx>
#include <simgear/misc/texcoord.hxx>
#include <simgear/scene/material/mat.hxx>
#include <simgear/scene/material/matlib.hxx>
#include <simgear/scene/util/SGUpdateVisitor.hxx>
+#include <simgear/scene/util/SGNodeMasks.hxx>
#include <simgear/scene/tgdb/leaf.hxx>
#include <simgear/scene/tgdb/pt_lights.hxx>
#include <simgear/scene/tgdb/userdata.hxx>
// 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" );
// 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();
}
// 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 );
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 ) {
* @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 )
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;
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;
+}
\f
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
// 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;
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();
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();
// 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],
}
} 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<string,list<Leaf> > LeafMap;
LeafMap leafMap;
LeafMap::iterator lmi = leafMap.begin();
while ( lmi != leafMap.end() ) {
+ SGMaterial *mat = findMaterial( lmi->first, path, matlib );
list<Leaf> &leaf_list = lmi->second;
list<Leaf>::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;
}
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<osg::Switch*>(node));
+ assert(dynamic_cast<SGUpdateVisitor*>(nv));
+
+ osg::Switch* lightSwitch = static_cast<osg::Switch*>(node);
+ SGUpdateVisitor* updateVisitor = static_cast<SGUpdateVisitor*>(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<SGUpdateVisitor*>(nv));
+ assert(dynamic_cast<osg::Fog*>(sa));
+ SGUpdateVisitor* updateVisitor = static_cast<SGUpdateVisitor*>(nv);
+ osg::Fog* fog = static_cast<osg::Fog*>(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<SGUpdateVisitor*>(nv));
+ assert(dynamic_cast<osg::Fog*>(sa));
+ SGUpdateVisitor* updateVisitor = static_cast<SGUpdateVisitor*>(nv);
+ osg::Fog* fog = static_cast<osg::Fog*>(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<SGUpdateVisitor*>(nv));
+ assert(dynamic_cast<osg::Fog*>(sa));
+ SGUpdateVisitor* updateVisitor = static_cast<SGUpdateVisitor*>(nv);
+ osg::Fog* fog = static_cast<osg::Fog*>(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<osg::Vec3Array> 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;
+}