#include <osg/StateSet>
#include <osg/Switch>
+#include <boost/foreach.hpp>
+
#include <simgear/debug/logstream.hxx>
#include <simgear/io/sg_binobj.hxx>
#include <simgear/math/sg_geodesy.hxx>
#include <simgear/math/sg_random.h>
+#include <simgear/scene/material/Effect.hxx>
+#include <simgear/scene/material/EffectGeode.hxx>
#include <simgear/scene/material/mat.hxx>
#include <simgear/scene/material/matlib.hxx>
#include <simgear/scene/model/SGOffsetTransform.hxx>
#include <simgear/scene/util/SGUpdateVisitor.hxx>
#include <simgear/scene/util/SGNodeMasks.hxx>
#include <simgear/scene/util/QuadTreeBuilder.hxx>
-#include <simgear/threads/SGThread.hxx>
-#include <simgear/threads/SGGuard.hxx>
#include "SGTexturedTriangleBin.hxx"
#include "SGLightBin.hxx"
SGMaterialTriangleMap materialTriangleMap;
SGLightBin tileLights;
SGLightBin randomTileLights;
- TreeBin randomForest;
+ SGTreeBinList randomForest;
SGDirectionalLightBin runwayLights;
SGDirectionalLightBin taxiLights;
SGDirectionalLightListBin vasiLights;
for (unsigned grp = 0; grp < obj.get_pts_v().size(); ++grp) {
std::string materialName = obj.get_pt_materials()[grp];
- SGMaterial* material = matlib->find(materialName);
+ SGMaterial* material = 0;
+ if (matlib)
+ material = matlib->find(materialName);
SGVec4f color = getMaterialLightColor(material);
if (3 <= materialName.size() && materialName.substr(0, 3) != "RWY") {
if (materialTriangleMap.empty())
return 0;
- osg::Geode* geode = new osg::Geode;
+ EffectGeode* eg = 0;
+ osg::Group* group = (materialTriangleMap.size() > 1 ? new osg::Group : 0);
+ //osg::Geode* geode = new osg::Geode;
SGMaterialTriangleMap::const_iterator i;
for (i = materialTriangleMap.begin(); i != materialTriangleMap.end(); ++i) {
- // CHUNCKED (sic) here splits up unconnected triangles parts of
- // the mesh into different Geometry sets, presumably for better
- // culling. I (timoore) believe it is more performant to build
- // the biggest indexed sets possible at the expense of tight
- // culling.
-//#define CHUNCKED
-#ifdef CHUNCKED
- SGMaterial *mat = matlib->find(i->first);
-
- std::list<SGTexturedTriangleBin::TriangleVector> connectSets;
- i->second.getConnectedSets(connectSets);
-
- std::list<SGTexturedTriangleBin::TriangleVector>::iterator j;
- for (j = connectSets.begin(); j != connectSets.end(); ++j) {
- osg::Geometry* geometry = i->second.buildGeometry(*j);
- if (mat)
- geometry->setStateSet(mat->get_state());
- geode->addDrawable(geometry);
- }
-#else
osg::Geometry* geometry = i->second.buildGeometry();
- SGMaterial *mat = matlib->find(i->first);
+ SGMaterial *mat = 0;
+ if (matlib)
+ mat = matlib->find(i->first);
+ eg = new EffectGeode;
if (mat)
- geometry->setStateSet(mat->get_state());
- geode->addDrawable(geometry);
-#endif
+ eg->setEffect(mat->get_effect());
+ eg->addDrawable(geometry);
+ eg->runGenerators(geometry); // Generate extra data needed by effect
+ if (group)
+ group->addChild(eg);
}
- return geode;
+ if (group)
+ return group;
+ else
+ return eg;
}
void computeRandomSurfaceLights(SGMaterialLib* matlib)
if (!mat)
continue;
- float coverage = mat->get_tree_coverage();
- if (coverage <= 0)
+ float wood_coverage = mat->get_wood_coverage();
+ if (wood_coverage <= 0)
continue;
-
- // Attributes that don't vary by tree
- randomForest.texture = mat->get_tree_texture();
- randomForest.range = mat->get_tree_range();
- randomForest.width = mat->get_tree_width();
- randomForest.height = mat->get_tree_height();
- randomForest.texture_varieties = mat->get_tree_varieties();
+
+ // Attributes that don't vary by tree but do vary by material
+ bool found = false;
+ TreeBin* bin = NULL;
+
+ BOOST_FOREACH(bin, randomForest)
+ {
+ if ((bin->texture == mat->get_tree_texture() ) &&
+ (bin->texture_varieties == mat->get_tree_varieties()) &&
+ (bin->range == mat->get_tree_range() ) &&
+ (bin->width == mat->get_tree_width() ) &&
+ (bin->height == mat->get_tree_height() ) ) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ bin = new TreeBin();
+ bin->texture = mat->get_tree_texture();
+ SG_LOG(SG_INPUT, SG_DEBUG, "Tree texture " << bin->texture);
+ bin->range = mat->get_tree_range();
+ bin->width = mat->get_tree_width();
+ bin->height = mat->get_tree_height();
+ bin->texture_varieties = mat->get_tree_varieties();
+ randomForest.push_back(bin);
+ }
std::vector<SGVec3f> randomPoints;
- i->second.addRandomSurfacePoints(coverage, 0, randomPoints);
- std::vector<SGVec3f>::iterator j;
- for (j = randomPoints.begin(); j != randomPoints.end(); ++j) {
-
- // Apply a random scaling factor and texture index.
- float scale = (mt_rand(&seed) + mt_rand(&seed)) / 2.0f + 0.5f;
- int v = (int) (mt_rand(&seed) * mat->get_tree_varieties());
- if (v == mat->get_tree_varieties()) v--;
- randomForest.insert(*j, v, scale);
+ i->second.addRandomTreePoints(wood_coverage,
+ mat->get_tree_density(),
+ mat->get_wood_size(),
+ randomPoints);
+
+ std::vector<SGVec3f>::iterator k;
+ for (k = randomPoints.begin(); k != randomPoints.end(); ++k) {
+ bin->insert(*k);
}
}
}
}
};
struct GetModelLODCoord {
- GetModelLODCoord(const osg::Matrix& transform) : _transform(transform) {}
- GetModelLODCoord(const GetModelLODCoord& rhs) : _transform(rhs._transform)
+ GetModelLODCoord() {}
+ GetModelLODCoord(const GetModelLODCoord& rhs)
{}
osg::Vec3 operator() (const ModelLOD& mlod) const
{
- return mlod.first->getBound().center() * _transform;
+ return mlod.first->getBound().center();
}
- osg::Matrix _transform;
};
typedef QuadTreeBuilder<osg::LOD*, ModelLOD, MakeQuadLeaf, AddModelLOD,
if (!tile.read_bin(path))
return false;
+ SGVec3d center = tile.get_gbs_center();
+ SGGeod geodPos = SGGeod::fromCart(center);
+ SGQuatd hlOr = SGQuatd::fromLonLat(geodPos)*SGQuatd::fromEulerDeg(0, 0, 180);
+
+ // rotate the tiles so that the bounding boxes get nearly axis aligned.
+ // this will help the collision tree's bounding boxes a bit ...
+ std::vector<SGVec3d> nodes = tile.get_wgs84_nodes();
+ for (unsigned i = 0; i < nodes.size(); ++i)
+ nodes[i] = hlOr.transform(nodes[i]);
+ tile.set_wgs84_nodes(nodes);
+
+ SGQuatf hlOrf(hlOr[0], hlOr[1], hlOr[2], hlOr[3]);
+ std::vector<SGVec3f> normals = tile.get_normals();
+ for (unsigned i = 0; i < normals.size(); ++i)
+ normals[i] = hlOrf.transform(normals[i]);
+ tile.set_normals(normals);
+
SGTileGeometryBin tileGeometryBin;
if (!tileGeometryBin.insertBinObj(tile, matlib))
return false;
- SGVec3d center = tile.get_gbs_center2();
- SGGeod geodPos = SGGeod::fromCart(center);
- SGQuatd hlOr = SGQuatd::fromLonLat(geodPos);
- SGVec3f up = toVec3f(hlOr.backTransform(SGVec3d(0, 0, -1)));
+ SGVec3f up(0, 0, 1);
GroundLightManager* lightManager = GroundLightManager::instance();
osg::ref_ptr<osg::Group> lightGroup = new SGOffsetTransform(0.94);
osg::ref_ptr<osg::Group> randomObjects;
- osg::ref_ptr<osg::Group> randomForest;
+ osg::ref_ptr<osg::Group> forestNode;
osg::Group* terrainGroup = new osg::Group;
osg::Node* node = tileGeometryBin.getSurfaceGeometry(matlib);
terrainGroup->addChild(node);
if (use_random_objects || use_random_vegetation) {
-
- // Simple matrix for used for flipping models that have been oriented
- // with the center of the tile but upside down.
- static const osg::Matrix flip(1, 0, 0, 0,
- 0, -1, 0, 0,
- 0, 0, -1, 0,
- 0, 0, 0, 1);
- // Determine an rotation matrix for the models to place them
- // perpendicular to the earth's surface. We use the same matrix,
- // based on the centre of the tile, as the small angular differences
- // between different points on the tile aren't worth worrying about
- // for random objects. We also need to flip the orientation 180 degrees
- osg::Matrix mAtt = flip * osg::Matrix::rotate(hlOr.osg());
- // The inverse goes from world coordinates to Z up tile coordinates.
- osg::Matrix world2Tile(osg::Matrix(hlOr.osg().conj()) * flip);
-
if (use_random_objects) {
- tileGeometryBin.computeRandomObjects(matlib);
+ if (matlib)
+ tileGeometryBin.computeRandomObjects(matlib);
if (tileGeometryBin.randomModels.getNumModels() > 0) {
// Generate a repeatable random seed
i < tileGeometryBin.randomModels.getNumModels(); i++) {
SGMatModelBin::MatModel obj
= tileGeometryBin.randomModels.getMatModel(i);
- osg::Node* node = sgGetRandomModel(obj.model);
+ osg::Node* node = sgGetRandomModel(obj.model, seed);
// Create a matrix to place the object in the correct
// location, and then apply the rotation matrix created
// above, with an additional random heading rotation if appropriate.
- osg::Matrix transformMat(mAtt);
- transformMat.postMult(osg::Matrix::translate(obj.position.osg()));
+ osg::Matrix transformMat;
+ transformMat = osg::Matrix::translate(toOsg(obj.position));
if (obj.model->get_heading_type() == SGMatModel::HEADING_RANDOM) {
// Rotate the object around the z axis.
double hdg = mt_rand(&seed) * M_PI * 2;
position->addChild(node);
models.push_back(ModelLOD(position, obj.lod));
}
- RandomObjectsQuadtree quadtree((GetModelLODCoord(world2Tile)),
- (AddModelLOD()));
+ RandomObjectsQuadtree quadtree((GetModelLODCoord()), (AddModelLOD()));
quadtree.buildQuadTree(models.begin(), models.end());
randomObjects = quadtree.getRoot();
randomObjects->setName("random objects");
}
}
- if (use_random_vegetation) {
+ if (use_random_vegetation && matlib) {
// Now add some random forest.
tileGeometryBin.computeRandomForest(matlib);
-
- if (tileGeometryBin.randomForest.getNumTrees() > 0) {
- randomForest = createForest(tileGeometryBin.randomForest, mAtt);
- randomForest->setName("random trees");
+
+ if (tileGeometryBin.randomForest.size() > 0) {
+ forestNode = createForest(tileGeometryBin.randomForest, osg::Matrix::identity());
+ forestNode->setName("Random trees");
}
}
}
if (calc_lights) {
// FIXME: ugly, has a side effect
- tileGeometryBin.computeRandomSurfaceLights(matlib);
+ if (matlib)
+ tileGeometryBin.computeRandomSurfaceLights(matlib);
if (tileGeometryBin.tileLights.getNumLights() > 0
|| tileGeometryBin.randomTileLights.getNumLights() > 0) {
}
if (!tileGeometryBin.vasiLights.empty()) {
- osg::Geode* vasiGeode = new osg::Geode;
+ EffectGeode* vasiGeode = new EffectGeode;
+ Effect* vasiEffect
+ = getLightEffect(6, osg::Vec3(1, 0.0001, 0.000001), 1, 6, true);
+ vasiGeode->setEffect(vasiEffect);
SGVec4f red(1, 0, 0, 1);
- SGMaterial* mat = matlib->find("RWY_RED_LIGHTS");
+ SGMaterial* mat = 0;
+ if (matlib)
+ mat = matlib->find("RWY_RED_LIGHTS");
if (mat)
red = mat->get_light_color();
SGVec4f white(1, 1, 1, 1);
- mat = matlib->find("RWY_WHITE_LIGHTS");
+ mat = 0;
+ if (matlib)
+ mat = matlib->find("RWY_WHITE_LIGHTS");
if (mat)
white = mat->get_light_color();
-
SGDirectionalLightListBin::const_iterator i;
for (i = tileGeometryBin.vasiLights.begin();
i != tileGeometryBin.vasiLights.end(); ++i) {
vasiGeode->addDrawable(SGLightFactory::getVasi(up, *i, red, white));
}
- vasiGeode->setCullCallback(new SGPointSpriteLightCullCallback(osg::Vec3(1, 0.0001, 0.000001), 6));
vasiGeode->setStateSet(lightManager->getRunwayLightStateSet());
lightGroup->addChild(vasiGeode);
}
-
+ Effect* runwayEffect = 0;
+ if (tileGeometryBin.runwayLights.getNumLights() > 0
+ || !tileGeometryBin.rabitLights.empty()
+ || !tileGeometryBin.reilLights.empty()
+ || !tileGeometryBin.odalLights.empty()
+ || tileGeometryBin.taxiLights.getNumLights() > 0)
+ runwayEffect = getLightEffect(4, osg::Vec3(1, 0.001, 0.0002), 1, 4, true);
if (tileGeometryBin.runwayLights.getNumLights() > 0
|| !tileGeometryBin.rabitLights.empty()
|| !tileGeometryBin.reilLights.empty()
|| !tileGeometryBin.odalLights.empty()) {
osg::Group* rwyLights = new osg::Group;
- rwyLights->setCullCallback(new SGPointSpriteLightCullCallback);
rwyLights->setStateSet(lightManager->getRunwayLightStateSet());
rwyLights->setNodeMask(RUNWAYLIGHTS_BIT);
if (tileGeometryBin.runwayLights.getNumLights() != 0) {
- osg::Geode* geode = new osg::Geode;
+ EffectGeode* geode = new EffectGeode;
+ geode->setEffect(runwayEffect);
geode->addDrawable(SGLightFactory::getLights(tileGeometryBin
.runwayLights));
rwyLights->addChild(geode);
if (tileGeometryBin.taxiLights.getNumLights() > 0) {
osg::Group* taxiLights = new osg::Group;
- taxiLights->setCullCallback(new SGPointSpriteLightCullCallback);
taxiLights->setStateSet(lightManager->getTaxiLightStateSet());
taxiLights->setNodeMask(RUNWAYLIGHTS_BIT);
- osg::Geode* geode = new osg::Geode;
+ EffectGeode* geode = new EffectGeode;
+ geode->setEffect(runwayEffect);
geode->addDrawable(SGLightFactory::getLights(tileGeometryBin.taxiLights));
taxiLights->addChild(geode);
lightGroup->addChild(taxiLights);
// The toplevel transform for that tile.
osg::MatrixTransform* transform = new osg::MatrixTransform;
transform->setName(path);
- transform->setMatrix(osg::Matrix::translate(center.osg()));
+ transform->setMatrix(osg::Matrix::rotate(toOsg(hlOr))*
+ osg::Matrix::translate(toOsg(center)));
transform->addChild(terrainGroup);
if (lightGroup->getNumChildren() > 0) {
osg::LOD* lightLOD = new osg::LOD;
transform->addChild(lightLOD);
}
- if (randomObjects.valid() || randomForest.valid()) {
+ if (randomObjects.valid() || forestNode.valid()) {
// Add a LoD node, so we don't try to display anything when the tile center
// is more than 20km away.
osg::LOD* objectLOD = new osg::LOD;
if (randomObjects.valid()) objectLOD->addChild(randomObjects.get(), 0, 20000);
- if (randomForest.valid()) objectLOD->addChild(randomForest.get(), 0, 20000);
+ if (forestNode.valid()) objectLOD->addChild(forestNode.get(), 0, 20000);
- unsigned nodeMask = SG_NODEMASK_CASTSHADOW_BIT | SG_NODEMASK_RECIEVESHADOW_BIT;
+ unsigned nodeMask = SG_NODEMASK_CASTSHADOW_BIT | SG_NODEMASK_RECIEVESHADOW_BIT | SG_NODEMASK_TERRAIN_BIT;
objectLOD->setNodeMask(nodeMask);
transform->addChild(objectLOD);
}