namespace simgear
{
-
+
typedef std::map<std::string, osg::observer_ptr<osg::StateSet> > BuildingStateSetMap;
static BuildingStateSetMap statesetmap;
typedef std::map<std::string, osg::observer_ptr<Effect> > EffectMap;
static EffectMap buildingEffectMap;
-
+
// Building instance scheme:
// vertex - local position of vertices, with 0,0,0 being the center front.
// fog coord - rotation
const Geometry* geom = static_cast<const Geometry*>(&drawable);
const Vec3Array* v = static_cast<const Vec3Array*>(geom->getVertexArray());
const Vec4Array* pos = static_cast<const Vec4Array*>(geom->getColorArray());
-
+
Geometry::PrimitiveSetList primSets = geom->getPrimitiveSetList();
for (Geometry::PrimitiveSetList::const_iterator psitr = primSets.begin(), psend = primSets.end();
psitr != psend;
bb.expandBy(pt);
}
}
- return bb;
+ return bb;
}
// 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.
mt seed;
mt_init(&seed, unsigned(123));
-
+
smallSharedGeometry = new osg::Geometry();
mediumSharedGeometry = new osg::Geometry();
largeSharedGeometry = new osg::Geometry();
-
+
smallBuildingMaxRadius = std::max(mat->get_building_small_max_depth() * 0.5, mat->get_building_small_max_width() * 0.5);
mediumBuildingMaxRadius = std::max(mat->get_building_medium_max_depth() * 0.5, mat->get_building_medium_max_width() * 0.5);
largeBuildingMaxRadius = std::max(mat->get_building_large_max_depth() * 0.5, mat->get_building_large_max_width() * 0.5);
-
+
smallBuildingMaxDepth = mat->get_building_small_max_depth();
mediumBuildingMaxDepth = mat->get_building_medium_max_depth();
- largeBuildingMaxDepth = mat->get_building_large_max_depth();
-
+ largeBuildingMaxDepth = mat->get_building_large_max_depth();
+
smallBuildingFraction = mat->get_building_small_fraction();
mediumBuildingFraction = mat->get_building_medium_fraction();
-
+
buildingRange = mat->get_building_range();
-
+
SG_LOG(SG_TERRAIN, SG_DEBUG, "Building fractions " << smallBuildingFraction << " " << mediumBuildingFraction);
-
-
+
+
// TODO: Reverse this - otherwise we never get any large buildings!
- BuildingType types[] = { SGBuildingBin::SMALL, SGBuildingBin::MEDIUM, SGBuildingBin::LARGE };
+ BuildingType types[] = { SGBuildingBin::SMALL, SGBuildingBin::MEDIUM, SGBuildingBin::LARGE };
BuildingList lists[] = { SGBuildingBin::smallBuildings, SGBuildingBin::mediumBuildings, SGBuildingBin::largeBuildings };
ref_ptr<Geometry> geometries[] = { smallSharedGeometry, mediumSharedGeometry, largeSharedGeometry };
-
+
for (int bt=0; bt < 3; bt++) {
SGBuildingBin::BuildingType buildingtype = types[bt];
ref_ptr<Geometry> sharedGeometry = geometries[bt];
BuildingList buildings = lists[bt];
-
+
osg::ref_ptr<osg::Vec3Array> v = new osg::Vec3Array;
osg::ref_ptr<osg::Vec2Array> t = new osg::Vec2Array;
osg::ref_ptr<osg::Vec3Array> n = new osg::Vec3Array;
-
+
v->reserve(BUILDING_SET_SIZE * VERTICES_PER_BUILDING);
t->reserve(BUILDING_SET_SIZE * VERTICES_PER_BUILDING);
n->reserve(BUILDING_SET_SIZE * VERTICES_PER_BUILDING);
-
+
sharedGeometry->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
sharedGeometry->setFogCoordBinding(osg::Geometry::BIND_PER_VERTEX);
sharedGeometry->setComputeBoundingBoxCallback(new BuildingBoundingBoxCallback);
sharedGeometry->setUseDisplayList(false);
-
- for (unsigned int j = 0; j < BUILDING_SET_SIZE; j++) {
+
+ for (unsigned int j = 0; j < BUILDING_SET_SIZE; j++) {
float width;
float depth;
int floors;
float height;
bool pitched;
-
+
if (buildingtype == SGBuildingBin::SMALL) {
// Small building
width = mat->get_building_small_min_width() + mt_rand(&seed) * mt_rand(&seed) * (mat->get_building_small_max_width() - mat->get_building_small_min_width());
depth = mat->get_building_small_min_depth() + mt_rand(&seed) * mt_rand(&seed) * (mat->get_building_small_max_depth() - mat->get_building_small_min_depth());
floors = SGMisc<double>::round(mat->get_building_small_min_floors() + mt_rand(&seed) * (mat->get_building_small_max_floors() - mat->get_building_small_min_floors()));
height = floors * (2.8 + mt_rand(&seed));
-
+
// Small buildings are never deeper than they are wide.
if (depth > width) { depth = width; }
-
+
pitched = (mt_rand(&seed) < mat->get_building_small_pitch());
} else if (buildingtype == SGBuildingBin::MEDIUM) {
width = mat->get_building_medium_min_width() + mt_rand(&seed) * mt_rand(&seed) * (mat->get_building_medium_max_width() - mat->get_building_medium_min_width());
depth = mat->get_building_medium_min_depth() + mt_rand(&seed) * mt_rand(&seed) * (mat->get_building_medium_max_depth() - mat->get_building_medium_min_depth());
floors = SGMisc<double>::round(mat->get_building_medium_min_floors() + mt_rand(&seed) * (mat->get_building_medium_max_floors() - mat->get_building_medium_min_floors()));
height = floors * (2.8 + mt_rand(&seed));
-
+
while ((height > width) && (floors > mat->get_building_medium_min_floors())) {
// Ensure that medium buildings aren't taller than they are wide
floors--;
- height = floors * (2.8 + mt_rand(&seed));
+ height = floors * (2.8 + mt_rand(&seed));
}
-
- pitched = (mt_rand(&seed) < mat->get_building_medium_pitch());
+
+ pitched = (mt_rand(&seed) < mat->get_building_medium_pitch());
} else {
width = mat->get_building_large_min_width() + mt_rand(&seed) * (mat->get_building_large_max_width() - mat->get_building_large_min_width());
depth = mat->get_building_large_min_depth() + mt_rand(&seed) * (mat->get_building_large_max_depth() - mat->get_building_large_min_depth());
- floors = SGMisc<double>::round(mat->get_building_large_min_floors() + mt_rand(&seed) * (mat->get_building_large_max_floors() - mat->get_building_large_min_floors()));
+ floors = SGMisc<double>::round(mat->get_building_large_min_floors() + mt_rand(&seed) * (mat->get_building_large_max_floors() - mat->get_building_large_min_floors()));
height = floors * (2.8 + mt_rand(&seed));
- pitched = (mt_rand(&seed) < mat->get_building_large_pitch());
+ pitched = (mt_rand(&seed) < mat->get_building_large_pitch());
}
-
- Building building = Building(buildingtype,
- width,
- depth,
- height,
+
+ Building building = Building(buildingtype,
+ width,
+ depth,
+ height,
floors,
- pitched);
-
+ pitched);
+
buildings.push_back(building);
// Now create an OSG Geometry based on the Building
float cw = 0.5f * building.width;
float cd = building.depth;
float ch = building.height;
-
+
// 0,0,0 is the bottom center of the front
- // face, e.g. where the front door would be
-
+ // face, e.g. where the front door would be
+
// BASEMENT
// This exteds 10m below the main section
- // Front face
+ // Front face
v->push_back( osg::Vec3( 0, -cw, -10) ); // bottom right
v->push_back( osg::Vec3( 0, cw, -10) ); // bottom left
v->push_back( osg::Vec3( 0, cw, 0) ); // top left
v->push_back( osg::Vec3( 0, -cw, 0) ); // top right
-
+
for (int i=0; i<4; ++i)
n->push_back( osg::Vec3(1, 0, 0) ); // normal
-
+
// Left face
v->push_back( osg::Vec3( -cd, -cw, -10) ); // bottom right
v->push_back( osg::Vec3( 0, -cw, -10) ); // bottom left
v->push_back( osg::Vec3( -cd, -cw, -10) ); // bottom left
v->push_back( osg::Vec3( -cd, -cw, 0) ); // top left
v->push_back( osg::Vec3( -cd, cw, 0) ); // top right
-
+
for (int i=0; i<4; ++i)
n->push_back( osg::Vec3(-1, 0, 0) ); // normal
-
+
// Right face
v->push_back( osg::Vec3( 0, cw, -10) ); // bottom right
v->push_back( osg::Vec3( -cd, cw, -10) ); // bottom left
v->push_back( osg::Vec3( 0, cw, 0) ); // top right
for (int i=0; i<4; ++i)
- n->push_back( osg::Vec3(0, 1, 0) ); // normal
-
+ n->push_back( osg::Vec3(0, 1, 0) ); // normal
+
// MAIN BODY
- // Front face
+ // Front face
v->push_back( osg::Vec3( 0, -cw, 0) ); // bottom right
v->push_back( osg::Vec3( 0, cw, 0) ); // bottom left
v->push_back( osg::Vec3( 0, cw, ch) ); // top left
v->push_back( osg::Vec3( 0, -cw, ch) ); // top right
-
+
for (int i=0; i<4; ++i)
n->push_back( osg::Vec3(1, 0, 0) ); // normal
-
+
// Left face
v->push_back( osg::Vec3( -cd, -cw, 0) ); // bottom right
v->push_back( osg::Vec3( 0, -cw, 0) ); // bottom left
v->push_back( osg::Vec3( -cd, -cw, 0) ); // bottom left
v->push_back( osg::Vec3( -cd, -cw, ch) ); // top left
v->push_back( osg::Vec3( -cd, cw, ch) ); // top right
-
+
for (int i=0; i<4; ++i)
n->push_back( osg::Vec3(-1, 0, 0) ); // normal
-
+
// Right face
v->push_back( osg::Vec3( 0, cw, 0) ); // bottom right
v->push_back( osg::Vec3( -cd, cw, 0) ); // bottom left
for (int i=0; i<4; ++i)
n->push_back( osg::Vec3(0, 1, 0) ); // normal
-
+
// ROOF
- if (building.pitched) {
-
+ if (building.pitched) {
+
// Front pitched roof
v->push_back( osg::Vec3( 0, -cw, ch) ); // bottom right
v->push_back( osg::Vec3( 0, cw, ch) ); // bottom left
v->push_back( osg::Vec3(-0.5*cd, cw, ch+3) ); // top left
v->push_back( osg::Vec3(-0.5*cd, -cw, ch+3) ); // top right
-
+
for (int i=0; i<4; ++i)
n->push_back( osg::Vec3(0.707, 0, 0.707) ); // normal
-
+
// Left pitched roof
v->push_back( osg::Vec3( -cd, -cw, ch) ); // bottom right
v->push_back( osg::Vec3( 0, -cw, ch) ); // bottom left
v->push_back( osg::Vec3(-0.5*cd, -cw, ch+3) ); // top left
v->push_back( osg::Vec3(-0.5*cd, -cw, ch+3) ); // top right
-
+
for (int i=0; i<4; ++i)
n->push_back( osg::Vec3(0, -1, 0) ); // normal
v->push_back( osg::Vec3( -cd, -cw, ch) ); // bottom left
v->push_back( osg::Vec3(-0.5*cd, -cw, ch+3) ); // top left
v->push_back( osg::Vec3(-0.5*cd, cw, ch+3) ); // top right
-
+
for (int i=0; i<4; ++i)
- n->push_back( osg::Vec3(-0.707, 0, 0.707) ); // normal
+ n->push_back( osg::Vec3(-0.707, 0, 0.707) ); // normal
// Right pitched roof
v->push_back( osg::Vec3( 0, cw, ch) ); // bottom right
v->push_back( osg::Vec3( -cd, cw, ch) ); // bottom left
v->push_back( osg::Vec3(-0.5*cd, cw, ch+3) ); // top left
v->push_back( osg::Vec3(-0.5*cd, cw, ch+3) ); // top right
-
+
for (int i=0; i<4; ++i)
n->push_back( osg::Vec3(0, 1, 0) ); // normal
- } else {
- // If the roof isn't pitched, we still generate the
+ } else {
+ // If the roof isn't pitched, we still generate the
// vertices for simplicity later.
-
+
// Top of the roof
v->push_back( osg::Vec3( 0, -cw, ch) ); // bottom right
v->push_back( osg::Vec3( 0, cw, ch) ); // bottom left
v->push_back( osg::Vec3(-cd, cw, ch) ); // top left
v->push_back( osg::Vec3(-cd, -cw, ch) ); // top right
-
+
for (int i=0; i<4; ++i)
n->push_back( osg::Vec3(0, 0, 1) ); // normal
-
+
// Left non-pitched roof
v->push_back( osg::Vec3( -cd, -cw, ch) ); // bottom right
v->push_back( osg::Vec3( 0, -cw, ch) ); // bottom left
v->push_back( osg::Vec3( 0, -cw, ch) ); // top left
v->push_back( osg::Vec3( -cd, -cw, ch) ); // top right
-
+
for (int i=0; i<4; ++i)
n->push_back( osg::Vec3(0, -1, 0) ); // normal
v->push_back( osg::Vec3(-cd, -cw, ch) ); // bottom left
v->push_back( osg::Vec3(-cd, -cw, ch) ); // top left
v->push_back( osg::Vec3(-cd, cw, ch) ); // top right
-
+
for (int i=0; i<4; ++i)
- n->push_back( osg::Vec3(1, 0, 0) ); // normal
+ n->push_back( osg::Vec3(1, 0, 0) ); // normal
// Right pitched roof
v->push_back( osg::Vec3( 0, cw, ch) ); // bottom right
v->push_back( osg::Vec3(-cd, cw, ch) ); // bottom left
v->push_back( osg::Vec3(-cd, cw, ch) ); // top left
v->push_back( osg::Vec3( 0, cw, ch) ); // top right
-
+
for (int i=0; i<4; ++i)
n->push_back( osg::Vec3(0, 1, 0) ); // normal
}
-
+
// The 1024x1024 texture is split into 32x16 blocks.
// For a small building, each block is 6m wide and 3m high.
// For a medium building, each block is 10m wide and 3m high.
// For a large building, each block is 20m wide and 3m high
-
+
if (building.type == SGBuildingBin::SMALL) {
// Small buildings are represented on the bottom 5 rows of 3 floors
int row = ((int) (mt_rand(&seed) * 1000)) % 5;
float back_x = 384.0/1024.0 + 32.0 / 1024.0 * round((float) building.depth/ 6.0f);
// BASEMENT - uses the baseline texture
- for (unsigned int i = 0; i < 16; i++) {
- t->push_back( osg::Vec2( left_x, base_y) );
+ for (unsigned int i = 0; i < 16; i++) {
+ t->push_back( osg::Vec2( left_x, base_y) );
}
// MAIN BODY
// Front
t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
t->push_back( osg::Vec2( left_x, top_y ) ); // top left
t->push_back( osg::Vec2( right_x, top_y ) ); // top right
-
+
// Left
t->push_back( osg::Vec2( front_x, base_y) ); // bottom right
t->push_back( osg::Vec2( back_x, base_y) ); // bottom left
t->push_back( osg::Vec2( back_x, top_y ) ); // top left
t->push_back( osg::Vec2( front_x, top_y ) ); // top right
-
+
// Back (same as front for the moment)
t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
t->push_back( osg::Vec2( left_x, top_y ) ); // top left
t->push_back( osg::Vec2( right_x, top_y ) ); // top right
-
+
// Right (same as left for the moment)
t->push_back( osg::Vec2( front_x, base_y) ); // bottom right
t->push_back( osg::Vec2( back_x, base_y) ); // bottom left
t->push_back( osg::Vec2( front_x, top_y ) ); // top right
// ROOF
- if (building.pitched) {
+ if (building.pitched) {
// Use the entire height of the roof texture
- top_y = base_y + 16.0 * 3.0 / 1024.0;
+ top_y = base_y + 16.0 * 3.0 / 1024.0;
left_x = 512/1024.0 + 32.0 / 1024.0 * round(building.width / 6.0f);
right_x = 512/1024.0;
front_x = 480.0/1024.0;
back_x = 512.0/1024.0;
-
+
// Front
t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
t->push_back( osg::Vec2( left_x, top_y ) ); // top left
t->push_back( osg::Vec2( right_x, top_y ) ); // top right
-
+
// Left
t->push_back( osg::Vec2( front_x, base_y) ); // bottom right
t->push_back( osg::Vec2( back_x, base_y) ); // bottom left
t->push_back( osg::Vec2( back_x, top_y ) ); // top left
t->push_back( osg::Vec2( front_x, top_y ) ); // top right
-
+
// Back (same as front for the moment)
t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
t->push_back( osg::Vec2( left_x, top_y ) ); // top left
t->push_back( osg::Vec2( right_x, top_y ) ); // top right
-
+
// Right (same as left for the moment)
t->push_back( osg::Vec2( front_x, base_y) ); // bottom right
t->push_back( osg::Vec2( back_x, base_y) ); // bottom left
left_x = 640.0/1024.0;
right_x = 512.0/1024.0;
// Use the entire height of the roof texture
- top_y = base_y + 16.0 * 3.0 / 1024.0;
-
+ top_y = base_y + 16.0 * 3.0 / 1024.0;
+
// Flat roofs still have 4 surfaces, so we need to set the textures
- for (int i=0; i<4; ++i) {
+ for (int i=0; i<4; ++i) {
t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
t->push_back( osg::Vec2( left_x, top_y ) ); // top left
t->push_back( osg::Vec2( right_x, top_y ) ); // top right
}
}
-
+
}
-
- if (building.type == SGBuildingBin::MEDIUM)
+
+ if (building.type == SGBuildingBin::MEDIUM)
{
- int column = ((int) (mt_rand(&seed) * 1000)) % 5;
+ int column = ((int) (mt_rand(&seed) * 1000)) % 5;
float base_y = 288 / 1024.0;
float top_y = base_y + 16.0 * (float) building.floors / 1024.0;
float left_x = column * 192.0 /1024.0 + 32.0 / 1024.0 * round((float) building.width / 10.0f);
float right_x = column * 192.0 /1024.0;
// BASEMENT - uses the baseline texture
- for (unsigned int i = 0; i < 16; i++) {
- t->push_back( osg::Vec2( left_x, base_y) );
- }
+ for (unsigned int i = 0; i < 16; i++) {
+ t->push_back( osg::Vec2( left_x, base_y) );
+ }
// MAIN BODY
// Front
t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
t->push_back( osg::Vec2( left_x, top_y ) ); // top left
t->push_back( osg::Vec2( right_x, top_y ) ); // top right
-
+
// Left
t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
t->push_back( osg::Vec2( left_x, top_y ) ); // top left
t->push_back( osg::Vec2( right_x, top_y ) ); // top right
-
+
// Back (same as front for the moment)
t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
t->push_back( osg::Vec2( left_x, top_y ) ); // top left
t->push_back( osg::Vec2( right_x, top_y ) ); // top right
-
+
// Right (same as left for the moment)
t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
t->push_back( osg::Vec2( right_x, top_y ) ); // top right
// ROOF
- if (building.pitched) {
+ if (building.pitched) {
base_y = 288.0/1024.0;
top_y = 576.0/1024.0;
left_x = 960.0/1024.0;
right_x = 1.0;
-
+
// Front
t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
t->push_back( osg::Vec2( left_x, top_y ) ); // top left
t->push_back( osg::Vec2( right_x, top_y ) ); // top right
-
+
// Left
t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
t->push_back( osg::Vec2( left_x, top_y ) ); // top left
t->push_back( osg::Vec2( right_x, top_y ) ); // top right
-
+
// Back (same as front for the moment)
t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
t->push_back( osg::Vec2( left_x, top_y ) ); // top left
t->push_back( osg::Vec2( right_x, top_y ) ); // top right
-
+
// Right (same as left for the moment)
t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
top_y = 576.0/1024.0;
left_x = column * 192.0 /1024.0;
right_x = (column + 1)* 192.0 /1024.0;
-
+
// Flat roofs still have 4 surfaces
- for (int i=0; i<4; ++i) {
+ for (int i=0; i<4; ++i) {
t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
t->push_back( osg::Vec2( left_x, top_y ) ); // top left
if (building.type == SGBuildingBin::LARGE)
{
- int column = ((int) (mt_rand(&seed) * 1000)) % 8;
+ int column = ((int) (mt_rand(&seed) * 1000)) % 8;
float base_y = 576 / 1024.0;
float top_y = base_y + 16.0 * (float) building.floors / 1024.0;
float left_x = column * 128.0 /1024.0 + 32.0 / 1024.0 * round((float) building.width / 20.0f);
- float right_x = column * 128.0 /1024.0;
+ float right_x = column * 128.0 /1024.0;
// BASEMENT - uses the baseline texture
- for (unsigned int i = 0; i < 16; i++) {
- t->push_back( osg::Vec2( left_x, base_y) );
- }
+ for (unsigned int i = 0; i < 16; i++) {
+ t->push_back( osg::Vec2( left_x, base_y) );
+ }
// MAIN BODY
// Front
t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
t->push_back( osg::Vec2( left_x, top_y ) ); // top left
t->push_back( osg::Vec2( right_x, top_y ) ); // top right
-
+
// Left
t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
t->push_back( osg::Vec2( left_x, top_y ) ); // top left
t->push_back( osg::Vec2( right_x, top_y ) ); // top right
-
+
// Back (same as front for the moment)
t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
t->push_back( osg::Vec2( left_x, top_y ) ); // top left
t->push_back( osg::Vec2( right_x, top_y ) ); // top right
-
+
// Right (same as left for the moment)
t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
t->push_back( osg::Vec2( right_x, top_y ) ); // top right
// ROOF
- if (building.pitched) {
+ if (building.pitched) {
base_y = 896/1024.0;
top_y = 1.0;
// Front
t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
t->push_back( osg::Vec2( left_x, top_y ) ); // top left
t->push_back( osg::Vec2( right_x, top_y ) ); // top right
-
+
// Left
t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
t->push_back( osg::Vec2( left_x, top_y ) ); // top left
t->push_back( osg::Vec2( right_x, top_y ) ); // top right
-
+
// Back (same as front for the moment)
t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
t->push_back( osg::Vec2( left_x, top_y ) ); // top left
t->push_back( osg::Vec2( right_x, top_y ) ); // top right
-
+
// Right (same as left for the moment)
t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
// Flat roof
base_y = 896/1024.0;
top_y = 1.0;
-
+
// Flat roofs still have 4 surfaces
- for (int i=0; i<4; ++i) {
+ for (int i=0; i<4; ++i) {
t->push_back( osg::Vec2( right_x, base_y) ); // bottom right
t->push_back( osg::Vec2( left_x, base_y) ); // bottom left
t->push_back( osg::Vec2( left_x, top_y ) ); // top left
}
}
}
-
+
// Set the vertex, texture and normals. Colors will be set per-instance
// later.
sharedGeometry->setVertexArray(v);
sharedGeometry->setNormalArray(n);
}
}
-
- void SGBuildingBin::insert(SGVec3f p, float r, BuildingType type) {
-
+
+ void SGBuildingBin::insert(SGVec3f p, float r, BuildingType type) {
+
if (type == SGBuildingBin::SMALL) {
- smallBuildingLocations.push_back(BuildingInstance(p, r, &smallBuildings, smallSharedGeometry));
+ smallBuildingLocations.push_back(BuildingInstance(p, r, &smallBuildings, smallSharedGeometry));
}
-
+
if (type == SGBuildingBin::MEDIUM) {
- mediumBuildingLocations.push_back(BuildingInstance(p, r, &mediumBuildings, mediumSharedGeometry));
+ mediumBuildingLocations.push_back(BuildingInstance(p, r, &mediumBuildings, mediumSharedGeometry));
}
if (type == SGBuildingBin::LARGE) {
- largeBuildingLocations.push_back(BuildingInstance(p, r, &largeBuildings, largeSharedGeometry));
- }
+ largeBuildingLocations.push_back(BuildingInstance(p, r, &largeBuildings, largeSharedGeometry));
+ }
}
int SGBuildingBin::getNumBuildings() {
- return smallBuildingLocations.size() + mediumBuildingLocations.size() + largeBuildingLocations.size();
+ return smallBuildingLocations.size() + mediumBuildingLocations.size() + largeBuildingLocations.size();
}
-
- bool SGBuildingBin::checkMinDist (SGVec3f p, float radius) {
+
+ bool SGBuildingBin::checkMinDist (SGVec3f p, float radius) {
BuildingInstanceList::iterator iter;
-
+
float r = (radius + smallBuildingMaxRadius) * (radius + smallBuildingMaxRadius);
for (iter = smallBuildingLocations.begin(); iter != smallBuildingLocations.end(); ++iter) {
if (iter->getDistSqr(p) < r) {
- return false;
- }
+ return false;
+ }
}
-
+
r = (radius + mediumBuildingMaxRadius) * (radius + mediumBuildingMaxRadius);
for (iter = mediumBuildingLocations.begin(); iter != mediumBuildingLocations.end(); ++iter) {
if (iter->getDistSqr(p) < r) {
- return false;
- }
+ return false;
+ }
}
-
+
r = (radius + largeBuildingMaxRadius) * (radius + largeBuildingMaxRadius);
for (iter = largeBuildingLocations.begin(); iter != largeBuildingLocations.end(); ++iter) {
if (iter->getDistSqr(p) < r) {
- return false;
- }
+ return false;
+ }
}
-
+
return true;
}
-
+
SGBuildingBin::BuildingType SGBuildingBin::getBuildingType(float roll) {
-
+
if (roll < smallBuildingFraction) {
- return SGBuildingBin::SMALL;
+ return SGBuildingBin::SMALL;
}
-
+
if (roll < (smallBuildingFraction + mediumBuildingFraction)) {
return SGBuildingBin::MEDIUM;
}
-
- return SGBuildingBin::LARGE;
+
+ return SGBuildingBin::LARGE;
}
float SGBuildingBin::getBuildingMaxRadius(BuildingType type) {
-
+
if (type == SGBuildingBin::SMALL) return smallBuildingMaxRadius;
if (type == SGBuildingBin::MEDIUM) return mediumBuildingMaxRadius;
if (type == SGBuildingBin::LARGE) return largeBuildingMaxRadius;
-
+
return 0;
}
-
+
float SGBuildingBin::getBuildingMaxDepth(BuildingType type) {
-
+
if (type == SGBuildingBin::SMALL) return smallBuildingMaxDepth;
if (type == SGBuildingBin::MEDIUM) return mediumBuildingMaxDepth;
if (type == SGBuildingBin::LARGE) return largeBuildingMaxDepth;
-
+
return 0;
}
-
+
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)))
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
}
-
+
ref_ptr<Group> group = new osg::Group();
-
- // Now, create a quadbuilding for the buildings.
-
- BuildingInstanceList locs[] = { smallBuildingLocations,
- SGBuildingBin::mediumBuildingLocations,
+
+ // Now, create a quadbuilding for the buildings.
+
+ BuildingInstanceList locs[] = { smallBuildingLocations,
+ SGBuildingBin::mediumBuildingLocations,
SGBuildingBin::largeBuildingLocations };
-
+
for (int i = 0; i < 3; i++)
{
// Create a quad tree. Only small and medium buildings are faded out.
quadbuilding(GetBuildingCoord(), AddBuildingLeafObject(),
SG_BUILDING_QUAD_TREE_DEPTH,
MakeBuildingLeaf(buildingRange, effect, (i != 2)));
-
+
// Transform building positions from the "geocentric" positions we
// get from the scenery polys into the local Z-up coordinate
// system.
for (size_t j = 0; j < quadbuilding.getRoot()->getNumChildren(); ++j)
group->addChild(quadbuilding.getRoot()->getChild(j));
}
-
+
return group;
}
-
+
// We may end up with a quadtree with many empty leaves. One might say
// that we should avoid constructing the leaves in the first place,
// but this node visitor tries to clean up after the fact.
struct QuadTreeCleaner : public osg::NodeVisitor
- {
+ {
QuadTreeCleaner() : NodeVisitor(NodeVisitor::TRAVERSE_ALL_CHILDREN)
{
}
}
}
};
-
+
// 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));
-
- delete bin;
- }
-
+
+ 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;
#include <osg/LOD>
#include <osg/MatrixTransform>
#include <osg/Point>
+#include <osg/Referenced>
#include <osg/StateSet>
#include <osg/Switch>
#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"
typedef std::list<SGLightBin> SGLightListBin;
typedef std::list<SGDirectionalLightBin> SGDirectionalLightListBin;
-struct SGTileGeometryBin {
+class SGTileGeometryBin : public osg::Referenced {
+public:
SGMaterialTriangleMap materialTriangleMap;
SGLightBin tileLights;
SGLightBin randomTileLights;
triangles.insert(v0, v1, v2);
}
}
-
+
static void
addFanGeometry(SGTexturedTriangleBin& triangles,
const std::vector<SGVec3d>& vertices,
void computeRandomSurfaceLights(SGMaterialLib* matlib)
{
SGMaterialTriangleMap::iterator i;
-
+
// generate a repeatable random seed
mt seed;
mt_init(&seed, unsigned(123));
-
+
for (i = materialTriangleMap.begin(); i != materialTriangleMap.end(); ++i) {
SGMaterial *mat = matlib->find(i->first);
if (!mat)
<< coverage << ", pushing up to 10000");
coverage = 10000;
}
-
+
std::vector<SGVec3f> randomPoints;
i->second.addRandomSurfacePoints(coverage, 3, mat->get_object_mask(i->second), randomPoints);
std::vector<SGVec3f>::iterator j;
}
}
}
-
+
void computeRandomObjectsAndBuildings(
- SGMaterialLib* matlib,
- float building_density,
- bool use_random_objects,
+ SGMaterialLib* matlib,
+ float building_density,
+ bool use_random_objects,
bool use_random_buildings)
{
SGMaterialTriangleMap::iterator i;
-
+
// generate a repeatable random seed
mt seed;
mt_init(&seed, unsigned(123));
-
+
for (i = materialTriangleMap.begin(); i != materialTriangleMap.end(); ++i) {
SGMaterial *mat = matlib->find(i->first);
SGTexturedTriangleBin triangleBin = i->second;
-
+
if (!mat)
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 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) {
- BOOST_FOREACH(bin, randomBuildings)
- {
- if (bin->getMaterialName() == mat->get_names()[0]) {
- found = true;
- break;
- }
- }
-
- if (!found) {
- bin = new SGBuildingBin(mat);
- randomBuildings.push_back(bin);
- }
- }
-
+
+ if (building_coverage == 0)
+ continue;
+
+ SGBuildingBin* bin;
+
+ if (building_coverage > 0) {
+ bin = new SGBuildingBin(mat);
+ randomBuildings.push_back(bin);
+ }
+
unsigned num = i->second.getNumTriangles();
int random_dropped = 0;
int mask_dropped = 0;
for (unsigned i = 0; i < num; ++i) {
SGTexturedTriangleBin::triangle_ref triangleRef = triangleBin.getTriangleRef(i);
-
+
SGVec3f vorigin = triangleBin.getVertex(triangleRef[0]).vertex;
SGVec3f v0 = triangleBin.getVertex(triangleRef[1]).vertex - vorigin;
SGVec3f v1 = triangleBin.getVertex(triangleRef[2]).vertex - vorigin;
SGVec2f t0 = triangleBin.getVertex(triangleRef[1]).texCoord - torigin;
SGVec2f t1 = triangleBin.getVertex(triangleRef[2]).texCoord - torigin;
SGVec3f normal = cross(v0, v1);
-
+
// Ensure the slope isn't too steep by checking the
// cos of the angle between the slope normal and the
// vertical (conveniently the z-component of the normalized
- // normal) and values passed in.
+ // normal) and values passed in.
float cos = normalize(normal).z();
float slope_density = 1.0;
if (cos < cos_zero_density_angle) continue; // Too steep for any objects
if (cos < cos_max_density_angle) {
- slope_density =
- (cos - cos_zero_density_angle) /
+ slope_density =
+ (cos - cos_zero_density_angle) /
(cos_max_density_angle - cos_zero_density_angle);
}
-
+
// Containers to hold the random buildings and objects generated
// for this triangle for collision detection purposes.
std::vector< std::pair< SGVec3f, float> > triangleObjectsList;
std::vector< std::pair< SGVec3f, float> > triangleBuildingList;
-
+
// Compute the area
float area = 0.5f*length(normal);
if (area <= SGLimitsf::min())
continue;
- // Generate any random objects
+ // Generate any random objects
if (use_random_objects && (group_count > 0))
{
for (int j = 0; j < group_count; j++)
{
SGMatModelGroup *object_group = mat->get_object_group(j);
int nObjects = object_group->get_object_count();
-
+
if (nObjects == 0) continue;
-
+
// For each of the random models in the group, determine an appropriate
// number of random placements and insert them.
for (int k = 0; k < nObjects; k++) {
SGMatModel * object = object_group->get_object(k);
-
+
// Determine the number of objecst to place, taking into account
// the slope density factor.
double n = slope_density * area / object->get_coverage_m2();
-
+
// Use the zombie door method to determine fractional object placement.
n = n + mt_rand(&seed);
SGVec3f randomPoint = vorigin + a*v0 + b*v1;
float rotation = static_cast<float>(mt_rand(&seed));
-
+
// Check that the point is sufficiently far from
// the edge of the triangle by measuring the distance
- // from the three lines that make up the triangle.
+ // from the three lines that make up the triangle.
float spacing = object->get_spacing_m();
-
- SGVec3f p = randomPoint - vorigin;
+
+ SGVec3f p = randomPoint - vorigin;
float edges[] = { length(cross(p , p - v0)) / length(v0),
length(cross(p - v0, p - v1)) / length(v1 - v0),
length(cross(p - v1, p )) / length(v1) };
- float edge_dist = *std::min_element(edges, edges + 3);
-
- if (edge_dist < spacing) {
+ float edge_dist = *std::min_element(edges, edges + 3);
+
+ if (edge_dist < spacing) {
n -= 1.0;
- continue;
- }
-
+ continue;
+ }
+
if (object_mask != NULL) {
SGVec2f texCoord = torigin + a*t0 + b*t1;
-
+
// Check this random point against the object mask
- // blue (for buildings) channel.
- osg::Image* img = object_mask->getImage();
+ // blue (for buildings) channel.
+ osg::Image* img = object_mask->getImage();
unsigned int x = (int) (img->s() * texCoord.x()) % img->s();
unsigned int y = (int) (img->t() * texCoord.y()) % img->t();
-
- if (mt_rand(&seed) > img->getColor(x, y).b()) {
+
+ if (mt_rand(&seed) > img->getColor(x, y).b()) {
// Failed object mask check
n -= 1.0;
- continue;
+ continue;
}
-
+
rotation = img->getColor(x,y).r();
}
-
+
bool close = false;
// Check it isn't too close to any other random objects in the triangle
std::vector<std::pair<SGVec3f, float> >::iterator l;
for (l = triangleObjectsList.begin(); l != triangleObjectsList.end(); ++l) {
- float min_dist2 = (l->second + object->get_spacing_m()) *
+ float min_dist2 = (l->second + object->get_spacing_m()) *
(l->second + object->get_spacing_m());
-
+
if (distSqr(l->first, randomPoint) > min_dist2) {
close = true;
continue;
}
}
-
+
if (!close) {
triangleObjectsList.push_back(std::make_pair(randomPoint, object->get_spacing_m()));
- randomModels.insert(randomPoint,
- object,
- (int)object->get_randomized_range_m(&seed),
+ randomModels.insert(randomPoint,
+ object,
+ (int)object->get_randomized_range_m(&seed),
rotation);
}
-
- n -= 1.0;
}
}
}
- }
-
+ }
+
// Random objects now generated. Now generate the random buildings (if any);
if (use_random_buildings && (building_coverage > 0) && (building_density > 0)) {
-
+
// Calculate the number of buildings, taking into account building density (which is linear)
- // and the slope density factor.
+ // and the slope density factor.
double num = building_density * building_density * slope_density * area / building_coverage;
-
+
// For partial units of area, use a zombie door method to
// create the proper random chance of an object being created
// for this triangle.
num = num + mt_rand(&seed);
if (num < 1.0f) {
- continue;
+ continue;
}
-
+
// Cosine of the angle between the two vectors.
float cosine = (dot(v0, v1) / (length(v0) * length(v1)));
// coverage will result.
float stepv0 = (sqrtf(building_coverage) / building_density) / length(v0) / sqrtf(1 - cosine * cosine);
float stepv1 = (sqrtf(building_coverage) / building_density) / length(v1);
-
+
stepv0 = std::min(stepv0, 1.0f);
stepv1 = std::min(stepv1, 1.0f);
-
+
// Start at a random point. a will be immediately incremented below.
- float a = -mt_rand(&seed) * stepv0;
+ float a = -mt_rand(&seed) * stepv0;
float b = mt_rand(&seed) * stepv1;
// Place an object each unit of area
while (num > 1.0) {
+ num -= 1.0;
- // Set the next location to place a building
+ // Set the next location to place a building
a += stepv0;
-
+
if ((a + b) > 1.0f) {
// Reached the end of the scan-line on v0. Reset and increment
// scan-line on v1
a = mt_rand(&seed) * stepv0;
b += stepv1;
}
-
+
if (b > 1.0f) {
- // In a degenerate case of a single point, we might be outside the
+ // In a degenerate case of a single point, we might be outside the
// scanline. Note that we need to still ensure that a+b < 1.
b = mt_rand(&seed) * stepv1 * (1.0f - a);
}
-
+
if ((a + b) > 1.0f ) {
// Truly degenerate case - simply choose a random point guaranteed
// to fulfil the constraing of a+b < 1.
a = mt_rand(&seed);
b = mt_rand(&seed) * (1.0f - a);
}
-
+
SGVec3f randomPoint = vorigin + a*v0 + b*v1;
float rotation = mt_rand(&seed);
-
+
if (object_mask != NULL) {
SGVec2f texCoord = torigin + a*t0 + b*t1;
- osg::Image* img = object_mask->getImage();
+ osg::Image* img = object_mask->getImage();
int x = (int) (img->s() * texCoord.x()) % img->s();
int y = (int) (img->t() * texCoord.y()) % img->t();
-
+
// In some degenerate cases x or y can be < 1, in which case the mod operand fails
while (x < 0) x += img->s();
while (y < 0) y += img->t();
- if (mt_rand(&seed) < img->getColor(x, y).b()) {
+ if (mt_rand(&seed) < img->getColor(x, y).b()) {
// Object passes mask. Rotation is taken from the red channel
rotation = img->getColor(x,y).r();
} else {
// Fails mask test - try again.
mask_dropped++;
- num -= 1.0;
continue;
- }
+ }
}
// Check building isn't too close to the triangle edge.
float type_roll = mt_rand(&seed);
SGBuildingBin::BuildingType buildingtype = bin->getBuildingType(type_roll);
float radius = bin->getBuildingMaxRadius(buildingtype);
-
- // Determine the actual center of the building, by shifting from the
+
+ // Determine the actual center of the building, by shifting from the
// center of the front face to the true center.
osg::Matrix rotationMat = osg::Matrix::rotate(- rotation * M_PI * 2,
osg::Vec3f(0.0, 0.0, 1.0));
SGVec3f buildingCenter = randomPoint + toSG(osg::Vec3f(-0.5 * bin->getBuildingMaxDepth(buildingtype), 0.0, 0.0) * rotationMat);
- SGVec3f p = buildingCenter - vorigin;
+ SGVec3f p = buildingCenter - vorigin;
float edges[] = { length(cross(p , p - v0)) / length(v0),
length(cross(p - v0, p - v1)) / length(v1 - v0),
length(cross(p - v1, p )) / length(v1) };
- float edge_dist = *std::min_element(edges, edges + 3);
-
- if (edge_dist < radius) {
- num -= 1.0;
+ float edge_dist = *std::min_element(edges, edges + 3);
+
+ if (edge_dist < radius) {
triangle_dropped++;
- continue;
+ continue;
}
-
- // Check building isn't too close to random objects and other buildings.
+
+ // Check building isn't too close to random objects and other buildings.
bool close = false;
std::vector<std::pair<SGVec3f, float> >::iterator iter;
-
+
for (iter = triangleBuildingList.begin(); iter != triangleBuildingList.end(); ++iter) {
float min_dist = iter->second + radius;
if (distSqr(iter->first, buildingCenter) < min_dist * min_dist) {
close = true;
continue;
- }
+ }
}
-
+
if (close) {
- num -= 1.0;
building_dropped++;
- continue;
+ continue;
}
-
+
for (iter = triangleObjectsList.begin(); iter != triangleObjectsList.end(); ++iter) {
float min_dist = iter->second + radius;
if (distSqr(iter->first, buildingCenter) < min_dist * min_dist) {
close = true;
continue;
- }
+ }
}
-
+
if (close) {
- num -= 1.0;
random_dropped++;
- continue;
- }
+ continue;
+ }
- std::pair<SGVec3f, float> pt = std::make_pair(buildingCenter, radius);
+ std::pair<SGVec3f, float> pt = std::make_pair(buildingCenter, radius);
triangleBuildingList.push_back(pt);
bin->insert(randomPoint, rotation, buildingtype);
- num -= 1.0;
}
}
-
+
triangleObjectsList.clear();
- triangleBuildingList.clear();
+ triangleBuildingList.clear();
}
-
+
SG_LOG(SG_TERRAIN, SG_DEBUG, "Random Buildings: " << ((bin) ? bin->getNumBuildings() : 0));
SG_LOG(SG_TERRAIN, SG_DEBUG, " Dropped due to mask: " << mask_dropped);
SG_LOG(SG_TERRAIN, SG_DEBUG, " Dropped due to random object: " << random_dropped);
SG_LOG(SG_TERRAIN, SG_DEBUG, " Dropped due to other buildings: " << building_dropped);
}
}
-
+
void computeRandomForest(SGMaterialLib* matlib, float vegetation_density)
{
SGMaterialTriangleMap::iterator i;
float wood_coverage = mat->get_wood_coverage();
if ((wood_coverage <= 0) || (vegetation_density <= 0))
continue;
-
+
// 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() ) &&
break;
}
}
-
+
if (!found) {
bin = new TreeBin();
bin->texture = mat->get_tree_texture();
mat->get_cos_tree_max_density_slope_angle(),
mat->get_cos_tree_zero_density_slope_angle(),
randomPoints);
-
+
std::vector<SGVec3f>::iterator k;
for (k = randomPoints.begin(); k != randomPoints.end(); ++k) {
bin->insert(*k);
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;
-
- SGMaterialLib* matlib = 0;
- 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();
- if (propertyNode) {
- use_random_objects
- = propertyNode->getBoolValue("/sim/rendering/random-objects",
- use_random_objects);
- use_random_vegetation
- = propertyNode->getBoolValue("/sim/rendering/random-vegetation",
- use_random_vegetation);
- vegetation_density
- = propertyNode->getFloatValue("/sim/rendering/vegetation-density",
- vegetation_density);
- use_random_buildings
- = propertyNode->getBoolValue("/sim/rendering/random-buildings",
- use_random_buildings);
- building_density
- = propertyNode->getFloatValue("/sim/rendering/building-density",
- building_density);
+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);
+
+ osg::LOD* lightLOD = generateLightingTileObjects();
+ if (lightLOD)
+ group->addChild(lightLOD);
+
+ osg::LOD* objectLOD = generateRandomTileObjects();
+ if (objectLOD)
+ group->addChild(objectLOD);
+
+ return group.release();
}
- }
- 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,
- building_density,
- use_random_objects,
- use_random_buildings);
- }
+ // Generate all the lighting objects for the tile.
+ osg::LOD* generateLightingTileObjects()
+ {
+ SGMaterialLib* matlib;
- if (tileGeometryBin.randomModels.getNumModels() > 0) {
- // Generate a repeatable random seed
- mt seed;
- mt_init(&seed, unsigned(123));
+ if (_options)
+ matlib = _options->getMaterialLib();
- std::vector<ModelLOD> models;
- for (unsigned int i = 0;
- i < tileGeometryBin.randomModels.getNumModels(); i++) {
- SGMatModelBin::MatModel obj
- = tileGeometryBin.randomModels.getMatModel(i);
-
- 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
- // location, and then apply the rotation matrix created
- // above, with an additional random (or taken from
- // the object mask) heading rotation if appropriate.
- 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;
- transformMat.preMult(osg::Matrix::rotate(hdg,
- osg::Vec3d(0.0, 0.0, 1.0)));
+ // 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 (obj.model->get_heading_type() == SGMatModel::HEADING_MASK) {
- // Rotate the object around the z axis.
- double hdg = - obj.rotation * M_PI * 2;
- transformMat.preMult(osg::Matrix::rotate(hdg,
- osg::Vec3d(0.0, 0.0, 1.0)));
+ 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);
}
-
- osg::MatrixTransform* position =
- new osg::MatrixTransform(transformMat);
- position->setName("positionRandomeModel");
- position->addChild(node);
- models.push_back(ModelLOD(position, obj.lod));
- }
- RandomObjectsQuadtree quadtree((GetModelLODCoord()), (AddModelLOD()));
- quadtree.buildQuadTree(models.begin(), models.end());
- randomObjects = quadtree.getRoot();
- randomObjects->setName("Random objects");
- }
- if (! tileGeometryBin.randomBuildings.empty()) {
- buildingNode = createRandomBuildings(tileGeometryBin.randomBuildings, osg::Matrix::identity(),
- options);
- buildingNode->setName("Random buildings");
- }
+ 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);
+ }
- if (use_random_vegetation && matlib) {
- // Now add some random forest.
- tileGeometryBin.computeRandomForest(matlib, vegetation_density);
-
- 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);
- }
+ 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.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));
+ 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;
}
- SGLightListBin::const_iterator j;
- for (j = tileGeometryBin.odalLights.begin();
- j != tileGeometryBin.odalLights.end(); ++j) {
- rwyLights->addChild(SGLightFactory::getOdal(*j));
+
+ // 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;
+
+ 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",
+ use_random_objects);
+ use_random_vegetation
+ = propertyNode->getBoolValue("/sim/rendering/random-vegetation",
+ use_random_vegetation);
+ vegetation_density
+ = propertyNode->getFloatValue("/sim/rendering/vegetation-density",
+ vegetation_density);
+ use_random_buildings
+ = propertyNode->getBoolValue("/sim/rendering/random-buildings",
+ use_random_buildings);
+ building_density
+ = propertyNode->getFloatValue("/sim/rendering/building-density",
+ building_density);
+ }
+ }
+
+
+
+ if (matlib && (use_random_objects || use_random_buildings)) {
+ _tileGeometryBin->computeRandomObjectsAndBuildings(matlib,
+ building_density,
+ use_random_objects,
+ use_random_buildings);
+ }
+
+
+ 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++) {
+ SGMatModelBin::MatModel obj
+ = _tileGeometryBin->randomModels.getMatModel(i);
+
+ 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
+ // location, and then apply the rotation matrix created
+ // above, with an additional random (or taken from
+ // the object mask) heading rotation if appropriate.
+ 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;
+ transformMat.preMult(osg::Matrix::rotate(hdg,
+ osg::Vec3d(0.0, 0.0, 1.0)));
+ }
+
+ if (obj.model->get_heading_type() == SGMatModel::HEADING_MASK) {
+ // Rotate the object around the z axis.
+ double hdg = - obj.rotation * M_PI * 2;
+ transformMat.preMult(osg::Matrix::rotate(hdg,
+ osg::Vec3d(0.0, 0.0, 1.0)));
+ }
+
+ osg::MatrixTransform* position =
+ new osg::MatrixTransform(transformMat);
+ position->setName("positionRandomModel");
+ position->addChild(node);
+ models.push_back(ModelLOD(position, obj.lod));
+ }
+ RandomObjectsQuadtree quadtree((GetModelLODCoord()), (AddModelLOD()));
+ quadtree.buildQuadTree(models.begin(), models.end());
+ randomObjects = quadtree.getRoot();
+ randomObjects->setName("Random objects");
+ }
+
+ 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);
+
+ if (! _tileGeometryBin->randomForest.empty()) {
+ forestNode = createForest(_tileGeometryBin->randomForest, osg::Matrix::identity(),
+ _options);
+ forestNode->setName("Random trees");
+ }
+ }
+
+ osg::LOD* objectLOD = NULL;
+
+ if (randomObjects.valid() || forestNode.valid() || buildingNode.valid()) {
+ objectLOD = new osg::LOD;
+
+ if (randomObjects.valid()) objectLOD->addChild(randomObjects.get(), 0, 20000);
+ if (forestNode.valid()) objectLOD->addChild(forestNode.get(), 0, 20000);
+ if (buildingNode.valid()) objectLOD->addChild(buildingNode.get(), 0, 20000);
+
+ unsigned nodeMask = SG_NODEMASK_CASTSHADOW_BIT | SG_NODEMASK_RECEIVESHADOW_BIT | SG_NODEMASK_TERRAIN_BIT;
+ objectLOD->setNodeMask(nodeMask);
+ }
+
+ return objectLOD;
}
- 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 original options to use for this bunch of models
+ osg::ref_ptr<SGReaderWriterOptions> _options;
+ osg::ref_ptr<SGTileGeometryBin> _tileGeometryBin;
+};
- // 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);
- }
-
- 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;
-
- if (randomObjects.valid()) objectLOD->addChild(randomObjects.get(), 0, 20000);
- if (forestNode.valid()) objectLOD->addChild(forestNode.get(), 0, 20000);
- if (buildingNode.valid()) objectLOD->addChild(buildingNode.get(), 0, 20000);
-
- unsigned nodeMask = SG_NODEMASK_CASTSHADOW_BIT | SG_NODEMASK_RECEIVESHADOW_BIT | SG_NODEMASK_TERRAIN_BIT;
- objectLOD->setNodeMask(nodeMask);
- transform->addChild(objectLOD);
- }
- transform->setNodeMask( ~simgear::MODELLIGHT_BIT );
-
- return transform;
+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;
}