Also adds a property controlling vegetation density.
#include <string.h>
#include <map>
#include <vector>
-#include<string>
+#include <string>
#include <boost/foreach.hpp>
#include "mat.hxx"
{
}
-SGMaterial::_internal_state::_internal_state(Effect *e, const string &t, bool l,
+SGMaterial::_internal_state::_internal_state(Effect *e, const string &t, bool l,
const SGReaderWriterOptions* o)
: effect(e), effect_realized(l), options(o)
{
SGMaterial::read_properties(const SGReaderWriterOptions* options,
const SGPropertyNode *props)
{
- // Gather the path(s) to the texture(s)
+ std::vector<bool> dds;
std::vector<SGPropertyNode_ptr> textures = props->getChildren("texture");
for (unsigned int i = 0; i < textures.size(); i++)
{
string tname = textures[i]->getStringValue();
+
if (tname.empty()) {
tname = "unknown.rgb";
}
+
+ if (tname.rfind(".dds") == (tname.length() - 4)) {
+ dds.push_back(true);
+ } else {
+ dds.push_back(false);
+ }
+
SGPath tpath("Textures.high");
tpath.append(tname);
string fullTexPath = SGModelLib::findDataFile(tpath.str(), options);
tpath.append(tname);
fullTexPath = SGModelLib::findDataFile(tpath.str(), options);
}
-
+
if (!fullTexPath.empty() ) {
_internal_state st( NULL, fullTexPath, false, options );
_status.push_back( st );
if (tname.empty()) {
tname = "unknown.rgb";
}
+
+ if (j == 0) {
+ if (tname.rfind(".dds") == (tname.length() - 4)) {
+ dds.push_back(true);
+ } else {
+ dds.push_back(false);
+ }
+ }
+
SGPath tpath("Textures.high");
tpath.append(tname);
string fullTexPath = SGModelLib::findDataFile(tpath.str(), options);
tpath.append(tname);
fullTexPath = SGModelLib::findDataFile(tpath.str(), options);
}
+
st.add_texture(fullTexPath, textures[j]->getIndex());
}
_internal_state st( NULL, tpath.str(), true, options );
_status.push_back( st );
}
+
+ std::vector<SGPropertyNode_ptr> masks = props->getChildren("object-mask");
+ for (unsigned int i = 0; i < masks.size(); i++)
+ {
+ string omname = masks[i]->getStringValue();
+
+ if (! omname.empty()) {
+ SGPath ompath("Textures.high");
+ ompath.append(omname);
+ string fullMaskPath = SGModelLib::findDataFile(ompath.str(), options);
+
+ if (fullMaskPath.empty()) {
+ ompath = SGPath("Textures");
+ ompath.append(omname);
+ fullMaskPath = SGModelLib::findDataFile(ompath.str(), options);
+ }
+
+ osg::Image* image = osgDB::readImageFile(fullMaskPath, options);
+ if (image->valid())
+ {
+ osg::Texture2D* object_mask = new osg::Texture2D;
+
+ if (dds[i]) {
+ // Texture is a DDS. This is relevant for the object mask, as DDS
+ // textures have an origin at the bottom left rather than top
+ // left, therefore we flip the object mask vertically.
+ image->flipVertical();
+ }
+
+ object_mask->setImage(image);
+ object_mask->setDataVariance(osg::Object::STATIC);
+ object_mask->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);
+ object_mask->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT);
+ _masks.push_back(object_mask);
+ }
+ }
+ }
xsize = props->getDoubleValue("xsize", 0.0);
ysize = props->getDoubleValue("ysize", 0.0);
string treeTexPath = props->getStringValue("tree-texture");
tree_texture = SGModelLib::findDataFile(treeTexPath, options);
}
-
+
// surface values for use with ground reactions
solid = props->getBoolValue("solid", true);
friction_factor = props->getDoubleValue("friction-factor", 1.0);
SGMaterial::init ()
{
_status.clear();
- _current_ptr = 0;
xsize = 0;
ysize = 0;
wrapu = true;
effect = "Effects/terrain-default";
}
-Effect* SGMaterial::get_effect(int n)
+Effect* SGMaterial::get_effect(int i)
+{
+ if(!_status[i].effect_realized) {
+ _status[i].effect->realizeTechniques(_status[i].options.get());
+ _status[i].effect_realized = true;
+ }
+ return _status[i].effect.get();
+}
+
+Effect* SGMaterial::get_effect(SGTexturedTriangleBin triangleBin)
{
if (_status.size() == 0) {
SG_LOG( SG_GENERAL, SG_WARN, "No effect available.");
return 0;
}
- int i = n >= 0 ? n : _current_ptr;
- if(!_status[i].effect_realized) {
- _status[i].effect->realizeTechniques(_status[i].options.get());
- _status[i].effect_realized = true;
+
+ int i = triangleBin.getTextureIndex() % _status.size();
+ return get_effect(i);
+}
+
+Effect* SGMaterial::get_effect()
+{
+ return get_effect(0);
+}
+
+
+osg::Texture2D* SGMaterial::get_object_mask(SGTexturedTriangleBin triangleBin)
+{
+ if (_status.size() == 0) {
+ SG_LOG( SG_GENERAL, SG_WARN, "No mask available.");
+ return 0;
+ }
+
+ // Note that the object mask is closely linked to the texture/effect
+ // so we index based on the texture index,
+ unsigned int i = triangleBin.getTextureIndex() % _status.size();
+ if (i < _masks.size()) {
+ return _masks[i];
+ } else {
+ return 0;
}
- // XXX This business of returning a "random" alternate texture is
- // really bogus. It means that the appearance of the terrain
- // depends on the order in which it is paged in!
- _current_ptr = (_current_ptr + 1) % _status.size();
- return _status[i].effect.get();
}
void SGMaterial::buildEffectProperties(const SGReaderWriterOptions* options)
#include <map>
#include <simgear/math/SGMath.hxx>
+#include "Effect.hxx"
+#include <simgear/scene/tgdb/SGTexturedTriangleBin.hxx>
#include <osg/ref_ptr>
+#include <osg/Texture2D>
namespace osg
{
/**
* Get the textured state.
*/
- simgear::Effect *get_effect(int n = -1);
+ simgear::Effect* get_effect(SGTexturedTriangleBin triangleBin);
+ simgear::Effect* get_effect();
+
+ /**
+ * Get the textured state.
+ */
+ osg::Texture2D* get_object_mask(SGTexturedTriangleBin triangleBin);
+
/**
* Get the number of textures assigned to this material.
* @return the texture to use for trees.
*/
inline std::string get_tree_texture () const { return tree_texture; }
-
+
/**
* Return if the surface material is solid, if it is not solid, a fluid
* can be assumed, that is usually water.
// texture status
std::vector<_internal_state> _status;
- // Round-robin counter
- mutable unsigned int _current_ptr;
-
// texture size
double xsize, ysize;
// Tree texture, typically a strip of applicable tree textures
std::string tree_texture;
+
+ // Object mask, a simple RGB texture used as a mask when placing
+ // random vegetation, objects and buildings
+ std::vector<osg::Texture2D*> _masks;
\f
////////////////////////////////////////////////////////////////////
// Internal constructors and methods.
void read_properties(const simgear::SGReaderWriterOptions* options,
const SGPropertyNode *props);
void buildEffectProperties(const simgear::SGReaderWriterOptions* options);
+ simgear::Effect* get_effect(int i);
};
SGMatModel::SGMatModel (const SGPropertyNode * node, double range_m)
: _models_loaded(false),
_coverage_m2(node->getDoubleValue("coverage-m2", 1000000)),
+ _spacing_m(node->getDoubleValue("spacing-m", 20)),
_range_m(range_m)
{
// Sanity check
_heading_type = HEADING_BILLBOARD;
} else if (hdg == "random") {
_heading_type = HEADING_RANDOM;
+ } else if (hdg == "mask") {
+ _heading_type = HEADING_MASK;
} else {
_heading_type = HEADING_FIXED;
SG_LOG(SG_INPUT, SG_ALERT, "Unknown heading type: " << hdg
}
osg::Node*
-SGMatModel::get_random_model( SGPropertyNode *prop_root, mt seed )
+SGMatModel::get_random_model( SGPropertyNode *prop_root, mt* seed )
{
load_models( prop_root ); // comment this out if preloading models
int nModels = _models.size();
- return _models[mt_rand(&seed) * nModels].get();
+ return _models[mt_rand(seed) * nModels].get();
}
double
return _range_m;
}
+double SGMatModel::get_spacing_m() const
+{
+ return _spacing_m;
+}
+
double SGMatModel::get_randomized_range_m(mt* seed) const
{
double lrand = mt_rand(seed);
enum HeadingType {
HEADING_FIXED,
HEADING_BILLBOARD,
- HEADING_RANDOM
+ HEADING_RANDOM,
+ HEADING_MASK
};
/**
*
* @return A randomly select model from the variants.
*/
- osg::Node *get_random_model( SGPropertyNode *prop_root, mt seed );
+ osg::Node *get_random_model( SGPropertyNode *prop_root, mt *seed );
/**
* @return The visual range.
*/
double get_range_m () const;
+
+ /**
+ * Get the minimum spacing between this and any
+ * other objects in m
+ *
+ * @return The spacing in m.
+ */
+ double get_spacing_m () const;
+
/**
* Get a randomized visual range
mutable std::vector<osg::ref_ptr<osg::Node> > _models;
mutable bool _models_loaded;
double _coverage_m2;
+ double _spacing_m;
double _range_m;
HeadingType _heading_type;
};
class SGMatModelBin {
public:
struct MatModel {
- MatModel(const SGVec3f& p, SGMatModel *m, int l) :
- position(p), model(m), lod(l)
+ MatModel(const SGVec3f& p, SGMatModel *m, int l, float rot) :
+ position(p), model(m), lod(l), rotation(rot)
{ }
SGVec3f position;
SGMatModel *model;
int lod;
+ float rotation;
};
typedef std::vector<MatModel> MatModelList;
_models.push_back(model);
}
- void insert(const SGVec3f& p, SGMatModel *m, int l)
- { insert(MatModel(p, m, l)); }
+ void insert(const SGVec3f& p, SGMatModel *m, int l, float rot)
+ { insert(MatModel(p, m, l, rot)); }
unsigned getNumModels() const
{ return _models.size(); }
SGMaterialLib* matlib = 0;
bool useRandomObjects = false;
bool useRandomVegetation = false;
+ float vegetation_density = 1.0f;
const SGReaderWriterOptions* sgOptions;
sgOptions = dynamic_cast<const SGReaderWriterOptions*>(options);
if (sgOptions) {
useRandomVegetation
= propertyNode->getBoolValue("/sim/rendering/random-vegetation",
useRandomVegetation);
+ vegetation_density
+ = propertyNode->getFloatValue("/sim/rendering/vegetation-density",
+ vegetation_density);
}
}
osg::Node* result = SGLoadBTG(fileName, matlib,
useRandomObjects,
- useRandomVegetation);
+ useRandomVegetation,
+ vegetation_density);
if (result)
return result;
else
#include <osg/Array>
#include <osg/Geometry>
#include <osg/PrimitiveSet>
+#include <osg/Texture2D>
+#include <stdio.h>
#include <simgear/math/sg_random.h>
#include <simgear/math/SGMath.hxx>
// The points are offsetted away from the triangles in
// offset * positive normal direction.
void addRandomSurfacePoints(float coverage, float offset,
+ osg::Texture2D* object_mask,
std::vector<SGVec3f>& points)
{
unsigned num = getNumTriangles();
SGVec3f v0 = getVertex(triangleRef[0]).vertex;
SGVec3f v1 = getVertex(triangleRef[1]).vertex;
SGVec3f v2 = getVertex(triangleRef[2]).vertex;
+ SGVec2f t0 = getVertex(triangleRef[0]).texCoord;
+ SGVec2f t1 = getVertex(triangleRef[1]).texCoord;
+ SGVec2f t2 = getVertex(triangleRef[2]).texCoord;
SGVec3f normal = cross(v1 - v0, v2 - v0);
// Compute the area
}
float c = 1 - a - b;
SGVec3f randomPoint = offsetVector + a*v0 + b*v1 + c*v2;
- points.push_back(randomPoint);
- unit -= coverage;
+
+ if (object_mask != NULL) {
+ SGVec2f texCoord = a*t0 + b*t1 + c*t2;
+
+ // Check this random point against the object mask
+ // red channel.
+ osg::Image* img = object_mask->getImage();
+ unsigned int x = (int) (img->s() * texCoord.x()) % img->s();
+ unsigned int y = (int) (img->t() * texCoord.y()) % img->t();
+
+ if (mt_rand(&seed) < img->getColor(x, y).r()) {
+ points.push_back(randomPoint);
+ }
+ } else {
+ // No object mask, so simply place the object
+ points.push_back(randomPoint);
+ }
+ unit -= coverage;
}
}
}
void addRandomTreePoints(float wood_coverage,
float tree_density,
float wood_size,
+ osg::Texture2D* object_mask,
+ float vegetation_density,
std::vector<SGVec3f>& points)
{
unsigned num = getNumTriangles();
SGVec3f v0 = getVertex(triangleRef[0]).vertex;
SGVec3f v1 = getVertex(triangleRef[1]).vertex;
SGVec3f v2 = getVertex(triangleRef[2]).vertex;
+ SGVec2f t0 = getVertex(triangleRef[0]).texCoord;
+ SGVec2f t1 = getVertex(triangleRef[1]).texCoord;
+ SGVec2f t2 = 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 a point being created
- // for this triangle
- float unit = area + mt_rand(&seed)*wood_coverage;
- int woodcount = (int) (unit / wood_coverage);
-
- for (int j = 0; j < woodcount; j++) {
-
- if (wood_size < area) {
- // We need to place a wood within the triangle and populate it
-
- // Determine the center of the wood
- float x = mt_rand(&seed);
- float y = mt_rand(&seed);
+ if (object_mask != NULL) {
+ // For partial units of area, use a zombie door method to
+ // create the proper random chance of a point being created
+ // for this triangle
+ float unit = area + mt_rand(&seed)*wood_coverage;
+
+ // Vegetation density is linear, while we're creating woodland
+ // by area.
+ int woodcount = (int) (vegetation_density *
+ vegetation_density *
+ unit / wood_coverage);
+
+ for (int j = 0; j < woodcount; j++) {
+ float a = mt_rand(&seed);
+ float b = mt_rand(&seed);
+
+ if ( a + b > 1.0f ) {
+ a = 1.0f - a;
+ b = 1.0f - b;
+ }
- // Determine the size of this wood in m^2, and the number
- // of trees in the wood
- float ws = wood_size + wood_size * (mt_rand(&seed) - 0.5f);
- unsigned total_trees = ws / tree_density;
- float wood_length = sqrt(ws);
+ float c = 1.0f - a - b;
+
+ SGVec3f randomPoint = a*v0 + b*v1 + c*v2;
+ SGVec2f texCoord = a*t0 + b*t1 + c*t2;
+
+ // Check this random point against the object mask
+ // green channel.
+ osg::Image* img = object_mask->getImage();
+ unsigned int x = (int) (img->s() * texCoord.x()) % img->s();
+ unsigned int y = (int) (img->t() * texCoord.y()) % img->t();
+
+ if (mt_rand(&seed) < img->getColor(x, y).g()) {
+ points.push_back(randomPoint);
+ }
+ }
+ } else {
+ // For partial units of area, use a zombie door method to
+ // create the proper random chance of a point being created
+ // for this triangle
+ float unit = area + mt_rand(&seed)*wood_coverage;
+ int woodcount = (int) (unit / wood_coverage);
+
+ if (wood_size < 1.0) {
+ // A wood size of 0 is used for an even spread of woodland,
+ // where each wood contains a single tree. In this case we
+ // need to apply the vegetation_density to the wood count rather
+ // than the tree density.
+ woodcount = woodcount * vegetation_density;
+ }
+
+ for (int j = 0; j < woodcount; j++) {
+
+ if (wood_size < area) {
+ // We need to place a wood within the triangle and populate it
+
+ // Determine the center of the wood
+ float x = mt_rand(&seed);
+ float y = mt_rand(&seed);
+
+ // Determine the size of this wood in m^2, and the number
+ // of trees in the wood
+ float ws = wood_size + wood_size * (mt_rand(&seed) - 0.5f);
+ unsigned total_trees = ws / tree_density;
+
+ if (wood_size >= 1.0) {
+ total_trees = total_trees * vegetation_density;
+ }
+
+ float wood_length = sqrt(ws);
- // From our wood size, work out the fraction on the two axis.
- // This will be used as a factor when placing trees in the wood.
- float x_tree_factor = wood_length / length(v1 -v0);
- float y_tree_factor = wood_length / length(v2 -v0);
+ // From our wood size, work out the fraction on the two axis.
+ // This will be used as a factor when placing trees in the wood.
+ float x_tree_factor = wood_length / length(v1 -v0);
+ float y_tree_factor = wood_length / length(v2 -v0);
- for (unsigned k = 0; k <= total_trees; k++) {
+ for (unsigned k = 0; k <= total_trees; k++) {
- float a = x + x_tree_factor * (mt_rand(&seed) - 0.5f);
- float b = y + y_tree_factor * (mt_rand(&seed) - 0.5f);
+ float a = x + x_tree_factor * (mt_rand(&seed) - 0.5f);
+ float b = y + y_tree_factor * (mt_rand(&seed) - 0.5f);
- // In some cases, the triangle side lengths are so small that the
- // tree_factors become so large as to make placing the tree within
- // the triangle almost impossible. In this case, we place them
- // randomly across the triangle.
- if (a < 0.0f || a > 1.0f) a = mt_rand(&seed);
- if (b < 0.0f || b > 1.0f) b = mt_rand(&seed);
-
- if ( a + b > 1.0f ) {
- a = 1.0f - a;
- b = 1.0f - b;
- }
+ // In some cases, the triangle side lengths are so small that the
+ // tree_factors become so large as to make placing the tree within
+ // the triangle almost impossible. In this case, we place them
+ // randomly across the triangle.
+ if (a < 0.0f || a > 1.0f) a = mt_rand(&seed);
+ if (b < 0.0f || b > 1.0f) b = mt_rand(&seed);
- float c = 1.0f - a - b;
+ if ( a + b > 1.0f ) {
+ a = 1.0f - a;
+ b = 1.0f - b;
+ }
+
+ float c = 1.0f - a - b;
+ SGVec3f randomPoint = a*v0 + b*v1 + c*v2;
+ points.push_back(randomPoint);
+ }
+ } else {
+ // This triangle is too small to contain a complete wood, so just
+ // distribute trees across it.
+ unsigned total_trees = area / tree_density;
- SGVec3f randomPoint = a*v0 + b*v1 + c*v2;
+ for (unsigned k = 0; k <= total_trees; k++) {
- points.push_back(randomPoint);
- }
- } else {
- // This triangle is too small to contain a complete wood, so just
- // distribute trees across it.
- unsigned total_trees = area / tree_density;
+ float a = mt_rand(&seed);
+ float b = mt_rand(&seed);
- for (unsigned k = 0; k <= total_trees; k++) {
+ if ( a + b > 1.0f ) {
+ a = 1.0f - a;
+ b = 1.0f - b;
+ }
- float a = mt_rand(&seed);
- float b = mt_rand(&seed);
+ float c = 1.0f - a - b;
- if ( a + b > 1.0f ) {
- a = 1.0f - a;
- b = 1.0f - b;
+ SGVec3f randomPoint = a*v0 + b*v1 + c*v2;
+ SGVec2f texCoord = a*t0 + b*t1 + c*t2;
+ points.push_back(randomPoint);
}
-
- float c = 1.0f - a - b;
-
- SGVec3f randomPoint = a*v0 + b*v1 + c*v2;
- points.push_back(randomPoint);
}
}
}
}
void addRandomPoints(float coverage,
- std::vector<SGVec3f>& points)
+ osg::Texture2D* object_mask,
+ std::vector<std::pair<SGVec3f, float> >& points)
{
unsigned num = getNumTriangles();
for (unsigned i = 0; i < num; ++i) {
SGVec3f v0 = getVertex(triangleRef[0]).vertex;
SGVec3f v1 = getVertex(triangleRef[1]).vertex;
SGVec3f v2 = getVertex(triangleRef[2]).vertex;
+ SGVec2f t0 = getVertex(triangleRef[0]).texCoord;
+ SGVec2f t1 = getVertex(triangleRef[1]).texCoord;
+ SGVec2f t2 = getVertex(triangleRef[2]).texCoord;
SGVec3f normal = cross(v1 - v0, v2 - v0);
// Compute the area
}
float c = 1 - a - b;
SGVec3f randomPoint = a*v0 + b*v1 + c*v2;
- points.push_back(randomPoint);
+
+ if (object_mask != NULL) {
+ SGVec2f texCoord = a*t0 + b*t1 + c*t2;
+
+ // Check this random point against the object mask
+ // blue (for buildings) channel. Also check
+ // that they are more than spacing metres away from
+ // any other point.
+ 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()) {
+ // The red channel contains the rotation for this object
+ points.push_back(std::make_pair(randomPoint, img->getColor(x,y).r()));
+ }
+ } else {
+ points.push_back(std::make_pair(randomPoint, mt_rand(&seed)));
+ }
num -= 1.0;
}
}
osg::Geometry* buildGeometry() const
{ return buildGeometry(getTriangles()); }
+
+ int getTextureIndex() {
+ if (empty() || getNumTriangles() == 0)
+ return 0;
+
+ triangle_ref triangleRef = getTriangleRef(0);
+ SGVec3f v0 = getVertex(triangleRef[0]).vertex;
+
+ return floor(v0.x());
+ }
private:
// Random seed for the triangle.
#include <boost/foreach.hpp>
+#include <algorithm>
+
#include <simgear/debug/logstream.hxx>
#include <simgear/io/sg_binobj.hxx>
#include <simgear/math/sg_geodesy.hxx>
mat = matlib->find(i->first);
eg = new EffectGeode;
if (mat)
- eg->setEffect(mat->get_effect());
+ eg->setEffect(mat->get_effect(i->second));
eg->addDrawable(geometry);
eg->runGenerators(geometry); // Generate extra data needed by effect
if (group)
}
std::vector<SGVec3f> randomPoints;
- i->second.addRandomSurfacePoints(coverage, 3, randomPoints);
+ i->second.addRandomSurfacePoints(coverage, 3, mat->get_object_mask(i->second), randomPoints);
std::vector<SGVec3f>::iterator j;
for (j = randomPoints.begin(); j != randomPoints.end(); ++j) {
float zombie = mt_rand(&seed);
}
}
- void computeRandomForest(SGMaterialLib* matlib)
+ void computeRandomForest(SGMaterialLib* matlib, float vegetation_density)
{
SGMaterialTriangleMap::iterator i;
i->second.addRandomTreePoints(wood_coverage,
mat->get_tree_density(),
mat->get_wood_size(),
+ mat->get_object_mask(i->second),
+ vegetation_density,
randomPoints);
std::vector<SGVec3f>::iterator k;
for (int k = 0; k < nObjects; k++) {
SGMatModel * object = object_group->get_object(k);
- std::vector<SGVec3f> randomPoints;
+ std::vector<std::pair<SGVec3f, float> > randomPoints;
- i->second.addRandomPoints(object->get_coverage_m2(), randomPoints);
- std::vector<SGVec3f>::iterator l;
+ i->second.addRandomPoints(object->get_coverage_m2(),
+ mat->get_object_mask(i->second),
+ randomPoints);
+ std::vector<std::pair<SGVec3f, float> >::iterator l;
for (l = randomPoints.begin(); l != randomPoints.end(); ++l) {
- randomModels.insert(*l, object, (int)object->get_randomized_range_m(&seed));
+
+ // Only add the model if it is sufficiently far from the
+ // other models
+ bool close = false;
+
+ for (unsigned i = 0; i < randomModels.getNumModels(); i++) {
+ float spacing = std::max(randomModels.getMatModel(i).model->get_spacing_m(), object->get_spacing_m());
+ spacing = spacing * spacing;
+
+ if (distSqr(randomModels.getMatModel(i).position, l->first) < spacing) {
+ close = true;
+ }
+ }
+ if (!close) {
+ randomModels.insert(l->first, object, (int)object->get_randomized_range_m(&seed), l->second);
+ }
}
}
}
}
}
}
+
bool insertBinObj(const SGBinObject& obj, SGMaterialLib* matlib)
{
GetModelLODCoord> RandomObjectsQuadtree;
osg::Node*
-SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool use_random_objects, bool use_random_vegetation)
+SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool use_random_objects, bool use_random_vegetation, float vegetation_density)
{
SGBinObject tile;
if (!tile.read_bin(path))
for (unsigned int i = 0;
i < tileGeometryBin.randomModels.getNumModels(); i++) {
SGMatModelBin::MatModel obj
- = tileGeometryBin.randomModels.getMatModel(i);
- osg::Node* node = sgGetRandomModel(obj.model, seed);
+ = tileGeometryBin.randomModels.getMatModel(i);
+
+ osg::Node* node = sgGetRandomModel(obj.model, &seed);
// Create a matrix to place the object in the correct
// location, and then apply the rotation matrix created
- // above, with an additional random heading rotation if appropriate.
+ // 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) {
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);
if (use_random_vegetation && matlib) {
// Now add some random forest.
- tileGeometryBin.computeRandomForest(matlib);
+ tileGeometryBin.computeRandomForest(matlib, vegetation_density);
if (tileGeometryBin.randomForest.size() > 0) {
forestNode = createForest(tileGeometryBin.randomForest, osg::Matrix::identity());
}
osg::Node*
-SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool use_random_objects, bool use_random_vegetation);
+SGLoadBTG(const std::string& path,
+ SGMaterialLib *matlib,
+ bool use_random_objects,
+ bool use_random_vegetation,
+ float vegetation_density);
#endif // _SG_OBJ_HXX
root_props = p;
}
-osg::Node* sgGetRandomModel(SGMatModel *obj, mt seed) {
+osg::Node* sgGetRandomModel(SGMatModel *obj, mt *seed) {
return obj->get_random_model( root_props, seed );
}
/**
* Get a random model.
*/
-osg::Node* sgGetRandomModel(SGMatModel *obj, mt seed);
+osg::Node* sgGetRandomModel(SGMatModel *obj, mt *seed);
namespace simgear
{