Random buildings - initial commit.
This commit is contained in:
parent
0c13fb7ae4
commit
f9bf403fc0
@ -264,6 +264,49 @@ SGMaterial::read_properties(const SGReaderWriterOptions* options,
|
|||||||
wrapv = props->getBoolValue("wrapv", true);
|
wrapv = props->getBoolValue("wrapv", true);
|
||||||
mipmap = props->getBoolValue("mipmap", true);
|
mipmap = props->getBoolValue("mipmap", true);
|
||||||
light_coverage = props->getDoubleValue("light-coverage", 0.0);
|
light_coverage = props->getDoubleValue("light-coverage", 0.0);
|
||||||
|
|
||||||
|
// Building properties
|
||||||
|
building_coverage = props->getDoubleValue("building-coverage", 0.0);
|
||||||
|
building_spacing = props->getDoubleValue("building-spacing-m", 5.0);
|
||||||
|
|
||||||
|
string bt = props->getStringValue("building-texture", "Textures/buildings.png");
|
||||||
|
building_texture = SGModelLib::findDataFile(bt, options);
|
||||||
|
|
||||||
|
if (building_texture.empty()) {
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT, "Cannot find texture \"" << bt);
|
||||||
|
}
|
||||||
|
|
||||||
|
building_small_ratio = props->getDoubleValue("building-small-ratio", 0.8);
|
||||||
|
building_medium_ratio = props->getDoubleValue("building-medium-ratio", 0.15);
|
||||||
|
building_large_ratio = props->getDoubleValue("building-large-ratio", 0.05);
|
||||||
|
|
||||||
|
building_small_pitch = props->getDoubleValue("building-small-pitch", 0.8);
|
||||||
|
building_medium_pitch = props->getDoubleValue("building-medium-pitch", 0.2);
|
||||||
|
building_large_pitch = props->getDoubleValue("building-large-pitch", 0.1);
|
||||||
|
|
||||||
|
building_small_min_floors = props->getIntValue("building-small-min-floors", 1);
|
||||||
|
building_small_max_floors = props->getIntValue("building-small-max-floors", 3);
|
||||||
|
building_medium_min_floors = props->getIntValue("building-medium-min-floors", 3);
|
||||||
|
building_medium_max_floors = props->getIntValue("building-medium-max-floors", 8);
|
||||||
|
building_large_min_floors = props->getIntValue("building-large-min-floors", 5);
|
||||||
|
building_large_max_floors = props->getIntValue("building-large-max-floors", 20);
|
||||||
|
|
||||||
|
building_small_min_width = props->getFloatValue("building-small-min-width-m", 15.0);
|
||||||
|
building_small_max_width = props->getFloatValue("building-small-max-width-m", 60.0);
|
||||||
|
building_small_min_depth = props->getFloatValue("building-small-min-depth-m", 10.0);
|
||||||
|
building_small_max_depth = props->getFloatValue("building-small-max-depth-m", 20.0);
|
||||||
|
|
||||||
|
building_medium_min_width = props->getFloatValue("building-medium-min-width-m", 25.0);
|
||||||
|
building_medium_max_width = props->getFloatValue("building-medium-max-width-m", 50.0);
|
||||||
|
building_medium_min_depth = props->getFloatValue("building-medium-min-depth-m", 20.0);
|
||||||
|
building_medium_max_depth = props->getFloatValue("building-medium-max-depth-m", 50.0);
|
||||||
|
|
||||||
|
building_large_min_width = props->getFloatValue("building-large-min-width-m", 50.0);
|
||||||
|
building_large_max_width = props->getFloatValue("building-large-max-width-m", 75.0);
|
||||||
|
building_large_min_depth = props->getFloatValue("building-large-min-depth-m", 50.0);
|
||||||
|
building_large_max_depth = props->getFloatValue("building-large-max-depth-m", 75.0);
|
||||||
|
|
||||||
|
// Random vegetation properties
|
||||||
wood_coverage = props->getDoubleValue("wood-coverage", 0.0);
|
wood_coverage = props->getDoubleValue("wood-coverage", 0.0);
|
||||||
tree_height = props->getDoubleValue("tree-height-m", 0.0);
|
tree_height = props->getDoubleValue("tree-height-m", 0.0);
|
||||||
tree_width = props->getDoubleValue("tree-width-m", 0.0);
|
tree_width = props->getDoubleValue("tree-width-m", 0.0);
|
||||||
@ -358,6 +401,7 @@ SGMaterial::init ()
|
|||||||
|
|
||||||
mipmap = true;
|
mipmap = true;
|
||||||
light_coverage = 0.0;
|
light_coverage = 0.0;
|
||||||
|
building_coverage = 0.0;
|
||||||
|
|
||||||
solid = true;
|
solid = true;
|
||||||
friction_factor = 1;
|
friction_factor = 1;
|
||||||
|
@ -145,6 +145,67 @@ public:
|
|||||||
* @return The area (m^2) covered by each light.
|
* @return The area (m^2) covered by each light.
|
||||||
*/
|
*/
|
||||||
inline double get_light_coverage () const { return light_coverage; }
|
inline double get_light_coverage () const { return light_coverage; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the building coverage.
|
||||||
|
*
|
||||||
|
* A smaller number means more generated buildings.
|
||||||
|
*
|
||||||
|
* @return The area (m^2) covered by each light.
|
||||||
|
*/
|
||||||
|
inline double get_building_coverage () const { return building_coverage; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the building spacing.
|
||||||
|
*
|
||||||
|
* This is the minimum spacing between buildings
|
||||||
|
*
|
||||||
|
* @return The minimum distance between buildings
|
||||||
|
*/
|
||||||
|
inline double get_building_spacing () const { return building_spacing; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the building texture.
|
||||||
|
*
|
||||||
|
* This is the texture used for auto-generated buildings.
|
||||||
|
*
|
||||||
|
* @return The texture for auto-generated buildings.
|
||||||
|
*/
|
||||||
|
inline std::string get_building_texture () const { return building_texture; }
|
||||||
|
|
||||||
|
// Ratio of the 3 random building sizes
|
||||||
|
inline double get_building_small_fraction () const { return building_small_ratio / (building_small_ratio + building_medium_ratio + building_large_ratio); }
|
||||||
|
inline double get_building_medium_fraction () const { return building_medium_ratio / (building_small_ratio + building_medium_ratio + building_large_ratio); }
|
||||||
|
inline double get_building_large_fraction () const { return building_large_ratio / (building_small_ratio + building_medium_ratio + building_large_ratio); }
|
||||||
|
|
||||||
|
// Proportion of buildings with pitched roofs
|
||||||
|
inline double get_building_small_pitch () const { return building_small_pitch; }
|
||||||
|
inline double get_building_medium_pitch () const { return building_medium_pitch; }
|
||||||
|
inline double get_building_large_pitch () const { return building_large_pitch; }
|
||||||
|
|
||||||
|
// Min/Max number of floors for each size
|
||||||
|
inline int get_building_small_min_floors () const { return building_small_min_floors; }
|
||||||
|
inline int get_building_small_max_floors () const { return building_small_max_floors; }
|
||||||
|
inline int get_building_medium_min_floors () const { return building_medium_min_floors; }
|
||||||
|
inline int get_building_medium_max_floors () const { return building_medium_max_floors; }
|
||||||
|
inline int get_building_large_min_floors () const { return building_large_min_floors; }
|
||||||
|
inline int get_building_large_max_floors () const { return building_large_max_floors; }
|
||||||
|
|
||||||
|
// Minimum width and depth for each size
|
||||||
|
inline double get_building_small_min_width () const { return building_small_min_width; }
|
||||||
|
inline double get_building_small_max_width () const { return building_small_max_width; }
|
||||||
|
inline double get_building_small_min_depth () const { return building_small_min_depth; }
|
||||||
|
inline double get_building_small_max_depth () const { return building_small_max_depth; }
|
||||||
|
|
||||||
|
inline double get_building_medium_min_width () const { return building_medium_min_width; }
|
||||||
|
inline double get_building_medium_max_width () const { return building_medium_max_width; }
|
||||||
|
inline double get_building_medium_min_depth () const { return building_medium_min_depth; }
|
||||||
|
inline double get_building_medium_max_depth () const { return building_medium_max_depth; }
|
||||||
|
|
||||||
|
inline double get_building_large_min_width () const { return building_large_min_width; }
|
||||||
|
inline double get_building_large_max_width () const { return building_large_max_width; }
|
||||||
|
inline double get_building_large_min_depth () const { return building_large_min_depth; }
|
||||||
|
inline double get_building_large_max_depth () const { return building_large_max_depth; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the wood coverage.
|
* Get the wood coverage.
|
||||||
@ -317,6 +378,49 @@ private:
|
|||||||
// coverage of night lighting.
|
// coverage of night lighting.
|
||||||
double light_coverage;
|
double light_coverage;
|
||||||
|
|
||||||
|
// coverage of buildings
|
||||||
|
double building_coverage;
|
||||||
|
|
||||||
|
// building spacing
|
||||||
|
double building_spacing;
|
||||||
|
|
||||||
|
// building texture
|
||||||
|
std::string building_texture;
|
||||||
|
|
||||||
|
// Ratio of the 3 random building sizes
|
||||||
|
double building_small_ratio;
|
||||||
|
double building_medium_ratio;
|
||||||
|
double building_large_ratio;
|
||||||
|
|
||||||
|
// Proportion of buildings with pitched roofs
|
||||||
|
double building_small_pitch;
|
||||||
|
double building_medium_pitch;
|
||||||
|
double building_large_pitch;
|
||||||
|
|
||||||
|
// Min/Max number of floors for each size
|
||||||
|
int building_small_min_floors;
|
||||||
|
int building_small_max_floors;
|
||||||
|
int building_medium_min_floors;
|
||||||
|
int building_medium_max_floors;
|
||||||
|
int building_large_min_floors;
|
||||||
|
int building_large_max_floors;
|
||||||
|
|
||||||
|
// Minimum width and depth for each size
|
||||||
|
double building_small_min_width;
|
||||||
|
double building_small_max_width;
|
||||||
|
double building_small_min_depth;
|
||||||
|
double building_small_max_depth;
|
||||||
|
|
||||||
|
double building_medium_min_width;
|
||||||
|
double building_medium_max_width;
|
||||||
|
double building_medium_min_depth;
|
||||||
|
double building_medium_max_depth;
|
||||||
|
|
||||||
|
double building_large_min_width;
|
||||||
|
double building_large_max_width;
|
||||||
|
double building_large_min_depth;
|
||||||
|
double building_large_max_depth;
|
||||||
|
|
||||||
// coverage of woods
|
// coverage of woods
|
||||||
double wood_coverage;
|
double wood_coverage;
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@ set(SOURCES
|
|||||||
GroundLightManager.cxx
|
GroundLightManager.cxx
|
||||||
ReaderWriterSPT.cxx
|
ReaderWriterSPT.cxx
|
||||||
ReaderWriterSTG.cxx
|
ReaderWriterSTG.cxx
|
||||||
|
SGBuildingBin.cxx
|
||||||
SGOceanTile.cxx
|
SGOceanTile.cxx
|
||||||
SGReaderWriterBTG.cxx
|
SGReaderWriterBTG.cxx
|
||||||
SGVasiDrawable.cxx
|
SGVasiDrawable.cxx
|
||||||
|
636
simgear/scene/tgdb/SGBuildingBin.cxx
Normal file
636
simgear/scene/tgdb/SGBuildingBin.cxx
Normal file
@ -0,0 +1,636 @@
|
|||||||
|
/* -*-c++-*-
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012 Stuart Buchanan
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||||
|
* MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <simgear_config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include <boost/foreach.hpp>
|
||||||
|
#include <boost/tuple/tuple_comparison.hpp>
|
||||||
|
|
||||||
|
#include <osg/Geode>
|
||||||
|
#include <osg/Geometry>
|
||||||
|
#include <osg/Math>
|
||||||
|
#include <osg/MatrixTransform>
|
||||||
|
#include <osg/Matrix>
|
||||||
|
#include <osg/ShadeModel>
|
||||||
|
#include <osg/Material>
|
||||||
|
#include <osg/CullFace>
|
||||||
|
|
||||||
|
#include <osgDB/ReadFile>
|
||||||
|
#include <osgDB/FileUtils>
|
||||||
|
|
||||||
|
#include <simgear/debug/logstream.hxx>
|
||||||
|
#include <simgear/math/sg_random.h>
|
||||||
|
#include <simgear/misc/sg_path.hxx>
|
||||||
|
#include <simgear/scene/material/Effect.hxx>
|
||||||
|
#include <simgear/scene/material/EffectGeode.hxx>
|
||||||
|
#include <simgear/scene/model/model.hxx>
|
||||||
|
#include <simgear/props/props.hxx>
|
||||||
|
#include <simgear/scene/util/QuadTreeBuilder.hxx>
|
||||||
|
#include <simgear/scene/util/RenderConstants.hxx>
|
||||||
|
#include <simgear/scene/util/StateAttributeFactory.hxx>
|
||||||
|
#include <simgear/structure/OSGUtils.hxx>
|
||||||
|
|
||||||
|
|
||||||
|
#include "ShaderGeometry.hxx"
|
||||||
|
#include "SGBuildingBin.hxx"
|
||||||
|
|
||||||
|
#define SG_BUILDING_QUAD_TREE_DEPTH 3
|
||||||
|
#define SG_BUILDING_FADE_OUT_LEVELS 10
|
||||||
|
|
||||||
|
using namespace osg;
|
||||||
|
|
||||||
|
namespace simgear
|
||||||
|
{
|
||||||
|
|
||||||
|
typedef std::map<std::string, osg::observer_ptr<osg::StateSet> > BuildingStateSetMap;
|
||||||
|
static BuildingStateSetMap statesetmap;
|
||||||
|
|
||||||
|
void addBuildingToLeafGeode(Geode* geode, const SGBuildingBin::Building& building)
|
||||||
|
{
|
||||||
|
// Generate a repeatable random seed
|
||||||
|
mt seed;
|
||||||
|
mt_init(&seed, unsigned(building.position.x()));
|
||||||
|
|
||||||
|
// Get or create geometry.
|
||||||
|
osg::ref_ptr<osg::Geometry> geom;
|
||||||
|
osg::Vec3Array* v = new osg::Vec3Array;
|
||||||
|
osg::Vec2Array* t = new osg::Vec2Array;
|
||||||
|
|
||||||
|
// Color and Normal will be per QUAD
|
||||||
|
osg::Vec4Array* c = new osg::Vec4Array;
|
||||||
|
osg::Vec3Array* n = new osg::Vec3Array;
|
||||||
|
|
||||||
|
if (geode->getNumDrawables() == 0) {
|
||||||
|
geom = new osg::Geometry;
|
||||||
|
v = new osg::Vec3Array;
|
||||||
|
t = new osg::Vec2Array;
|
||||||
|
c = new osg::Vec4Array;
|
||||||
|
n = new osg::Vec3Array;
|
||||||
|
|
||||||
|
// Set the color, which is bound overall, and simply white
|
||||||
|
c->push_back( osg::Vec4( 1, 1, 1, 1) );
|
||||||
|
geom->setColorArray(c);
|
||||||
|
geom->setColorBinding(osg::Geometry::BIND_OVERALL);
|
||||||
|
|
||||||
|
geom->setNormalBinding(osg::Geometry::BIND_PER_PRIMITIVE);
|
||||||
|
// Temporary primitive set. Will be over-written later.
|
||||||
|
geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,1));
|
||||||
|
geode->addDrawable(geom);
|
||||||
|
} else {
|
||||||
|
geom = (osg::Geometry*) geode->getDrawable(0);
|
||||||
|
v = (osg::Vec3Array*) geom->getVertexArray();
|
||||||
|
t = (osg::Vec2Array*) geom->getTexCoordArray(0);
|
||||||
|
c = (osg::Vec4Array*) geom->getColorArray();
|
||||||
|
n = (osg::Vec3Array*) geom->getNormalArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
// For the moment we'll create a simple box with 5 sides (no need
|
||||||
|
// for a base).
|
||||||
|
int num_quads = 5;
|
||||||
|
|
||||||
|
if (building.pitched) {
|
||||||
|
// If it's a pitched roof, we add another 3 quads (we'll be
|
||||||
|
// removing the flat top).
|
||||||
|
num_quads+=3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up the rotation and translation matrix, which we apply to
|
||||||
|
// vertices as they are created as we'll be adding buildings later.
|
||||||
|
osg::Matrix transformMat;
|
||||||
|
transformMat = osg::Matrix::translate(toOsg(building.position));
|
||||||
|
double hdg = - building.rotation * M_PI * 2;
|
||||||
|
osg::Matrix rotationMat = osg::Matrix::rotate(hdg,
|
||||||
|
osg::Vec3d(0.0, 0.0, 1.0));
|
||||||
|
transformMat.preMult(rotationMat);
|
||||||
|
|
||||||
|
// Create the vertices
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
// BASEMENT
|
||||||
|
// This exteds 10m below the main section
|
||||||
|
// Front face
|
||||||
|
v->push_back( osg::Vec3( 0, cw, -10) * transformMat ); // bottom right
|
||||||
|
v->push_back( osg::Vec3( 0, -cw, -10) * transformMat ); // bottom left
|
||||||
|
v->push_back( osg::Vec3( 0, -cw, 0) * transformMat ); // top left
|
||||||
|
v->push_back( osg::Vec3( 0, cw, 0) * transformMat ); // top right
|
||||||
|
|
||||||
|
n->push_back( osg::Vec3(-1, 0, 0) * rotationMat ); // normal
|
||||||
|
|
||||||
|
// Left face
|
||||||
|
v->push_back( osg::Vec3( 0, -cw, -10) * transformMat ); // bottom right
|
||||||
|
v->push_back( osg::Vec3( cd, -cw, -10) * transformMat ); // bottom left
|
||||||
|
v->push_back( osg::Vec3( cd, -cw, 0) * transformMat ); // top left
|
||||||
|
v->push_back( osg::Vec3( 0, -cw, 0) * transformMat ); // top right
|
||||||
|
|
||||||
|
n->push_back( osg::Vec3(0, -1, 0) * rotationMat ); // normal
|
||||||
|
|
||||||
|
// Back face
|
||||||
|
v->push_back( osg::Vec3( cd, -cw, -10) * transformMat ); // bottom right
|
||||||
|
v->push_back( osg::Vec3( cd, cw, -10) * transformMat ); // bottom left
|
||||||
|
v->push_back( osg::Vec3( cd, cw, 0) * transformMat ); // top left
|
||||||
|
v->push_back( osg::Vec3( cd, -cw, 0) * transformMat ); // top right
|
||||||
|
|
||||||
|
n->push_back( osg::Vec3(1, 0, 0) * rotationMat ); // normal
|
||||||
|
|
||||||
|
// Right face
|
||||||
|
v->push_back( osg::Vec3( cd, cw, -10) * transformMat ); // bottom right
|
||||||
|
v->push_back( osg::Vec3( 0, cw, -10) * transformMat ); // bottom left
|
||||||
|
v->push_back( osg::Vec3( 0, cw, 0) * transformMat ); // top left
|
||||||
|
v->push_back( osg::Vec3( cd, cw, 0) * transformMat ); // top right
|
||||||
|
|
||||||
|
n->push_back( osg::Vec3(0, 1, 0) * rotationMat ); // normal
|
||||||
|
|
||||||
|
// MAIN BODY
|
||||||
|
// Front face
|
||||||
|
v->push_back( osg::Vec3( 0, cw, 0) * transformMat ); // bottom right
|
||||||
|
v->push_back( osg::Vec3( 0, -cw, 0) * transformMat ); // bottom left
|
||||||
|
v->push_back( osg::Vec3( 0, -cw, ch) * transformMat ); // top left
|
||||||
|
v->push_back( osg::Vec3( 0, cw, ch) * transformMat ); // top right
|
||||||
|
|
||||||
|
n->push_back( osg::Vec3(-1, 0, 0) * rotationMat ); // normal
|
||||||
|
|
||||||
|
// Left face
|
||||||
|
v->push_back( osg::Vec3( 0, -cw, 0) * transformMat ); // bottom right
|
||||||
|
v->push_back( osg::Vec3( cd, -cw, 0) * transformMat ); // bottom left
|
||||||
|
v->push_back( osg::Vec3( cd, -cw, ch) * transformMat ); // top left
|
||||||
|
v->push_back( osg::Vec3( 0, -cw, ch) * transformMat ); // top right
|
||||||
|
|
||||||
|
n->push_back( osg::Vec3(0, -1, 0) * rotationMat ); // normal
|
||||||
|
|
||||||
|
// Back face
|
||||||
|
v->push_back( osg::Vec3( cd, -cw, 0) * transformMat ); // bottom right
|
||||||
|
v->push_back( osg::Vec3( cd, cw, 0) * transformMat ); // bottom left
|
||||||
|
v->push_back( osg::Vec3( cd, cw, ch) * transformMat ); // top left
|
||||||
|
v->push_back( osg::Vec3( cd, -cw, ch) * transformMat ); // top right
|
||||||
|
|
||||||
|
n->push_back( osg::Vec3(1, 0, 0) * rotationMat ); // normal
|
||||||
|
|
||||||
|
// Right face
|
||||||
|
v->push_back( osg::Vec3( cd, cw, 0) * transformMat ); // bottom right
|
||||||
|
v->push_back( osg::Vec3( 0, cw, 0) * transformMat ); // bottom left
|
||||||
|
v->push_back( osg::Vec3( 0, cw, ch) * transformMat ); // top left
|
||||||
|
v->push_back( osg::Vec3( cd, cw, ch) * transformMat ); // top right
|
||||||
|
|
||||||
|
n->push_back( osg::Vec3(0, 1, 0) * rotationMat ); // normal
|
||||||
|
|
||||||
|
// ROOF
|
||||||
|
if (building.pitched) {
|
||||||
|
|
||||||
|
// Front pitched roof
|
||||||
|
v->push_back( osg::Vec3( 0, cw, ch) * transformMat ); // bottom right
|
||||||
|
v->push_back( osg::Vec3( 0, -cw, ch) * transformMat ); // bottom left
|
||||||
|
v->push_back( osg::Vec3(0.5*cd, -cw, ch+3) * transformMat ); // top left
|
||||||
|
v->push_back( osg::Vec3(0.5*cd, cw, ch+3) * transformMat ); // top right
|
||||||
|
n->push_back( osg::Vec3(-0.707, 0, 0.707) * rotationMat ); // normal
|
||||||
|
|
||||||
|
// Left pitched roof
|
||||||
|
v->push_back( osg::Vec3( 0, -cw, ch) * transformMat ); // bottom right
|
||||||
|
v->push_back( osg::Vec3( cd, -cw, ch) * transformMat ); // bottom left
|
||||||
|
v->push_back( osg::Vec3(0.5*cd, -cw, ch+3) * transformMat ); // top left
|
||||||
|
v->push_back( osg::Vec3(0.5*cd, -cw, ch+3) * transformMat ); // top right
|
||||||
|
n->push_back( osg::Vec3(0, -1, 0) * rotationMat ); // normal
|
||||||
|
|
||||||
|
// Back pitched roof
|
||||||
|
v->push_back( osg::Vec3( cd, -cw, ch) * transformMat ); // bottom right
|
||||||
|
v->push_back( osg::Vec3( cd, cw, ch) * transformMat ); // bottom left
|
||||||
|
v->push_back( osg::Vec3(0.5*cd, cw, ch+3) * transformMat ); // top left
|
||||||
|
v->push_back( osg::Vec3(0.5*cd, -cw, ch+3) * transformMat ); // top right
|
||||||
|
n->push_back( osg::Vec3(0.707, 0, 0.707) * rotationMat ); // normal
|
||||||
|
|
||||||
|
// Right pitched roof
|
||||||
|
v->push_back( osg::Vec3( cd, cw, ch) * transformMat ); // bottom right
|
||||||
|
v->push_back( osg::Vec3( 0, cw, ch) * transformMat ); // bottom left
|
||||||
|
v->push_back( osg::Vec3(0.5*cd, cw, ch+3) * transformMat ); // top left
|
||||||
|
v->push_back( osg::Vec3(0.5*cd, cw, ch+3) * transformMat ); // top right
|
||||||
|
n->push_back( osg::Vec3(0, 1, 0) * rotationMat ); // normal
|
||||||
|
} else {
|
||||||
|
// Top face
|
||||||
|
v->push_back( osg::Vec3( 0, cw, ch) * transformMat ); // bottom right
|
||||||
|
v->push_back( osg::Vec3( 0, -cw, ch) * transformMat ); // bottom left
|
||||||
|
v->push_back( osg::Vec3( cd, -cw, ch) * transformMat ); // top left
|
||||||
|
v->push_back( osg::Vec3( cd, cw, ch) * transformMat ); // top right
|
||||||
|
n->push_back( osg::Vec3( 0, 0, 1) * rotationMat ); // 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 base_y = (float) row * 16.0 * 3.0 / 1024.0;
|
||||||
|
float top_y = base_y + 16.0 * (float) building.floors / 1024.0;
|
||||||
|
float left_x = 0.0f;
|
||||||
|
float right_x = 32.0 / 1024.0 * round((float) building.width / 6.0f);
|
||||||
|
float front_x = 384.0/1024.0;
|
||||||
|
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) );
|
||||||
|
}
|
||||||
|
// MAIN BODY
|
||||||
|
// 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
|
||||||
|
t->push_back( osg::Vec2( back_x, top_y ) ); // top left
|
||||||
|
t->push_back( osg::Vec2( front_x, top_y ) ); // top right
|
||||||
|
|
||||||
|
// ROOF
|
||||||
|
if (building.pitched) {
|
||||||
|
// Use the entire height of the roof texture
|
||||||
|
top_y = base_y + 16.0 * 3.0 / 1024.0;
|
||||||
|
left_x = 512/1024.0;
|
||||||
|
right_x = 512/1024.0 + 32.0 / 1024.0 * round(building.width / 6.0f);
|
||||||
|
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
|
||||||
|
t->push_back( osg::Vec2( back_x, top_y ) ); // top left
|
||||||
|
t->push_back( osg::Vec2( front_x, top_y ) ); // top right
|
||||||
|
} else {
|
||||||
|
// Flat roof
|
||||||
|
left_x = 512.0/1024.0;
|
||||||
|
right_x = 640.0/1024.0;
|
||||||
|
// Use the entire height of the roof texture
|
||||||
|
top_y = base_y + 16.0 * 3.0 / 1024.0;
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
float right_x = left_x + 32.0 / 1024.0 * round((float) building.width / 10.0f);
|
||||||
|
|
||||||
|
// BASEMENT - uses the baseline texture
|
||||||
|
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( 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
|
||||||
|
t->push_back( osg::Vec2( left_x, top_y ) ); // top left
|
||||||
|
t->push_back( osg::Vec2( right_x, top_y ) ); // top right
|
||||||
|
|
||||||
|
// ROOF
|
||||||
|
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
|
||||||
|
t->push_back( osg::Vec2( left_x, top_y ) ); // top left
|
||||||
|
t->push_back( osg::Vec2( right_x, top_y ) ); // top right
|
||||||
|
} else {
|
||||||
|
// Flat roof
|
||||||
|
base_y = 416/1024.0;
|
||||||
|
top_y = 576.0/1024.0;
|
||||||
|
right_x = left_x + 32.0 / 1024.0 * 6.0;
|
||||||
|
|
||||||
|
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::LARGE)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
float right_x = left_x + 32.0 / 1024.0 * round((float) building.width / 20.0f);
|
||||||
|
|
||||||
|
// BASEMENT - uses the baseline texture
|
||||||
|
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( 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
|
||||||
|
t->push_back( osg::Vec2( left_x, top_y ) ); // top left
|
||||||
|
t->push_back( osg::Vec2( right_x, top_y ) ); // top right
|
||||||
|
|
||||||
|
// ROOF
|
||||||
|
if (building.pitched) {
|
||||||
|
base_y = 896/1024.0;
|
||||||
|
top_y = 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
|
||||||
|
t->push_back( osg::Vec2( left_x, top_y ) ); // top left
|
||||||
|
t->push_back( osg::Vec2( right_x, top_y ) ); // top right
|
||||||
|
} else {
|
||||||
|
// Flat roof
|
||||||
|
base_y = 896/1024.0;
|
||||||
|
top_y = 1.0;
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the vertex, texture and normals back.
|
||||||
|
geom->setVertexArray(v);
|
||||||
|
geom->setTexCoordArray(0, t);
|
||||||
|
geom->setNormalArray(n);
|
||||||
|
|
||||||
|
geom->setPrimitiveSet(0, new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,v->size()));
|
||||||
|
geode->setDrawable(0, geom);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper classes for creating the quad tree
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
struct MakeBuildingLeaf
|
||||||
|
{
|
||||||
|
MakeBuildingLeaf(float range, Effect* effect) :
|
||||||
|
_range(range), _effect(effect) {}
|
||||||
|
|
||||||
|
MakeBuildingLeaf(const MakeBuildingLeaf& rhs) :
|
||||||
|
_range(rhs._range), _effect(rhs._effect)
|
||||||
|
{}
|
||||||
|
|
||||||
|
LOD* operator() () const
|
||||||
|
{
|
||||||
|
LOD* result = new LOD;
|
||||||
|
|
||||||
|
// Create a series of LOD nodes so trees cover decreases slightly
|
||||||
|
// gradually with distance from _range to 2*_range
|
||||||
|
for (float i = 0.0; i < SG_BUILDING_FADE_OUT_LEVELS; i++)
|
||||||
|
{
|
||||||
|
//osg::ref_ptr<EffectGeode> geode = new EffectGeode();
|
||||||
|
//geode->setEffect(_effect);
|
||||||
|
osg::ref_ptr<osg::Geode> geode = new osg::Geode();
|
||||||
|
result->addChild(geode, 0, _range * (1.0 + i / (SG_BUILDING_FADE_OUT_LEVELS - 1.0)));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
float _range;
|
||||||
|
Effect* _effect;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AddBuildingLeafObject
|
||||||
|
{
|
||||||
|
void operator() (LOD* lod, const SGBuildingBin::Building& building) const
|
||||||
|
{
|
||||||
|
Geode* geode = static_cast<Geode*>(lod->getChild(int(building.position.x() * 10.0f) % lod->getNumChildren()));
|
||||||
|
addBuildingToLeafGeode(geode, building);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GetBuildingCoord
|
||||||
|
{
|
||||||
|
Vec3 operator() (const SGBuildingBin::Building& building) const
|
||||||
|
{
|
||||||
|
return toOsg(building.position);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef QuadTreeBuilder<LOD*, SGBuildingBin::Building, MakeBuildingLeaf, AddBuildingLeafObject,
|
||||||
|
GetBuildingCoord> BuildingGeometryQuadtree;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct BuildingTransformer
|
||||||
|
{
|
||||||
|
BuildingTransformer(Matrix& mat_) : mat(mat_) {}
|
||||||
|
SGBuildingBin::Building operator()(const SGBuildingBin::Building& building) const
|
||||||
|
{
|
||||||
|
Vec3 pos = toOsg(building.position);
|
||||||
|
return SGBuildingBin::Building(toSG(pos * mat), building);
|
||||||
|
}
|
||||||
|
Matrix mat;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 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,
|
||||||
|
const SGReaderWriterOptions* options)
|
||||||
|
{
|
||||||
|
Matrix transInv = Matrix::inverse(transform);
|
||||||
|
static Matrix ident;
|
||||||
|
// Set up some shared structures.
|
||||||
|
MatrixTransform* mt = new MatrixTransform(transform);
|
||||||
|
Effect* effect = makeEffect("Effects/model-default", true);
|
||||||
|
|
||||||
|
SGBuildingBin* bin = NULL;
|
||||||
|
|
||||||
|
BOOST_FOREACH(bin, buildings)
|
||||||
|
{
|
||||||
|
// Now, create a quadbuilding for the buildings.
|
||||||
|
BuildingGeometryQuadtree
|
||||||
|
quadbuilding(GetBuildingCoord(), AddBuildingLeafObject(),
|
||||||
|
SG_BUILDING_QUAD_TREE_DEPTH,
|
||||||
|
MakeBuildingLeaf(20000.0f, effect)); // FIXME - tie to property
|
||||||
|
|
||||||
|
// Transform building positions from the "geocentric" positions we
|
||||||
|
// get from the scenery polys into the local Z-up coordinate
|
||||||
|
// system.
|
||||||
|
std::vector<SGBuildingBin::Building> rotatedBuildings;
|
||||||
|
rotatedBuildings.reserve(bin->buildings.size());
|
||||||
|
std::transform(bin->buildings.begin(), bin->buildings.end(),
|
||||||
|
std::back_inserter(rotatedBuildings),
|
||||||
|
BuildingTransformer(transInv));
|
||||||
|
quadbuilding.buildQuadTree(rotatedBuildings.begin(), rotatedBuildings.end());
|
||||||
|
|
||||||
|
ref_ptr<Group> group = quadbuilding.getRoot();
|
||||||
|
|
||||||
|
// Set up the stateset for this building bin and the texture to use.
|
||||||
|
osg::StateSet* stateSet = group->getOrCreateStateSet();
|
||||||
|
const std::string texturename = bin->texture;
|
||||||
|
osg::Texture2D* texture = SGLoadTexture2D(texturename);
|
||||||
|
texture->setWrap(osg::Texture2D::WRAP_S, osg::Texture2D::CLAMP_TO_EDGE);
|
||||||
|
texture->setWrap(osg::Texture2D::WRAP_T, osg::Texture2D::CLAMP_TO_EDGE);
|
||||||
|
stateSet->setTextureAttributeAndModes(0, texture);
|
||||||
|
|
||||||
|
osg::ShadeModel* shadeModel = new osg::ShadeModel;
|
||||||
|
shadeModel->setMode(osg::ShadeModel::FLAT);
|
||||||
|
stateSet->setAttributeAndModes(shadeModel);
|
||||||
|
stateSet->setMode(GL_LIGHTING, osg::StateAttribute::ON);
|
||||||
|
stateSet->setMode(GL_FOG, osg::StateAttribute::ON);
|
||||||
|
stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON);
|
||||||
|
stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::ON);
|
||||||
|
stateSet->setMode(GL_BLEND, osg::StateAttribute::OFF);
|
||||||
|
stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::OFF);
|
||||||
|
stateSet->setAttribute(new osg::CullFace(osg::CullFace::BACK));
|
||||||
|
|
||||||
|
osg::Material* material = new osg::Material;
|
||||||
|
material->setAmbient(osg::Material::FRONT, osg::Vec4(0.3,0.3,0.3,1.0));
|
||||||
|
material->setDiffuse(osg::Material::FRONT, osg::Vec4(1.0,1.0,1.0,1.0));
|
||||||
|
material->setSpecular(osg::Material::FRONT, osg::Vec4(0,0,0,1.0));
|
||||||
|
material->setShininess(osg::Material::FRONT, 0.0);
|
||||||
|
material->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE);
|
||||||
|
stateSet->setAttribute(material);
|
||||||
|
mt->addChild(group);
|
||||||
|
}
|
||||||
|
|
||||||
|
return mt;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
110
simgear/scene/tgdb/SGBuildingBin.hxx
Normal file
110
simgear/scene/tgdb/SGBuildingBin.hxx
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
/* -*-c++-*-
|
||||||
|
*
|
||||||
|
* Copyright (C) 2011 Stuart Buchanan
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||||
|
* MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SG_BUILDING_BIN_HXX
|
||||||
|
#define SG_BUILDING_BIN_HXX
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <osg/Geometry>
|
||||||
|
#include <osg/Group>
|
||||||
|
#include <osg/Matrix>
|
||||||
|
|
||||||
|
#include <simgear/scene/util/OsgMath.hxx>
|
||||||
|
|
||||||
|
namespace simgear
|
||||||
|
{
|
||||||
|
class SGBuildingBin {
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum BuildingType {
|
||||||
|
SMALL = 0,
|
||||||
|
MEDIUM,
|
||||||
|
LARGE };
|
||||||
|
|
||||||
|
struct Building {
|
||||||
|
Building(BuildingType t, const SGVec3f& p, float w, float d, float h, int f, float rot, bool pitch) :
|
||||||
|
type(t),
|
||||||
|
position(p),
|
||||||
|
width(w),
|
||||||
|
depth(d),
|
||||||
|
height(h),
|
||||||
|
floors(f),
|
||||||
|
rotation(rot),
|
||||||
|
pitched(pitch),
|
||||||
|
radius(std::max(d, 0.5f*w))
|
||||||
|
{ }
|
||||||
|
Building(const SGVec3f& p, Building b) :
|
||||||
|
type(b.type),
|
||||||
|
position(p),
|
||||||
|
width(b.width),
|
||||||
|
depth(b.depth),
|
||||||
|
height(b.height),
|
||||||
|
floors(b.floors),
|
||||||
|
rotation(b.rotation),
|
||||||
|
pitched(b.pitched),
|
||||||
|
radius(std::max(b.depth, 0.5f*b.width))
|
||||||
|
{ }
|
||||||
|
|
||||||
|
BuildingType type;
|
||||||
|
SGVec3f position;
|
||||||
|
float width;
|
||||||
|
float depth;
|
||||||
|
float height;
|
||||||
|
int floors;
|
||||||
|
float rotation;
|
||||||
|
bool pitched;
|
||||||
|
float radius;
|
||||||
|
|
||||||
|
float getFootprint() {
|
||||||
|
return radius;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::vector<Building> BuildingList;
|
||||||
|
BuildingList buildings;
|
||||||
|
|
||||||
|
std::string texture;
|
||||||
|
|
||||||
|
void insert(const Building& model)
|
||||||
|
{
|
||||||
|
buildings.push_back(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
void insert(BuildingType t, const SGVec3f& p, float w, float d, float h, int f, float rot, bool pitch)
|
||||||
|
{ insert(Building(t, p, w, d, h, f, rot, pitch)); }
|
||||||
|
|
||||||
|
unsigned getNumBuildings() const
|
||||||
|
{ return buildings.size(); }
|
||||||
|
const Building& getBuilding(unsigned i) const
|
||||||
|
{ return buildings[i]; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// List of buildings
|
||||||
|
typedef std::list<SGBuildingBin*> SGBuildingBinList;
|
||||||
|
|
||||||
|
osg::Group* createRandomBuildings(SGBuildingBinList buildinglist, const osg::Matrix& transform,
|
||||||
|
const SGReaderWriterOptions* options);
|
||||||
|
}
|
||||||
|
#endif
|
@ -60,6 +60,7 @@
|
|||||||
#include "SGTexturedTriangleBin.hxx"
|
#include "SGTexturedTriangleBin.hxx"
|
||||||
#include "SGLightBin.hxx"
|
#include "SGLightBin.hxx"
|
||||||
#include "SGModelBin.hxx"
|
#include "SGModelBin.hxx"
|
||||||
|
#include "SGBuildingBin.hxx"
|
||||||
#include "TreeBin.hxx"
|
#include "TreeBin.hxx"
|
||||||
#include "SGDirectionalLightBin.hxx"
|
#include "SGDirectionalLightBin.hxx"
|
||||||
#include "GroundLightManager.hxx"
|
#include "GroundLightManager.hxx"
|
||||||
@ -85,6 +86,7 @@ struct SGTileGeometryBin {
|
|||||||
SGLightListBin odalLights;
|
SGLightListBin odalLights;
|
||||||
SGDirectionalLightListBin reilLights;
|
SGDirectionalLightListBin reilLights;
|
||||||
SGMatModelBin randomModels;
|
SGMatModelBin randomModels;
|
||||||
|
SGBuildingBinList randomBuildings;
|
||||||
|
|
||||||
static SGVec4f
|
static SGVec4f
|
||||||
getMaterialLightColor(const SGMaterial* material)
|
getMaterialLightColor(const SGMaterial* material)
|
||||||
@ -445,7 +447,242 @@ struct SGTileGeometryBin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void computeRandomBuildings(SGMaterialLib* matlib, float building_density)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
|
||||||
|
float coverage = mat->get_building_coverage();
|
||||||
|
|
||||||
|
// Minimum spacing needs to include the maximum footprint of a building.
|
||||||
|
// As the 0,0,0 point is the center of the front of the building, we need
|
||||||
|
// to consider the full depth, but only half the possible width.
|
||||||
|
float min_spacing = mat->get_building_spacing();
|
||||||
|
|
||||||
|
if (coverage <= 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
bool found = false;
|
||||||
|
SGBuildingBin* bin = NULL;
|
||||||
|
|
||||||
|
BOOST_FOREACH(bin, randomBuildings)
|
||||||
|
{
|
||||||
|
if (bin->texture == mat->get_building_texture()) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
bin = new SGBuildingBin();
|
||||||
|
bin->texture = mat->get_building_texture();
|
||||||
|
SG_LOG(SG_INPUT, SG_DEBUG, "Building texture " << bin->texture);
|
||||||
|
randomBuildings.push_back(bin);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::pair<SGVec3f, float> > randomPoints;
|
||||||
|
|
||||||
|
unsigned num = i->second.getNumTriangles();
|
||||||
|
int triangle_dropped = 0;
|
||||||
|
int building_dropped = 0;
|
||||||
|
int random_dropped = 0;
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < num; ++i) {
|
||||||
|
SGBuildingBin::BuildingList triangle_buildings;
|
||||||
|
SGTexturedTriangleBin::triangle_ref triangleRef = triangleBin.getTriangleRef(i);
|
||||||
|
|
||||||
|
SGVec3f v0 = triangleBin.getVertex(triangleRef[0]).vertex;
|
||||||
|
SGVec3f v1 = triangleBin.getVertex(triangleRef[1]).vertex;
|
||||||
|
SGVec3f v2 = triangleBin.getVertex(triangleRef[2]).vertex;
|
||||||
|
SGVec2f t0 = triangleBin.getVertex(triangleRef[0]).texCoord;
|
||||||
|
SGVec2f t1 = triangleBin.getVertex(triangleRef[1]).texCoord;
|
||||||
|
SGVec2f t2 = triangleBin.getVertex(triangleRef[2]).texCoord;
|
||||||
|
SGVec3f normal = cross(v1 - v0, v2 - v0);
|
||||||
|
|
||||||
|
// Compute the area
|
||||||
|
float area = 0.5f*length(normal);
|
||||||
|
if (area <= SGLimitsf::min())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// for partial units of area, use a zombie door method to
|
||||||
|
// create the proper random chance of an object being created
|
||||||
|
// for this triangle.
|
||||||
|
double num = area / coverage + mt_rand(&seed);
|
||||||
|
|
||||||
|
// Apply density.
|
||||||
|
num = num * building_density;
|
||||||
|
|
||||||
|
// place an object each unit of area
|
||||||
|
while ( num > 1.0 ) {
|
||||||
|
float a = mt_rand(&seed);
|
||||||
|
float b = mt_rand(&seed);
|
||||||
|
if ( a + b > 1 ) {
|
||||||
|
a = 1 - a;
|
||||||
|
b = 1 - b;
|
||||||
|
}
|
||||||
|
|
||||||
|
float c = 1 - a - b;
|
||||||
|
SGVec3f randomPoint = a*v0 + b*v1 + c*v2;
|
||||||
|
float rotation = mt_rand(&seed);
|
||||||
|
|
||||||
|
if (object_mask != NULL) {
|
||||||
|
SGVec2f texCoord = a*t0 + b*t1 + c*t2;
|
||||||
|
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()) {
|
||||||
|
// Object passes mask. Rotation is taken from the red channel
|
||||||
|
rotation = img->getColor(x,y).r();
|
||||||
|
} else {
|
||||||
|
// Fails mask test - try again.
|
||||||
|
num -= 1.0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now create the building, so we have an idea of its footprint
|
||||||
|
// and therefore appropriate spacing.
|
||||||
|
SGBuildingBin::BuildingType buildingtype;
|
||||||
|
float width;
|
||||||
|
float depth;
|
||||||
|
int floors;
|
||||||
|
float height;
|
||||||
|
bool pitched;
|
||||||
|
|
||||||
|
// Determine the building type, and hence dimensions.
|
||||||
|
float type = mt_rand(&seed);
|
||||||
|
|
||||||
|
if (type < mat->get_building_small_fraction()) {
|
||||||
|
// Small building
|
||||||
|
buildingtype = SGBuildingBin::SMALL;
|
||||||
|
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 = 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));
|
||||||
|
|
||||||
|
if (depth > width) { depth = width; }
|
||||||
|
|
||||||
|
pitched = (mt_rand(&seed) < mat->get_building_small_pitch());
|
||||||
|
} else if (type < (mat->get_building_small_fraction() + mat->get_building_medium_fraction())) {
|
||||||
|
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 = 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));
|
||||||
|
pitched = (mt_rand(&seed) < mat->get_building_medium_pitch());
|
||||||
|
} else {
|
||||||
|
buildingtype = SGBuildingBin::LARGE;
|
||||||
|
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 = 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());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine an appropriate minimum spacing for the object. Note that the
|
||||||
|
// origin of the building model is the center of the front face, hence we
|
||||||
|
// consider the full depth. We choose _not_ to use the diagonal distance
|
||||||
|
// to one of the rear corners, as we assume that terrain masking will
|
||||||
|
// make the buildings place in some sort of grid.
|
||||||
|
float radius = std::max(depth, 0.5f*width);
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
if (((length(cross(randomPoint - v0, randomPoint - v1)) / length(v1 - v0)) < radius) ||
|
||||||
|
((length(cross(randomPoint - v1, randomPoint - v2)) / length(v2 - v1)) < radius) ||
|
||||||
|
((length(cross(randomPoint - v2, randomPoint - v0)) / length(v0 - v2)) < radius) )
|
||||||
|
{
|
||||||
|
triangle_dropped++;
|
||||||
|
num -= 1.0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check against the generic random objects. TODO - make this more efficient by
|
||||||
|
// masking ahead of time objects outside of the triangle.
|
||||||
|
bool too_close = false;
|
||||||
|
for (unsigned int i = 0; i < randomModels.getNumModels(); ++i) {
|
||||||
|
float min_dist = randomModels.getMatModel(i).model->get_spacing_m() + radius + min_spacing;
|
||||||
|
min_dist = min_dist * min_dist;
|
||||||
|
|
||||||
|
if (distSqr(randomModels.getMatModel(i).position, randomPoint) < min_dist) {
|
||||||
|
too_close = true;
|
||||||
|
random_dropped++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (too_close) {
|
||||||
|
// Too close to a random model - drop and try again
|
||||||
|
num -= 1.0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
SGBuildingBin::BuildingList::iterator l;
|
||||||
|
|
||||||
|
// Check that the building is sufficiently far from any other building within the triangle.
|
||||||
|
for (l = triangle_buildings.begin(); l != triangle_buildings.end(); ++l) {
|
||||||
|
|
||||||
|
float min_dist = l->radius + radius + min_spacing;
|
||||||
|
min_dist = min_dist * min_dist;
|
||||||
|
|
||||||
|
if (distSqr(randomPoint, l->position) < min_dist) {
|
||||||
|
building_dropped++;
|
||||||
|
too_close = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (too_close) {
|
||||||
|
// Too close to another building - drop and try again
|
||||||
|
num -= 1.0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we've passed all of the above tests we have a valid
|
||||||
|
// building, so create it!
|
||||||
|
SGBuildingBin::Building building =
|
||||||
|
SGBuildingBin::Building(buildingtype,
|
||||||
|
randomPoint,
|
||||||
|
width,
|
||||||
|
depth,
|
||||||
|
height,
|
||||||
|
floors,
|
||||||
|
rotation,
|
||||||
|
pitched);
|
||||||
|
triangle_buildings.push_back(building);
|
||||||
|
num -= 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the buildings from this triangle to the overall list.
|
||||||
|
SGBuildingBin::BuildingList::iterator l;
|
||||||
|
|
||||||
|
for (l = triangle_buildings.begin(); l != triangle_buildings.end(); ++l) {
|
||||||
|
bin->insert(*l);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SG_LOG(SG_INPUT, SG_DEBUG, "Random Buildings: " << bin->getNumBuildings());
|
||||||
|
SG_LOG(SG_INPUT, SG_DEBUG, " Dropped due to triangle edge: " << triangle_dropped);
|
||||||
|
SG_LOG(SG_INPUT, SG_DEBUG, " Dropped due to random object: " << random_dropped);
|
||||||
|
SG_LOG(SG_INPUT, SG_DEBUG, " Dropped due to other building: " << building_dropped);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void computeRandomForest(SGMaterialLib* matlib, float vegetation_density)
|
void computeRandomForest(SGMaterialLib* matlib, float vegetation_density)
|
||||||
{
|
{
|
||||||
SGMaterialTriangleMap::iterator i;
|
SGMaterialTriangleMap::iterator i;
|
||||||
@ -538,9 +775,9 @@ struct SGTileGeometryBin {
|
|||||||
object->get_spacing_m(),
|
object->get_spacing_m(),
|
||||||
mat->get_object_mask(i->second),
|
mat->get_object_mask(i->second),
|
||||||
randomPoints);
|
randomPoints);
|
||||||
|
|
||||||
std::vector<std::pair<SGVec3f, float> >::iterator l;
|
std::vector<std::pair<SGVec3f, float> >::iterator l;
|
||||||
for (l = randomPoints.begin(); l != randomPoints.end(); ++l) {
|
for (l = randomPoints.begin(); l != randomPoints.end(); ++l) {
|
||||||
|
|
||||||
// Only add the model if it is sufficiently far from the
|
// Only add the model if it is sufficiently far from the
|
||||||
// other models
|
// other models
|
||||||
bool close = false;
|
bool close = false;
|
||||||
@ -551,8 +788,10 @@ struct SGTileGeometryBin {
|
|||||||
|
|
||||||
if (distSqr(randomModels.getMatModel(i).position, l->first) < spacing) {
|
if (distSqr(randomModels.getMatModel(i).position, l->first) < spacing) {
|
||||||
close = true;
|
close = true;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!close) {
|
if (!close) {
|
||||||
randomModels.insert(l->first, object, (int)object->get_randomized_range_m(&seed), l->second);
|
randomModels.insert(l->first, object, (int)object->get_randomized_range_m(&seed), l->second);
|
||||||
}
|
}
|
||||||
@ -563,7 +802,6 @@ struct SGTileGeometryBin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool insertBinObj(const SGBinObject& obj, SGMaterialLib* matlib)
|
bool insertBinObj(const SGBinObject& obj, SGMaterialLib* matlib)
|
||||||
{
|
{
|
||||||
@ -608,7 +846,9 @@ SGLoadBTG(const std::string& path, const simgear::SGReaderWriterOptions* options
|
|||||||
SGMaterialLib* matlib = 0;
|
SGMaterialLib* matlib = 0;
|
||||||
bool use_random_objects = false;
|
bool use_random_objects = false;
|
||||||
bool use_random_vegetation = false;
|
bool use_random_vegetation = false;
|
||||||
float vegetation_density = 1.0f;
|
bool use_random_buildings = false;
|
||||||
|
float vegetation_density = 1.0f;
|
||||||
|
float building_density = 1.0f;
|
||||||
if (options) {
|
if (options) {
|
||||||
matlib = options->getMaterialLib();
|
matlib = options->getMaterialLib();
|
||||||
SGPropertyNode* propertyNode = options->getPropertyNode().get();
|
SGPropertyNode* propertyNode = options->getPropertyNode().get();
|
||||||
@ -618,10 +858,16 @@ SGLoadBTG(const std::string& path, const simgear::SGReaderWriterOptions* options
|
|||||||
use_random_objects);
|
use_random_objects);
|
||||||
use_random_vegetation
|
use_random_vegetation
|
||||||
= propertyNode->getBoolValue("/sim/rendering/random-vegetation",
|
= propertyNode->getBoolValue("/sim/rendering/random-vegetation",
|
||||||
use_random_vegetation);
|
use_random_vegetation);
|
||||||
vegetation_density
|
vegetation_density
|
||||||
= propertyNode->getFloatValue("/sim/rendering/vegetation-density",
|
= propertyNode->getFloatValue("/sim/rendering/vegetation-density",
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -652,75 +898,82 @@ SGLoadBTG(const std::string& path, const simgear::SGReaderWriterOptions* options
|
|||||||
osg::ref_ptr<osg::Group> lightGroup = new SGOffsetTransform(0.94);
|
osg::ref_ptr<osg::Group> lightGroup = new SGOffsetTransform(0.94);
|
||||||
osg::ref_ptr<osg::Group> randomObjects;
|
osg::ref_ptr<osg::Group> randomObjects;
|
||||||
osg::ref_ptr<osg::Group> forestNode;
|
osg::ref_ptr<osg::Group> forestNode;
|
||||||
|
osg::ref_ptr<osg::Group> buildingNode;
|
||||||
osg::Group* terrainGroup = new osg::Group;
|
osg::Group* terrainGroup = new osg::Group;
|
||||||
|
|
||||||
osg::Node* node = tileGeometryBin.getSurfaceGeometry(matlib);
|
osg::Node* node = tileGeometryBin.getSurfaceGeometry(matlib);
|
||||||
if (node)
|
if (node)
|
||||||
terrainGroup->addChild(node);
|
terrainGroup->addChild(node);
|
||||||
|
|
||||||
if (use_random_objects || use_random_vegetation) {
|
if (use_random_objects && matlib) {
|
||||||
if (use_random_objects) {
|
tileGeometryBin.computeRandomObjects(matlib);
|
||||||
if (matlib)
|
|
||||||
tileGeometryBin.computeRandomObjects(matlib);
|
|
||||||
|
|
||||||
if (tileGeometryBin.randomModels.getNumModels() > 0) {
|
|
||||||
// Generate a repeatable random seed
|
|
||||||
mt seed;
|
|
||||||
mt_init(&seed, unsigned(123));
|
|
||||||
|
|
||||||
std::vector<ModelLOD> models;
|
if (tileGeometryBin.randomModels.getNumModels() > 0) {
|
||||||
for (unsigned int i = 0;
|
// Generate a repeatable random seed
|
||||||
i < tileGeometryBin.randomModels.getNumModels(); i++) {
|
mt seed;
|
||||||
SGMatModelBin::MatModel obj
|
mt_init(&seed, unsigned(123));
|
||||||
= tileGeometryBin.randomModels.getMatModel(i);
|
|
||||||
|
|
||||||
SGPropertyNode* root = options->getPropertyNode()->getRootNode();
|
std::vector<ModelLOD> models;
|
||||||
osg::Node* node = obj.model->get_random_model(root, &seed);
|
for (unsigned int i = 0;
|
||||||
|
i < tileGeometryBin.randomModels.getNumModels(); i++) {
|
||||||
// Create a matrix to place the object in the correct
|
SGMatModelBin::MatModel obj
|
||||||
// location, and then apply the rotation matrix created
|
= tileGeometryBin.randomModels.getMatModel(i);
|
||||||
// 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) {
|
SGPropertyNode* root = options->getPropertyNode()->getRootNode();
|
||||||
// Rotate the object around the z axis.
|
osg::Node* node = obj.model->get_random_model(root, &seed);
|
||||||
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->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 (use_random_vegetation && matlib) {
|
|
||||||
// Now add some random forest.
|
|
||||||
tileGeometryBin.computeRandomForest(matlib, vegetation_density);
|
|
||||||
|
|
||||||
if (tileGeometryBin.randomForest.size() > 0) {
|
// Create a matrix to place the object in the correct
|
||||||
forestNode = createForest(tileGeometryBin.randomForest, osg::Matrix::identity(),
|
// location, and then apply the rotation matrix created
|
||||||
options);
|
// above, with an additional random (or taken from
|
||||||
forestNode->setName("Random trees");
|
// 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->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 (use_random_vegetation && matlib) {
|
||||||
|
// Now add some random forest.
|
||||||
|
tileGeometryBin.computeRandomForest(matlib, vegetation_density);
|
||||||
|
|
||||||
|
if (tileGeometryBin.randomForest.size() > 0) {
|
||||||
|
forestNode = createForest(tileGeometryBin.randomForest, osg::Matrix::identity(),
|
||||||
|
options);
|
||||||
|
forestNode->setName("Random trees");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (use_random_buildings && matlib) {
|
||||||
|
tileGeometryBin.computeRandomBuildings(matlib, building_density);
|
||||||
|
if (tileGeometryBin.randomBuildings.size() > 0) {
|
||||||
|
buildingNode = createRandomBuildings(tileGeometryBin.randomBuildings, osg::Matrix::identity(),
|
||||||
|
options);
|
||||||
|
buildingNode->setName("Random buildings");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME: ugly, has a side effect
|
// FIXME: ugly, has a side effect
|
||||||
if (matlib)
|
if (matlib)
|
||||||
tileGeometryBin.computeRandomSurfaceLights(matlib);
|
tileGeometryBin.computeRandomSurfaceLights(matlib);
|
||||||
@ -736,6 +989,7 @@ SGLoadBTG(const std::string& path, const simgear::SGReaderWriterOptions* options
|
|||||||
groundLights0->addChild(geode);
|
groundLights0->addChild(geode);
|
||||||
lightGroup->addChild(groundLights0);
|
lightGroup->addChild(groundLights0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tileGeometryBin.randomTileLights.getNumLights() > 0) {
|
if (tileGeometryBin.randomTileLights.getNumLights() > 0) {
|
||||||
osg::Group* groundLights1 = new osg::Group;
|
osg::Group* groundLights1 = new osg::Group;
|
||||||
groundLights1->setStateSet(lightManager->getGroundLightStateSet());
|
groundLights1->setStateSet(lightManager->getGroundLightStateSet());
|
||||||
@ -778,6 +1032,7 @@ SGLoadBTG(const std::string& path, const simgear::SGReaderWriterOptions* options
|
|||||||
vasiGeode->setStateSet(lightManager->getRunwayLightStateSet());
|
vasiGeode->setStateSet(lightManager->getRunwayLightStateSet());
|
||||||
lightGroup->addChild(vasiGeode);
|
lightGroup->addChild(vasiGeode);
|
||||||
}
|
}
|
||||||
|
|
||||||
Effect* runwayEffect = 0;
|
Effect* runwayEffect = 0;
|
||||||
if (tileGeometryBin.runwayLights.getNumLights() > 0
|
if (tileGeometryBin.runwayLights.getNumLights() > 0
|
||||||
|| !tileGeometryBin.rabitLights.empty()
|
|| !tileGeometryBin.rabitLights.empty()
|
||||||
@ -841,7 +1096,7 @@ SGLoadBTG(const std::string& path, const simgear::SGReaderWriterOptions* options
|
|||||||
transform->addChild(lightLOD);
|
transform->addChild(lightLOD);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (randomObjects.valid() || forestNode.valid()) {
|
if (randomObjects.valid() || forestNode.valid() || buildingNode.valid()) {
|
||||||
|
|
||||||
// Add a LoD node, so we don't try to display anything when the tile center
|
// Add a LoD node, so we don't try to display anything when the tile center
|
||||||
// is more than 20km away.
|
// is more than 20km away.
|
||||||
@ -849,6 +1104,7 @@ SGLoadBTG(const std::string& path, const simgear::SGReaderWriterOptions* options
|
|||||||
|
|
||||||
if (randomObjects.valid()) objectLOD->addChild(randomObjects.get(), 0, 20000);
|
if (randomObjects.valid()) objectLOD->addChild(randomObjects.get(), 0, 20000);
|
||||||
if (forestNode.valid()) objectLOD->addChild(forestNode.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_RECIEVESHADOW_BIT | SG_NODEMASK_TERRAIN_BIT;
|
unsigned nodeMask = SG_NODEMASK_CASTSHADOW_BIT | SG_NODEMASK_RECIEVESHADOW_BIT | SG_NODEMASK_TERRAIN_BIT;
|
||||||
objectLOD->setNodeMask(nodeMask);
|
objectLOD->setNodeMask(nodeMask);
|
||||||
|
Loading…
Reference in New Issue
Block a user