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

@ -61,13 +61,13 @@ using namespace osg;
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
@ -88,7 +88,7 @@ BuildingBoundingBoxCallback::computeBound(const Drawable& drawable) const
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;
@ -104,132 +104,132 @@ BuildingBoundingBoxCallback::computeBound(const Drawable& drawable) const
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
@ -244,10 +244,10 @@ BuildingBoundingBoxCallback::computeBound(const Drawable& drawable) const
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
@ -255,18 +255,18 @@ BuildingBoundingBoxCallback::computeBound(const Drawable& drawable) const
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
@ -281,10 +281,10 @@ BuildingBoundingBoxCallback::computeBound(const Drawable& drawable) const
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
@ -293,25 +293,25 @@ BuildingBoundingBoxCallback::computeBound(const Drawable& drawable) const
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
@ -320,37 +320,37 @@ BuildingBoundingBoxCallback::computeBound(const Drawable& drawable) const
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
@ -359,25 +359,25 @@ BuildingBoundingBoxCallback::computeBound(const Drawable& drawable) const
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;
@ -389,8 +389,8 @@ BuildingBoundingBoxCallback::computeBound(const Drawable& drawable) const
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
@ -398,19 +398,19 @@ BuildingBoundingBoxCallback::computeBound(const Drawable& drawable) const
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
@ -418,32 +418,32 @@ BuildingBoundingBoxCallback::computeBound(const Drawable& drawable) const
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
@ -454,31 +454,31 @@ BuildingBoundingBoxCallback::computeBound(const Drawable& drawable) const
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
@ -486,19 +486,19 @@ BuildingBoundingBoxCallback::computeBound(const Drawable& drawable) const
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
@ -506,30 +506,30 @@ BuildingBoundingBoxCallback::computeBound(const Drawable& drawable) const
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
@ -541,9 +541,9 @@ BuildingBoundingBoxCallback::computeBound(const Drawable& drawable) const
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
@ -554,16 +554,16 @@ BuildingBoundingBoxCallback::computeBound(const Drawable& drawable) const
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
@ -571,19 +571,19 @@ BuildingBoundingBoxCallback::computeBound(const Drawable& drawable) const
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
@ -591,7 +591,7 @@ BuildingBoundingBoxCallback::computeBound(const Drawable& drawable) const
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
@ -599,19 +599,19 @@ BuildingBoundingBoxCallback::computeBound(const Drawable& drawable) const
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
@ -621,9 +621,9 @@ BuildingBoundingBoxCallback::computeBound(const Drawable& drawable) const
// 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
@ -632,7 +632,7 @@ BuildingBoundingBoxCallback::computeBound(const Drawable& drawable) const
}
}
}
// Set the vertex, texture and normals. Colors will be set per-instance
// later.
sharedGeometry->setVertexArray(v);
@ -640,88 +640,88 @@ BuildingBoundingBoxCallback::computeBound(const Drawable& drawable) const
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)))
@ -731,27 +731,27 @@ 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
}
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.
@ -759,7 +759,7 @@ BuildingBoundingBoxCallback::computeBound(const Drawable& drawable) const
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.
@ -773,15 +773,15 @@ BuildingBoundingBoxCallback::computeBound(const Drawable& drawable) const
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)
{
}
@ -815,31 +815,32 @@ 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));
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;

View File

@ -56,9 +56,9 @@ class SGBuildingBin {
public:
// Number of buildings to auto-generate. Individual
// building instances are taken from this set.
// building instances are taken from this set.
static const unsigned int BUILDING_SET_SIZE = 200;
static const unsigned int QUADS_PER_BUILDING = 12;
static const unsigned int VERTICES_PER_BUILDING = 4 * QUADS_PER_BUILDING;
static const unsigned int VERTICES_PER_BUILDING_SET = BUILDING_SET_SIZE * VERTICES_PER_BUILDING;
@ -66,21 +66,21 @@ public:
enum BuildingType {
SMALL = 0,
MEDIUM,
LARGE };
LARGE };
private:
struct Building {
Building(BuildingType t, float w, float d, float h, int f, bool pitch) :
type(t),
width(w),
depth(d),
height(h),
type(t),
width(w),
depth(d),
height(h),
floors(f),
pitched(pitch),
pitched(pitch),
radius(std::max(d, 0.5f*w))
{ }
BuildingType type;
float width;
float depth;
@ -88,22 +88,22 @@ private:
int floors;
bool pitched;
float radius;
float getFootprint() {
return radius;
}
};
// The set of buildings that are instantiated
typedef std::vector<Building> BuildingList;
BuildingList smallBuildings;
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;
float mediumBuildingFraction;
@ -112,20 +112,20 @@ private:
float smallBuildingMaxRadius;
float mediumBuildingMaxRadius;
float largeBuildingMaxRadius;
// The maximum depth of each building type
float smallBuildingMaxDepth;
float mediumBuildingMaxDepth;
float largeBuildingMaxDepth;
// Visibility range for buildings
float buildingRange;
// Shared geometries of the building set
ref_ptr<Geometry> smallSharedGeometry;
ref_ptr<Geometry> mediumSharedGeometry;
ref_ptr<Geometry> largeSharedGeometry;
struct BuildingInstance {
BuildingInstance(SGVec3f p, float r, const BuildingList* bl, ref_ptr<Geometry> sg) :
position(p),
@ -133,26 +133,26 @@ private:
buildingList(bl),
sharedGeometry(sg)
{ }
BuildingInstance(SGVec3f p, BuildingInstance b) :
position(p),
rotation(b.rotation),
buildingList(b.buildingList),
sharedGeometry(b.sharedGeometry)
{ }
{ }
SGVec3f position;
float rotation;
// References to allow the QuadTreeBuilder to work
const BuildingList* buildingList;
ref_ptr<Geometry> sharedGeometry;
ref_ptr<Geometry> sharedGeometry;
SGVec3f getPosition() { return position; }
float getRotation() { return rotation; }
float getDistSqr(SGVec3f p) {
return distSqr(p, position);
return distSqr(p, position);
}
const osg::Vec4f getColorValue() {
@ -161,42 +161,42 @@ private:
};
// Information for an instance of a building - position and orientation
typedef std::vector<BuildingInstance> BuildingInstanceList;
typedef std::vector<BuildingInstance> BuildingInstanceList;
BuildingInstanceList smallBuildingLocations;
BuildingInstanceList mediumBuildingLocations;
BuildingInstanceList largeBuildingLocations;
public:
public:
SGBuildingBin(const SGMaterial *mat);
~SGBuildingBin() {
smallBuildings.clear();
smallBuildings.clear();
mediumBuildings.clear();
largeBuildings.clear();
smallBuildingLocations.clear();
mediumBuildingLocations.clear();
largeBuildingLocations.clear();
}
void insert(SGVec3f p, float r, BuildingType type);
int getNumBuildings();
bool checkMinDist (SGVec3f p, float radius);
std::string getMaterialName() { return material_name; }
std::string* getMaterialName() { return material_name; }
BuildingType getBuildingType(float roll);
float getBuildingMaxRadius(BuildingType);
float getBuildingMaxDepth(BuildingType);
// Helper classes for creating the quad tree
struct MakeBuildingLeaf
{
MakeBuildingLeaf(float range, Effect* effect, bool fade) :
_range(range), _effect(effect), _fade_out(fade) {}
MakeBuildingLeaf(const MakeBuildingLeaf& rhs) :
_range(rhs._range), _effect(rhs._effect), _fade_out(rhs._fade_out)
{}
@ -204,30 +204,30 @@ public:
LOD* operator() () const
{
LOD* result = new LOD;
if (_fade_out) {
if (_fade_out) {
// Create a series of LOD nodes so buidling cover decreases
// gradually with distance from _range to 2*_range
for (float i = 0.0; i < SG_BUILDING_FADE_OUT_LEVELS; i++)
{
{
EffectGeode* geode = new EffectGeode;
geode->setEffect(_effect.get());
result->addChild(geode, 0, _range * (1.0 + i / (SG_BUILDING_FADE_OUT_LEVELS - 1.0)));
result->addChild(geode, 0, _range * (1.0 + i / (SG_BUILDING_FADE_OUT_LEVELS - 1.0)));
}
} else {
// No fade-out, so all are visible for 2X range
EffectGeode* geode = new EffectGeode;
geode->setEffect(_effect.get());
result->addChild(geode, 0, 2.0 * _range);
result->addChild(geode, 0, 2.0 * _range);
}
return result;
}
float _range;
ref_ptr<Effect> _effect;
bool _fade_out;
};
struct AddBuildingLeafObject
{
Geometry* createNewBuildingGeometryInstance(const BuildingInstance& building) const
@ -237,32 +237,32 @@ public:
geom->setColorBinding(Geometry::BIND_PER_VERTEX);
geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS));
return geom;
}
}
void operator() (LOD* lod, const BuildingInstance& building) const
{
Geode* geode = static_cast<Geode*>(lod->getChild(int(building.position.x() * 10.0f) % lod->getNumChildren()));
unsigned int numDrawables = geode->getNumDrawables();
unsigned int numDrawables = geode->getNumDrawables();
// Get the last geometry of to be added and check if there is space for
// another building instance within it. This is done by checking
// if the number of Color values matches the number of vertices.
// The color array is used to store the position of a particular
// instance.
Geometry* geom;
if (numDrawables == 0) {
// Create a new copy of the shared geometry to instantiate
geom = createNewBuildingGeometryInstance(building);
geode->addDrawable(geom);
} else {
geom = static_cast<Geometry*>(geode->getDrawable(numDrawables - 1));
geom = static_cast<Geometry*>(geode->getDrawable(numDrawables - 1));
}
// Check if this building is too close to any other others.
DrawArrays* primSet = static_cast<DrawArrays*>(geom->getPrimitiveSet(0));
Vec4Array* posArray = static_cast<Vec4Array*>(geom->getColorArray());
// Now check if this geometry is full.
if (posArray->size() >= static_cast<Vec3Array*>(geom->getVertexArray())->size()) {
// This particular geometry is full, so we generate another
@ -272,7 +272,7 @@ public:
posArray = static_cast<Vec4Array*>(geom->getColorArray());
SG_LOG(SG_TERRAIN, SG_DEBUG, "Added new geometry to building geod: " << geode->getNumDrawables());
}
// We now have a geometry with space for this new building.
// Set the position and rotation
osg::Vec4f c = osg::Vec4f(toOsg(building.position), building.rotation);
@ -293,7 +293,7 @@ public:
typedef QuadTreeBuilder<LOD*, BuildingInstance, MakeBuildingLeaf, AddBuildingLeafObject,
GetBuildingCoord> BuildingGeometryQuadtree;
struct BuildingInstanceTransformer
{
BuildingInstanceTransformer(Matrix& mat_) : mat(mat_) {}
@ -304,8 +304,8 @@ public:
}
Matrix mat;
};
ref_ptr<Group> createBuildingsGroup(Matrix transInv, const SGReaderWriterOptions* options);
ref_ptr<Group> createBuildingsGroup(Matrix transInv, const SGReaderWriterOptions* options);
};
@ -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

File diff suppressed because it is too large Load Diff