PagedLOD for random trees, buildings and objects.

This commit is contained in:
Stuart Buchanan 2013-12-06 20:20:46 +00:00
parent 3ec9c7ae6e
commit 5bc535a8d2
3 changed files with 710 additions and 642 deletions

View File

@ -110,10 +110,10 @@ BuildingBoundingBoxCallback::computeBound(const Drawable& drawable) const
// Set up the building set based on the material definitions
SGBuildingBin::SGBuildingBin(const SGMaterial *mat) {
material_name = mat->get_names()[0];
material_name = new std::string(mat->get_names()[0]);
SG_LOG(SG_TERRAIN, SG_DEBUG, "Building material " << material_name);
texture = mat->get_building_texture();
lightMap = mat->get_building_lightmap();
texture = new std::string(mat->get_building_texture());
lightMap = new std::string(mat->get_building_lightmap());
SG_LOG(SG_TERRAIN, SG_DEBUG, "Building texture " << texture);
// Generate a random seed for the building generation.
@ -721,7 +721,7 @@ BuildingBoundingBoxCallback::computeBound(const Drawable& drawable) const
ref_ptr<Group> SGBuildingBin::createBuildingsGroup(Matrix transInv, const SGReaderWriterOptions* options)
{
ref_ptr<Effect> effect;
EffectMap::iterator iter = buildingEffectMap.find(texture);
EffectMap::iterator iter = buildingEffectMap.find(*texture);
if ((iter == buildingEffectMap.end())||
(!iter->second.lock(effect)))
@ -731,15 +731,15 @@ BuildingBoundingBoxCallback::computeBound(const Drawable& drawable) const
SGPropertyNode* params = makeChild(effectProp, "parameters");
// Main texture - n=0
params->getChild("texture", 0, true)->getChild("image", 0, true)
->setStringValue(texture);
->setStringValue(*texture);
// Light map - n=3
params->getChild("texture", 3, true)->getChild("image", 0, true)
->setStringValue(lightMap);
->setStringValue(*lightMap);
effect = makeEffect(effectProp, true, options);
if (iter == buildingEffectMap.end())
buildingEffectMap.insert(EffectMap::value_type(texture, effect));
buildingEffectMap.insert(EffectMap::value_type(*texture, effect));
else
iter->second = effect; // update existing, but empty observer
}
@ -819,27 +819,28 @@ BuildingBoundingBoxCallback::computeBound(const Drawable& drawable) const
// This actually returns a MatrixTransform node. If we rotate the whole
// forest into the local Z-up coordinate system we can reuse the
// primitive building geometry for all the forests of the same type.
osg::Group* createRandomBuildings(SGBuildingBinList buildings, const osg::Matrix& transform,
osg::Group* createRandomBuildings(SGBuildingBinList& buildings, const osg::Matrix& transform,
const SGReaderWriterOptions* options)
{
Matrix transInv = Matrix::inverse(transform);
static Matrix ident;
// Set up some shared structures.
MatrixTransform* mt = new MatrixTransform(transform);
SGBuildingBinList::iterator i;
SGBuildingBin* bin = NULL;
BOOST_FOREACH(bin, buildings)
{
for (i = buildings.begin(); i != buildings.end(); ++i) {
SGBuildingBin* bin = *i;
ref_ptr<Group> group = bin->createBuildingsGroup(transInv, options);
for (size_t i = 0; i < group->getNumChildren(); ++i)
mt->addChild(group->getChild(i));
for (size_t j = 0; j < group->getNumChildren(); ++j) {
mt->addChild(group->getChild(j));
}
delete bin;
}
buildings.clear();
QuadTreeCleaner cleaner;
mt->accept(cleaner);
return mt;

View File

@ -100,9 +100,9 @@ private:
BuildingList mediumBuildings;
BuildingList largeBuildings;
std::string material_name;
std::string texture;
std::string lightMap;
std::string* material_name;
std::string* texture;
std::string* lightMap;
// Fraction of buildings of this type
float smallBuildingFraction;
@ -184,7 +184,7 @@ public:
bool checkMinDist (SGVec3f p, float radius);
std::string getMaterialName() { return material_name; }
std::string* getMaterialName() { return material_name; }
BuildingType getBuildingType(float roll);
@ -313,7 +313,7 @@ public:
typedef std::list<SGBuildingBin*> SGBuildingBinList;
osg::Group* createRandomBuildings(SGBuildingBinList buildinglist, const osg::Matrix& transform,
osg::Group* createRandomBuildings(SGBuildingBinList& buildinglist, const osg::Matrix& transform,
const SGReaderWriterOptions* options);
}
#endif

View File

@ -37,6 +37,7 @@
#include <osg/LOD>
#include <osg/MatrixTransform>
#include <osg/Point>
#include <osg/Referenced>
#include <osg/StateSet>
#include <osg/Switch>
@ -59,6 +60,7 @@
#include <simgear/scene/util/SGNodeMasks.hxx>
#include <simgear/scene/util/QuadTreeBuilder.hxx>
#include <simgear/scene/util/SGReaderWriterOptions.hxx>
#include <simgear/scene/util/OptionsReadFileCallback.hxx>
#include "SGTexturedTriangleBin.hxx"
#include "SGLightBin.hxx"
@ -77,7 +79,8 @@ typedef std::map<std::string,SGTexturedTriangleBin> SGMaterialTriangleMap;
typedef std::list<SGLightBin> SGLightListBin;
typedef std::list<SGDirectionalLightBin> SGDirectionalLightListBin;
struct SGTileGeometryBin {
class SGTileGeometryBin : public osg::Referenced {
public:
SGMaterialTriangleMap materialTriangleMap;
SGLightBin tileLights;
SGLightBin randomTileLights;
@ -486,28 +489,25 @@ struct SGTileGeometryBin {
continue;
osg::Texture2D* object_mask = mat->get_object_mask(triangleBin);
osg::Image* img;
if (object_mask != NULL) {
img = object_mask->getImage();
}
int group_count = mat->get_object_group_count();
float building_coverage = mat->get_building_coverage();
float cos_zero_density_angle = mat->get_cos_object_zero_density_slope_angle();
float cos_max_density_angle = mat->get_cos_object_max_density_slope_angle();
bool found = false;
SGBuildingBin* bin = NULL;
if (building_coverage == 0)
continue;
SGBuildingBin* bin;
if (building_coverage > 0) {
BOOST_FOREACH(bin, randomBuildings)
{
if (bin->getMaterialName() == mat->get_names()[0]) {
found = true;
break;
}
}
if (!found) {
bin = new SGBuildingBin(mat);
randomBuildings.push_back(bin);
}
}
unsigned num = i->second.getNumTriangles();
int random_dropped = 0;
@ -638,8 +638,6 @@ struct SGTileGeometryBin {
(int)object->get_randomized_range_m(&seed),
rotation);
}
n -= 1.0;
}
}
}
@ -678,6 +676,7 @@ struct SGTileGeometryBin {
// Place an object each unit of area
while (num > 1.0) {
num -= 1.0;
// Set the next location to place a building
a += stepv0;
@ -721,7 +720,6 @@ struct SGTileGeometryBin {
} else {
// Fails mask test - try again.
mask_dropped++;
num -= 1.0;
continue;
}
}
@ -744,7 +742,6 @@ struct SGTileGeometryBin {
float edge_dist = *std::min_element(edges, edges + 3);
if (edge_dist < radius) {
num -= 1.0;
triangle_dropped++;
continue;
}
@ -762,7 +759,6 @@ struct SGTileGeometryBin {
}
if (close) {
num -= 1.0;
building_dropped++;
continue;
}
@ -776,7 +772,6 @@ struct SGTileGeometryBin {
}
if (close) {
num -= 1.0;
random_dropped++;
continue;
}
@ -784,7 +779,6 @@ struct SGTileGeometryBin {
std::pair<SGVec3f, float> pt = std::make_pair(buildingCenter, radius);
triangleBuildingList.push_back(pt);
bin->insert(randomPoint, rotation, buildingtype);
num -= 1.0;
}
}
@ -892,22 +886,184 @@ struct GetModelLODCoord {
typedef QuadTreeBuilder<osg::LOD*, ModelLOD, MakeQuadLeaf, AddModelLOD,
GetModelLODCoord> RandomObjectsQuadtree;
osg::Node*
SGLoadBTG(const std::string& path, const simgear::SGReaderWriterOptions* options)
{
SGBinObject tile;
if (!tile.read_bin(path))
return NULL;
class RandomObjectCallback : public OptionsReadFileCallback {
public:
virtual osgDB::ReaderWriter::ReadResult
readNode(const std::string&, const osgDB::Options*)
{
osg::ref_ptr<osg::Group> group = new osg::Group;
group->setName("Random Object and Lighting Group");
group->setDataVariance(osg::Object::STATIC);
SGMaterialLib* matlib = 0;
osg::LOD* lightLOD = generateLightingTileObjects();
if (lightLOD)
group->addChild(lightLOD);
osg::LOD* objectLOD = generateRandomTileObjects();
if (objectLOD)
group->addChild(objectLOD);
return group.release();
}
// Generate all the lighting objects for the tile.
osg::LOD* generateLightingTileObjects()
{
SGMaterialLib* matlib;
if (_options)
matlib = _options->getMaterialLib();
// FIXME: ugly, has a side effect
if (matlib)
_tileGeometryBin->computeRandomSurfaceLights(matlib);
GroundLightManager* lightManager = GroundLightManager::instance();
osg::ref_ptr<osg::Group> lightGroup = new SGOffsetTransform(0.94);
SGVec3f up(0, 0, 1);
if (_tileGeometryBin->tileLights.getNumLights() > 0
|| _tileGeometryBin->randomTileLights.getNumLights() > 0) {
osg::Group* groundLights0 = new osg::Group;
groundLights0->setStateSet(lightManager->getGroundLightStateSet());
groundLights0->setNodeMask(GROUNDLIGHTS0_BIT);
osg::Geode* geode = new osg::Geode;
geode->addDrawable(SGLightFactory::getLights(_tileGeometryBin->tileLights));
geode->addDrawable(SGLightFactory::getLights(_tileGeometryBin->randomTileLights, 4, -0.3f));
groundLights0->addChild(geode);
lightGroup->addChild(groundLights0);
}
if (_tileGeometryBin->randomTileLights.getNumLights() > 0) {
osg::Group* groundLights1 = new osg::Group;
groundLights1->setStateSet(lightManager->getGroundLightStateSet());
groundLights1->setNodeMask(GROUNDLIGHTS1_BIT);
osg::Group* groundLights2 = new osg::Group;
groundLights2->setStateSet(lightManager->getGroundLightStateSet());
groundLights2->setNodeMask(GROUNDLIGHTS2_BIT);
osg::Geode* geode = new osg::Geode;
geode->addDrawable(SGLightFactory::getLights(_tileGeometryBin->randomTileLights, 2, -0.15f));
groundLights1->addChild(geode);
lightGroup->addChild(groundLights1);
geode = new osg::Geode;
geode->addDrawable(SGLightFactory::getLights(_tileGeometryBin->randomTileLights));
groundLights2->addChild(geode);
lightGroup->addChild(groundLights2);
}
if (!_tileGeometryBin->vasiLights.empty()) {
EffectGeode* vasiGeode = new EffectGeode;
Effect* vasiEffect
= getLightEffect(24, osg::Vec3(1, 0.0001, 0.000001), 1, 24, true);
vasiGeode->setEffect(vasiEffect);
SGVec4f red(1, 0, 0, 1);
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 = 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->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(16, osg::Vec3(1, 0.001, 0.0002), 1, 16, true);
if (_tileGeometryBin->runwayLights.getNumLights() > 0
|| !_tileGeometryBin->rabitLights.empty()
|| !_tileGeometryBin->reilLights.empty()
|| !_tileGeometryBin->odalLights.empty()
|| !_tileGeometryBin->holdshortLights.empty()
|| !_tileGeometryBin->guardLights.empty()) {
osg::Group* rwyLights = new osg::Group;
rwyLights->setStateSet(lightManager->getRunwayLightStateSet());
rwyLights->setNodeMask(RUNWAYLIGHTS_BIT);
if (_tileGeometryBin->runwayLights.getNumLights() != 0) {
EffectGeode* geode = new EffectGeode;
geode->setEffect(runwayEffect);
geode->addDrawable(SGLightFactory::getLights(_tileGeometryBin->runwayLights));
rwyLights->addChild(geode);
}
SGDirectionalLightListBin::const_iterator i;
for (i = _tileGeometryBin->rabitLights.begin();
i != _tileGeometryBin->rabitLights.end(); ++i) {
rwyLights->addChild(SGLightFactory::getSequenced(*i));
}
for (i = _tileGeometryBin->reilLights.begin();
i != _tileGeometryBin->reilLights.end(); ++i) {
rwyLights->addChild(SGLightFactory::getSequenced(*i));
}
for (i = _tileGeometryBin->holdshortLights.begin();
i != _tileGeometryBin->holdshortLights.end(); ++i) {
rwyLights->addChild(SGLightFactory::getHoldShort(*i));
}
for (i = _tileGeometryBin->guardLights.begin();
i != _tileGeometryBin->guardLights.end(); ++i) {
rwyLights->addChild(SGLightFactory::getGuard(*i));
}
SGLightListBin::const_iterator j;
for (j = _tileGeometryBin->odalLights.begin();
j != _tileGeometryBin->odalLights.end(); ++j) {
rwyLights->addChild(SGLightFactory::getOdal(*j));
}
lightGroup->addChild(rwyLights);
}
if (_tileGeometryBin->taxiLights.getNumLights() > 0) {
osg::Group* taxiLights = new osg::Group;
taxiLights->setStateSet(lightManager->getTaxiLightStateSet());
taxiLights->setNodeMask(RUNWAYLIGHTS_BIT);
EffectGeode* geode = new EffectGeode;
geode->setEffect(runwayEffect);
geode->addDrawable(SGLightFactory::getLights(_tileGeometryBin->taxiLights));
taxiLights->addChild(geode);
lightGroup->addChild(taxiLights);
}
osg::LOD* lightLOD = NULL;
if (lightGroup->getNumChildren() > 0) {
lightLOD = new osg::LOD;
lightLOD->addChild(lightGroup.get(), 0, 60000);
// VASI is always on, so doesn't use light bits.
lightLOD->setNodeMask(LIGHTS_BITS | MODEL_BIT | PERMANENTLIGHT_BIT);
}
return lightLOD;
}
// Generate all the random forest, objects and buildings for the tile
osg::LOD* generateRandomTileObjects()
{
SGMaterialLib* matlib;
bool use_random_objects = false;
bool use_random_vegetation = false;
bool use_random_buildings = false;
float vegetation_density = 1.0f;
float building_density = 1.0f;
if (options) {
matlib = options->getMaterialLib();
SGPropertyNode* propertyNode = options->getPropertyNode().get();
osg::ref_ptr<osg::Group> randomObjects;
osg::ref_ptr<osg::Group> forestNode;
osg::ref_ptr<osg::Group> buildingNode;
if (_options) {
matlib = _options->getMaterialLib();
SGPropertyNode* propertyNode = _options->getPropertyNode().get();
if (propertyNode) {
use_random_objects
= propertyNode->getBoolValue("/sim/rendering/random-objects",
@ -927,60 +1083,28 @@ SGLoadBTG(const std::string& path, const simgear::SGReaderWriterOptions* options
}
}
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 NULL;
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> forestNode;
osg::ref_ptr<osg::Group> buildingNode;
osg::Group* terrainGroup = new osg::Group;
terrainGroup->setName("BTGTerrainGroup");
osg::Node* node = tileGeometryBin.getSurfaceGeometry(matlib);
if (node)
terrainGroup->addChild(node);
if (matlib && (use_random_objects || use_random_buildings)) {
tileGeometryBin.computeRandomObjectsAndBuildings(matlib,
_tileGeometryBin->computeRandomObjectsAndBuildings(matlib,
building_density,
use_random_objects,
use_random_buildings);
}
if (tileGeometryBin.randomModels.getNumModels() > 0) {
if (_tileGeometryBin->randomModels.getNumModels() > 0) {
// Generate a repeatable random seed
mt seed;
mt_init(&seed, unsigned(123));
std::vector<ModelLOD> models;
for (unsigned int i = 0;
i < tileGeometryBin.randomModels.getNumModels(); i++) {
i < _tileGeometryBin->randomModels.getNumModels(); i++) {
SGMatModelBin::MatModel obj
= tileGeometryBin.randomModels.getMatModel(i);
= _tileGeometryBin->randomModels.getMatModel(i);
SGPropertyNode* root = options->getPropertyNode()->getRootNode();
SGPropertyNode* root = _options->getPropertyNode()->getRootNode();
osg::Node* node = obj.model->get_random_model(root, &seed);
// Create a matrix to place the object in the correct
@ -1005,7 +1129,7 @@ SGLoadBTG(const std::string& path, const simgear::SGReaderWriterOptions* options
osg::MatrixTransform* position =
new osg::MatrixTransform(transformMat);
position->setName("positionRandomeModel");
position->setName("positionRandomModel");
position->addChild(node);
models.push_back(ModelLOD(position, obj.lod));
}
@ -1015,160 +1139,28 @@ SGLoadBTG(const std::string& path, const simgear::SGReaderWriterOptions* options
randomObjects->setName("Random objects");
}
if (! tileGeometryBin.randomBuildings.empty()) {
buildingNode = createRandomBuildings(tileGeometryBin.randomBuildings, osg::Matrix::identity(),
options);
if (! _tileGeometryBin->randomBuildings.empty()) {
buildingNode = createRandomBuildings(_tileGeometryBin->randomBuildings, osg::Matrix::identity(),
_options);
buildingNode->setName("Random buildings");
_tileGeometryBin->randomBuildings.clear();
}
if (use_random_vegetation && matlib) {
// Now add some random forest.
tileGeometryBin.computeRandomForest(matlib, vegetation_density);
_tileGeometryBin->computeRandomForest(matlib, vegetation_density);
if (! tileGeometryBin.randomForest.empty()) {
forestNode = createForest(tileGeometryBin.randomForest, osg::Matrix::identity(),
options);
if (! _tileGeometryBin->randomForest.empty()) {
forestNode = createForest(_tileGeometryBin->randomForest, osg::Matrix::identity(),
_options);
forestNode->setName("Random trees");
}
}
// FIXME: ugly, has a side effect
if (matlib)
tileGeometryBin.computeRandomSurfaceLights(matlib);
if (tileGeometryBin.tileLights.getNumLights() > 0
|| tileGeometryBin.randomTileLights.getNumLights() > 0) {
osg::Group* groundLights0 = new osg::Group;
groundLights0->setStateSet(lightManager->getGroundLightStateSet());
groundLights0->setNodeMask(GROUNDLIGHTS0_BIT);
osg::Geode* geode = new osg::Geode;
geode->addDrawable(SGLightFactory::getLights(tileGeometryBin.tileLights));
geode->addDrawable(SGLightFactory::getLights(tileGeometryBin.randomTileLights, 4, -0.3f));
groundLights0->addChild(geode);
lightGroup->addChild(groundLights0);
}
if (tileGeometryBin.randomTileLights.getNumLights() > 0) {
osg::Group* groundLights1 = new osg::Group;
groundLights1->setStateSet(lightManager->getGroundLightStateSet());
groundLights1->setNodeMask(GROUNDLIGHTS1_BIT);
osg::Group* groundLights2 = new osg::Group;
groundLights2->setStateSet(lightManager->getGroundLightStateSet());
groundLights2->setNodeMask(GROUNDLIGHTS2_BIT);
osg::Geode* geode = new osg::Geode;
geode->addDrawable(SGLightFactory::getLights(tileGeometryBin.randomTileLights, 2, -0.15f));
groundLights1->addChild(geode);
lightGroup->addChild(groundLights1);
geode = new osg::Geode;
geode->addDrawable(SGLightFactory::getLights(tileGeometryBin.randomTileLights));
groundLights2->addChild(geode);
lightGroup->addChild(groundLights2);
}
if (!tileGeometryBin.vasiLights.empty()) {
EffectGeode* vasiGeode = new EffectGeode;
Effect* vasiEffect
= getLightEffect(24, osg::Vec3(1, 0.0001, 0.000001), 1, 24, true);
vasiGeode->setEffect(vasiEffect);
SGVec4f red(1, 0, 0, 1);
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 = 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->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(16, osg::Vec3(1, 0.001, 0.0002), 1, 16, true);
if (tileGeometryBin.runwayLights.getNumLights() > 0
|| !tileGeometryBin.rabitLights.empty()
|| !tileGeometryBin.reilLights.empty()
|| !tileGeometryBin.odalLights.empty()
|| !tileGeometryBin.holdshortLights.empty()
|| !tileGeometryBin.guardLights.empty()) {
osg::Group* rwyLights = new osg::Group;
rwyLights->setStateSet(lightManager->getRunwayLightStateSet());
rwyLights->setNodeMask(RUNWAYLIGHTS_BIT);
if (tileGeometryBin.runwayLights.getNumLights() != 0) {
EffectGeode* geode = new EffectGeode;
geode->setEffect(runwayEffect);
geode->addDrawable(SGLightFactory::getLights(tileGeometryBin
.runwayLights));
rwyLights->addChild(geode);
}
SGDirectionalLightListBin::const_iterator i;
for (i = tileGeometryBin.rabitLights.begin();
i != tileGeometryBin.rabitLights.end(); ++i) {
rwyLights->addChild(SGLightFactory::getSequenced(*i));
}
for (i = tileGeometryBin.reilLights.begin();
i != tileGeometryBin.reilLights.end(); ++i) {
rwyLights->addChild(SGLightFactory::getSequenced(*i));
}
for (i = tileGeometryBin.holdshortLights.begin();
i != tileGeometryBin.holdshortLights.end(); ++i) {
rwyLights->addChild(SGLightFactory::getHoldShort(*i));
}
for (i = tileGeometryBin.guardLights.begin();
i != tileGeometryBin.guardLights.end(); ++i) {
rwyLights->addChild(SGLightFactory::getGuard(*i));
}
SGLightListBin::const_iterator j;
for (j = tileGeometryBin.odalLights.begin();
j != tileGeometryBin.odalLights.end(); ++j) {
rwyLights->addChild(SGLightFactory::getOdal(*j));
}
lightGroup->addChild(rwyLights);
}
if (tileGeometryBin.taxiLights.getNumLights() > 0) {
osg::Group* taxiLights = new osg::Group;
taxiLights->setStateSet(lightManager->getTaxiLightStateSet());
taxiLights->setNodeMask(RUNWAYLIGHTS_BIT);
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::rotate(toOsg(hlOr))*
osg::Matrix::translate(toOsg(center)));
transform->addChild(terrainGroup);
if (lightGroup->getNumChildren() > 0) {
osg::LOD* lightLOD = new osg::LOD;
lightLOD->addChild(lightGroup.get(), 0, 60000);
// VASI is always on, so doesn't use light bits.
lightLOD->setNodeMask(LIGHTS_BITS | MODEL_BIT | PERMANENTLIGHT_BIT);
transform->addChild(lightLOD);
}
osg::LOD* objectLOD = NULL;
if (randomObjects.valid() || forestNode.valid() || buildingNode.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;
objectLOD = new osg::LOD;
if (randomObjects.valid()) objectLOD->addChild(randomObjects.get(), 0, 20000);
if (forestNode.valid()) objectLOD->addChild(forestNode.get(), 0, 20000);
@ -1176,8 +1168,83 @@ SGLoadBTG(const std::string& path, const simgear::SGReaderWriterOptions* options
unsigned nodeMask = SG_NODEMASK_CASTSHADOW_BIT | SG_NODEMASK_RECEIVESHADOW_BIT | SG_NODEMASK_TERRAIN_BIT;
objectLOD->setNodeMask(nodeMask);
transform->addChild(objectLOD);
}
return objectLOD;
}
/// The original options to use for this bunch of models
osg::ref_ptr<SGReaderWriterOptions> _options;
osg::ref_ptr<SGTileGeometryBin> _tileGeometryBin;
};
osg::Node*
SGLoadBTG(const std::string& path, const simgear::SGReaderWriterOptions* options)
{
SGBinObject tile;
if (!tile.read_bin(path))
return NULL;
SGMaterialLib* matlib = 0;
if (options) {
matlib = options->getMaterialLib();
}
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);
osg::ref_ptr<SGTileGeometryBin> tileGeometryBin = new SGTileGeometryBin;
if (!tileGeometryBin->insertBinObj(tile, matlib))
return NULL;
osg::Group* terrainGroup = new osg::Group;
terrainGroup->setName("BTGTerrainGroup");
osg::Node* node = tileGeometryBin->getSurfaceGeometry(matlib);
if (node)
terrainGroup->addChild(node);
// The toplevel transform for that tile.
osg::MatrixTransform* transform = new osg::MatrixTransform;
transform->setName(path);
transform->setMatrix(osg::Matrix::rotate(toOsg(hlOr))*
osg::Matrix::translate(toOsg(center)));
transform->addChild(terrainGroup);
// PagedLOD for the random objects so we don't need to generate
// them all on tile loading.
osg::PagedLOD* pagedLOD = new osg::PagedLOD;
pagedLOD->setCenterMode(osg::PagedLOD::USE_BOUNDING_SPHERE_CENTER);
pagedLOD->setName("pagedObjectLOD");
// we just need to know about the read file callback that itself holds the data
osg::ref_ptr<RandomObjectCallback> randomObjectCallback = new RandomObjectCallback;
randomObjectCallback->_options = SGReaderWriterOptions::copyOrCreate(options);
randomObjectCallback->_tileGeometryBin = tileGeometryBin;
osg::ref_ptr<osgDB::Options> callbackOptions = new osgDB::Options;
callbackOptions->setReadFileCallback(randomObjectCallback.get());
pagedLOD->setDatabaseOptions(callbackOptions.get());
pagedLOD->setFileName(pagedLOD->getNumChildren(), "Dummy name - use the stored data in the read file callback");
pagedLOD->setRange(pagedLOD->getNumChildren(), 0, 35000);
transform->addChild(pagedLOD);
transform->setNodeMask( ~simgear::MODELLIGHT_BIT );
return transform;