tree_height = props->getDoubleValue("tree-height-m", 0.0);
tree_width = props->getDoubleValue("tree-width-m", 0.0);
tree_range = props->getDoubleValue("tree-range-m", 0.0);
+ tree_varieties = props->getIntValue("tree-varieties", 1);
+
+ SGPath tpath( fg_root );
+ tpath.append(props->getStringValue("tree-texture"));
+ tree_texture = tpath.str();
// surface values for use with ground reactions
solid = props->getBoolValue("solid", true);
for (unsigned int i = 0; i < object_group_nodes.size(); i++)
object_groups.push_back(new SGMatModelGroup(object_group_nodes[i]));
- vector<SGPropertyNode_ptr> tree_texture_nodes =
- ((SGPropertyNode *)props)->getChildren("tree-texture");
- for (unsigned int i = 0; i < tree_texture_nodes.size(); i++) {
- SGPath tpath( fg_root );
- tpath.append(tree_texture_nodes[i]->getStringValue());
- tree_textures.push_back(tpath.str());
- }
-
// read glyph table for taxi-/runway-signs
vector<SGPropertyNode_ptr> glyph_nodes = props->getChildren("glyph");
for (unsigned int i = 0; i < glyph_nodes.size(); i++) {
inline double get_tree_range () const { return tree_range; }
/**
- * Get the list of textures to use for trees in the forest
+ * Get the number of tree varieties available
*
- * @return the vector of forest textures to use.
+ * @return the number of different trees defined in the texture strip
*/
- inline vector<string> get_tree_textures () const { return tree_textures; }
+ inline int get_tree_varieties () const { return tree_varieties; }
+
+ /**
+ * Get the texture strip to use for trees
+ *
+ * @return the texture to use for trees.
+ */
+ inline string get_tree_texture () const { return tree_texture; }
/**
* Return if the surface material is solid, if it is not solid, a fluid
// Width of the tree
double tree_width;
+ // Number of varieties of tree texture
+ int tree_varieties;
+
// True if the material is solid, false if it is a fluid
bool solid;
// taxiway-/runway-sign texture elements
map<string, SGSharedPtr<SGMaterialGlyph> > glyphs;
- // The list of forest textures, used when creating trees
- vector<string> tree_textures;
+ // Tree texture, typically a strip of applicable tree textures
+ string tree_texture;
\f
////////////////////////////////////////////////////////////////////
// Internal constructors and methods.
return _objects[index];
}
-
-
-
// end of matmodel.cxx
SGMaterialLib* matlib = 0;
bool calcLights = false;
bool useRandomObjects = false;
+ bool useRandomVegetation = false;
const SGReaderWriterBTGOptions* btgOptions
= dynamic_cast<const SGReaderWriterBTGOptions*>(options);
if (btgOptions) {
matlib = btgOptions->getMatlib();
calcLights = btgOptions->getCalcLights();
useRandomObjects = btgOptions->getUseRandomObjects();
+ useRandomVegetation = btgOptions->getUseRandomVegetation();
}
osg::Node* result = SGLoadBTG(fileName, matlib, calcLights,
- useRandomObjects);
+ useRandomObjects,
+ useRandomVegetation);
if (result)
return result;
else
SGReaderWriterBTGOptions() {}
SGReaderWriterBTGOptions(const std::string& str):
osgDB::ReaderWriter::Options(str),
- _matlib(0), _calcLights(false), _useRandomObjects(false)
+ _matlib(0), _calcLights(false),
+ _useRandomObjects(false),
+ _useRandomVegetation(false)
{}
SGReaderWriterBTGOptions(const SGReaderWriterBTGOptions& options,
const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY):
osgDB::ReaderWriter::Options(options, copyop),
_matlib(options._matlib), _calcLights(options._calcLights),
- _useRandomObjects(options._useRandomObjects)
+ _useRandomObjects(options._useRandomObjects),
+ _useRandomVegetation(options._useRandomVegetation)
{
}
SGMaterialLib* getMatlib() const { return _matlib; }
bool getCalcLights() const { return _calcLights; }
void setCalcLights(bool calcLights) { _calcLights = calcLights; }
bool getUseRandomObjects() const { return _useRandomObjects; }
+ bool getUseRandomVegetation() const { return _useRandomVegetation; }
void setUseRandomObjects(bool useRandomObjects)
{
_useRandomObjects = useRandomObjects;
}
+ void setUseRandomVegetation(bool useRandomVegetation)
+ {
+ _useRandomVegetation = useRandomVegetation;
+ }
+
protected:
virtual ~SGReaderWriterBTGOptions() {}
SGMaterialLib* _matlib;
bool _calcLights;
bool _useRandomObjects;
-
+ bool _useRandomVegetation;
};
#endif
#include <osgDB/Registry>
#include <osgDB/Input>
#include <osgDB/ParameterOutput>
+#include <simgear/screen/extensions.hxx>
#include "ShaderGeometry.hxx"
{
void ShaderGeometry::drawImplementation(RenderInfo& renderInfo) const
{
- for(PositionSizeList::const_iterator itr = _trees.begin();
- itr != _trees.end();
- ++itr) {
- glColor4fv(itr->ptr());
+ osg::State& state = *renderInfo.getState();
+ const Extensions* extensions = getExtensions(state.getContextID(),true);
+
+ for(TreeBin::TreeList::const_iterator t = _trees.begin(); t != _trees.end(); ++t)
+ {
+ extensions->glVertexAttrib1f(1, (float) t->texture_index/varieties);
+ glColor4f(t->position.x(), t->position.y(), t->position.z(), t->scale);
_geometry->draw(renderInfo);
}
}
{
BoundingBox geom_box = _geometry->getBound();
BoundingBox bb;
- for(PositionSizeList::const_iterator itr = _trees.begin();
+ for(TreeBin::TreeList::const_iterator itr = _trees.begin();
itr != _trees.end();
++itr) {
- bb.expandBy(geom_box.corner(0)*(*itr)[3] +
- Vec3((*itr)[0], (*itr)[1], (*itr)[2]));
- bb.expandBy(geom_box.corner(7)*(*itr)[3] +
- Vec3((*itr)[0], (*itr)[1], (*itr)[2]));
+ bb.expandBy(geom_box.corner(0)*itr->scale +
+ osg::Vec3( itr->position.x(), itr->position.y(), itr->position.z() ));
+ bb.expandBy(geom_box.corner(7)*itr->scale +
+ osg::Vec3( itr->position.x(), itr->position.y(), itr->position.z() ));
}
return bb;
}
if ((fr[0].matchWord("geometry"))) {
++fr;
iteratorAdvanced = true;
- Drawable* drawable = fr.readDrawable();
+ osg::Drawable* drawable = fr.readDrawable();
if (drawable) {
geom._geometry = drawable;
}
iteratorAdvanced = true;
// skip {
while (!fr.eof() && fr[0].getNoNestedBrackets() > entry) {
- Vec4 v;
+ SGVec3f v;
+ int t;
+ float s;
if (fr[0].getFloat(v.x()) && fr[1].getFloat(v.y())
- && fr[2].getFloat(v.z()) && fr[3].getFloat(v.w())) {
+ && fr[2].getFloat(v.z()) && fr[3].getInt(t) && fr[4].getFloat(s)) {
fr += 4;
- geom._trees.push_back(v);
+ //SGVec3f* v = new SGVec3f(v.x(), v.y(), v.z());
+ //TreeBin::Tree tree = new TreeBin::Tree(v, t, s);
+ geom._trees.push_back(TreeBin::Tree(v, t, s));
} else {
++fr;
}
fw.indent() << "instances " << geom._trees.size() << std::endl;
fw.indent() << "{" << std::endl;
fw.moveIn();
- for (ShaderGeometry::PositionSizeList::const_iterator iter
+ for (TreeBin::TreeList::const_iterator iter
= geom._trees.begin();
iter != geom._trees.end();
++iter) {
- fw.indent() << iter->x() << " " << iter->y() << " " << iter->z() << " "
- << iter->w() << std::endl;
+ fw.indent() << iter->position.x() << " " << iter->position.y() << " " << iter->position.z() << " "
+ << iter->texture_index << " " << iter->scale << std::endl;
}
fw.moveOut();
fw.indent() << "}" << std::endl;
#include <osg/Vec3>
#include <osg/Vec4>
+#include "TreeBin.hxx"
+
namespace simgear
{
{
setUseDisplayList(false);
}
+
+ ShaderGeometry(int v) :
+ varieties(v)
+ {
+ setUseDisplayList(false);
+ }
/** Copy constructor using CopyOp to manage deep vs shallow copy.*/
ShaderGeometry(const ShaderGeometry& ShaderGeometry,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY):
_geometry = geometry;
}
- void addTree(const osg::Vec3& position, float scale)
+ void addTree(TreeBin::Tree tree)
{
- _trees.push_back(osg::Vec4(position, scale));
+ _trees.push_back(tree);
}
osg::ref_ptr<osg::Drawable> _geometry;
- PositionSizeList _trees;
+ TreeBin::TreeList _trees;
+ int varieties;
protected:
namespace simgear
{
-osg::Geometry* createOrthQuads(float w, float h, const osg::Matrix& rotate)
+osg::Geometry* createOrthQuads(float w, float h, int varieties, const osg::Matrix& rotate)
{
//const osg::Vec3& pos = osg::Vec3(0.0f,0.0f,0.0f),
v[6].set( cw,0.0f,h);
v[7].set(-cw,0.0f,h);
+ // The texture coordinate range is not the
+ // entire coordinate space - as the texture
+ // has a number of different trees on it.
+ float tx = 1.0f/varieties;
+
t[0].set(0.0f,0.0f);
- t[1].set(1.0f,0.0f);
- t[2].set(1.0f,1.0f);
+ t[1].set( tx,0.0f);
+ t[2].set( tx,1.0f);
t[3].set(0.0f,1.0f);
t[4].set(0.0f,0.0f);
- t[5].set(1.0f,0.0f);
- t[6].set(1.0f,1.0f);
+ t[5].set( tx,0.0f);
+ t[6].set( tx,1.0f);
t[7].set(0.0f,1.0f);
// For now the normal is normal to the quad. If we want to get
}
static char vertexShaderSource[] =
+ "varying vec2 texcoord;\n"
"varying float fogFactor;\n"
+ "attribute float textureIndex;\n"
"\n"
"void main(void)\n"
"{\n"
+ " texcoord = gl_MultiTexCoord0.st + vec2(textureIndex, 0.0);\n"
" vec3 position = gl_Vertex.xyz * gl_Color.w + gl_Color.xyz;\n"
" gl_Position = gl_ModelViewProjectionMatrix * vec4(position,1.0);\n"
" vec3 ecPosition = vec3(gl_ModelViewMatrix * vec4(position, 1.0));\n"
" vec4 ambientColor = gl_FrontLightModelProduct.sceneColor + gl_LightSource[0].ambient * gl_FrontMaterial.ambient;\n"
" gl_FrontColor = ambientColor + gl_LightSource[0].diffuse * vec4(diffuse, 1.0);\n"
" gl_BackColor = ambientColor + gl_LightSource[0].diffuse * vec4(backDiffuse, 1.0)\n;"
- " gl_TexCoord[0] = gl_MultiTexCoord0;\n"
+// " gl_TexCoord[0] = gl_MultiTexCoord0;\n"
" float fogCoord = abs(ecPosition.z);\n"
" fogFactor = exp( -gl_Fog.density * gl_Fog.density * fogCoord * fogCoord);\n"
" fogFactor = clamp(fogFactor, 0.0, 1.0);\n"
static char fragmentShaderSource[] =
"uniform sampler2D baseTexture; \n"
-// "varying vec3 N;\n"\r
+ "varying vec2 texcoord;\n"
+// "varying vec3 N;\n"
// "varying vec3 v;\n"
"varying float fogFactor;\n"
"\n"
"void main(void) \n"
"{ \n"
- " vec4 base = texture2D( baseTexture, gl_TexCoord[0].st);\n"
+ " vec4 base = texture2D( baseTexture, texcoord);\n"
" vec4 finalColor = base * gl_Color;\n"
" gl_FragColor = mix(gl_Fog.color, finalColor, fogFactor );\n"
{
struct MakeTreesLeaf
{
- MakeTreesLeaf(float range, Geometry* geometry) :
- _range(range), _geometry(geometry)
+ MakeTreesLeaf(float range, Geometry* geometry, int varieties) :
+ _range(range), _geometry(geometry), _varieties(varieties)
{}
MakeTreesLeaf(const MakeTreesLeaf& rhs) :
- _range(rhs._range), _geometry(rhs._geometry) {}
+ _range(rhs._range), _geometry(rhs._geometry), _varieties(rhs._varieties) {}
LOD* operator() () const
{
LOD* result = new LOD;
Geode* geode = new Geode;
- ShaderGeometry* sg = new ShaderGeometry;
+ ShaderGeometry* sg = new ShaderGeometry(_varieties);
sg->setGeometry(_geometry);
geode->addDrawable(sg);
result->addChild(geode, 0, _range);
return result;
}
float _range;
+ int _varieties;
Geometry* _geometry;
};
Geode* geode = static_cast<Geode*>(lod->getChild(0));
ShaderGeometry* sg
= static_cast<ShaderGeometry*>(geode->getDrawable(0));
- sg->addTree(tree.position.osg(), tree.height);
+ sg->addTree(tree);
}
};
osg::Group* createForest(TreeBin& forest, const osg::Matrix& transform)
{
// Set up some shared structures.
- // FIXME: Currently we only take the texture, height and width of the first tree in the forest. In the future
- // we should be able to handle multiple textures etc.
- TreeBin::Tree firstTree = forest.getTree(0);
-
- osg::Geometry* shared_geometry = createOrthQuads(firstTree.width,
- firstTree.height,
+ osg::Geometry* shared_geometry = createOrthQuads(forest.width,
+ forest.height,
+ forest.texture_varieties,
transform);
+
ref_ptr<Group> group;
osg::StateSet* stateset = 0;
- StateSetMap::iterator iter = treeTextureMap.find(firstTree.texture);
+ StateSetMap::iterator iter = treeTextureMap.find(forest.texture);
if (iter == treeTextureMap.end()) {
osg::Texture2D *tex = new osg::Texture2D;
tex->setWrap( osg::Texture2D::WRAP_S, osg::Texture2D::CLAMP );
tex->setWrap( osg::Texture2D::WRAP_T, osg::Texture2D::CLAMP );
- tex->setImage(osgDB::readImageFile(firstTree.texture));
+ tex->setImage(osgDB::readImageFile(forest.texture));
static ref_ptr<AlphaFunc> alphaFunc;
static ref_ptr<Program> program;
baseTextureSampler = new osg::Uniform("baseTexture", 0);
Shader* vertex_shader = new Shader(Shader::VERTEX, vertexShaderSource);
program->addShader(vertex_shader);
+ program->addBindAttribLocation("textureIndex", 1);
+
Shader* fragment_shader = new Shader(Shader::FRAGMENT,
fragmentShaderSource);
program->addShader(fragment_shader);
stateset->addUniform(baseTextureSampler.get());
stateset->setMode(GL_VERTEX_PROGRAM_TWO_SIDE, StateAttribute::ON);
stateset->setAttribute(material.get());
- // XXX This should really come from a material definition
- // instead of being hard-coded.
- treeTextureMap.insert(StateSetMap::value_type(firstTree.texture,
+
+ treeTextureMap.insert(StateSetMap::value_type(forest.texture,
stateset));
} else {
stateset = iter->second.get();
ShaderGeometryQuadtree quadtree(GetTreeCoord(Matrix::inverse(transform)),
AddTreesLeafObject(),
SG_TREE_QUAD_TREE_DEPTH,
- MakeTreesLeaf(firstTree.range,
- shared_geometry));
+ MakeTreesLeaf(forest.range,
+ shared_geometry,
+ forest.texture_varieties));
quadtree.buildQuadTree(forest._trees.begin(), forest._trees.end());
group = quadtree.getRoot();
}
#define TREE_BIN_HXX
#include <vector>
+#include <string>
#include <osg/Geometry>
#include <osg/Group>
#include <osg/Matrix>
-#include <simgear/math/SGVec3.hxx>
+#include <simgear/math/SGMath.hxx>
namespace simgear
{
class TreeBin {
public:
- struct Tree {
- Tree(const SGVec3f& p, string t, float h, float w, double r) :
- position(p), texture(t), height(h), width(w), range(r)
- { }
- SGVec3f position;
- string texture;
- float height;
- float width;
- double range;
- };
+ struct Tree {
+ Tree(const SGVec3f& p, int t, float s) :
+ position(p), texture_index(t), scale(s)
+ { }
+ SGVec3f position;
+ int texture_index;
+ float scale;
+ };
+
typedef std::vector<Tree> TreeList;
+ int texture_varieties;
+ double range;
+ float height;
+ float width;
+ std::string texture;
+
void insert(const Tree& t)
{ _trees.push_back(t); }
- void insert(const SGVec3f& p, string t, float h, float w, double r)
- { insert(Tree(p, t, h, w, r)); }
+ void insert(const SGVec3f& p, int t, float s)
+ { insert(Tree(p, t, s)); }
unsigned getNumTrees() const
{ return _trees.size(); }
std::string materialName = obj.get_pt_materials()[grp];
SGMaterial* material = matlib->find(materialName);
SGVec4f color = getMaterialLightColor(material);
-
+
if (3 <= materialName.size() && materialName.substr(0, 3) != "RWY") {
// Just plain lights. Not something for the runway.
addPointGeometry(tileLights, obj.get_wgs84_nodes(), color,
void computeRandomForest(SGMaterialLib* matlib)
{
SGMaterialTriangleMap::iterator i;
-
+
// generate a repeatable random seed
mt seed;
mt_init(&seed, unsigned(586));
-
+
for (i = materialTriangleMap.begin(); i != materialTriangleMap.end(); ++i) {
SGMaterial *mat = matlib->find(i->first);
if (!mat)
float coverage = mat->get_tree_coverage();
if (coverage <= 0)
continue;
-
- vector<string> textures = mat->get_tree_textures();
-
+
+ // Attributes that don't vary by tree
+ randomForest.texture = mat->get_tree_texture();
+ randomForest.range = mat->get_tree_range();
+ randomForest.width = mat->get_tree_width();
+ randomForest.height = mat->get_tree_height();
+ randomForest.texture_varieties = mat->get_tree_varieties();
+
std::vector<SGVec3f> randomPoints;
i->second.addRandomSurfacePoints(coverage, 0, randomPoints);
std::vector<SGVec3f>::iterator j;
- for (j = randomPoints.begin(); j != randomPoints.end(); ++j) {
- int k = (int)(mt_rand(&seed) * textures.size());
- if (k == textures.size()) k--;
- randomForest.insert(*j, textures[k], mat->get_tree_height(), mat->get_tree_width(), mat->get_tree_range());
+ for (j = randomPoints.begin(); j != randomPoints.end(); ++j) {
+
+ // Apply a random scaling factor and texture index.
+ float scale = (mt_rand(&seed) + mt_rand(&seed)) / 2.0f + 0.5f;
+ int v = (int) (mt_rand(&seed) * mat->get_tree_varieties());
+ if (v == mat->get_tree_varieties()) v--;
+ randomForest.insert(*j, v, scale);
}
}
}
-
+
void computeRandomObjects(SGMaterialLib* matlib)
{
SGMaterialTriangleMap::iterator i;
-
+
// generate a repeatable random seed
mt seed;
mt_init(&seed, unsigned(123));
SGMaterial *mat = matlib->find(i->first);
if (!mat)
continue;
-
+
int group_count = mat->get_object_group_count();
-
+
if (group_count > 0)
- {
+ {
for (int j = 0; j < group_count; j++)
- {
+ {
SGMatModelGroup *object_group = mat->get_object_group(j);
int nObjects = object_group->get_object_count();
-
+
if (nObjects > 0)
{
// For each of the random models in the group, determine an appropriate
// number of random placements and insert them.
for (int k = 0; k < nObjects; k++) {
SGMatModel * object = object_group->get_object(k);
-
+
std::vector<SGVec3f> randomPoints;
i->second.addRandomPoints(object->get_coverage_m2(), randomPoints);
GetModelLODCoord> RandomObjectsQuadtree;
osg::Node*
-SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool calc_lights, bool use_random_objects)
+SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool calc_lights, bool use_random_objects, bool use_random_vegetation)
{
SGBinObject tile;
if (!tile.read_bin(path))
osg::ref_ptr<osg::Group> randomObjects;
osg::ref_ptr<osg::Group> randomForest;
osg::Group* terrainGroup = new osg::Group;
-
+
osg::Node* node = tileGeometryBin.getSurfaceGeometry(matlib);
if (node)
terrainGroup->addChild(node);
-
+
if (use_random_objects) {
-
+
// Simple matrix for used for flipping models that have been oriented
// with the center of the tile but upside down.
static const osg::Matrix flip(1, 0, 0, 0,
// heading rotation if appropriate.
osg::Matrix mPos = osg::Matrix::translate(obj.position.osg());
osg::MatrixTransform* 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;
position = new osg::MatrixTransform(mAtt * mPos);
}
- position->addChild(node);
+ position->addChild(node);
models.push_back(ModelLOD(position, obj.lod));
}
RandomObjectsQuadtree quadtree((GetModelLODCoord(world2Tile)),
randomObjects = quadtree.getRoot();
randomObjects->setName("random objects");
}
-
- // Now add some random forest.
- tileGeometryBin.computeRandomForest(matlib);
-
- if (tileGeometryBin.randomForest.getNumTrees() > 0) {
- randomForest = createForest(tileGeometryBin.randomForest, mAtt);
- randomForest->setName("random trees");
+
+ if (use_random_vegetation)
+ {
+ // Now add some random forest.
+ tileGeometryBin.computeRandomForest(matlib);
+
+ if (tileGeometryBin.randomForest.getNumTrees() > 0) {
+ randomForest = createForest(tileGeometryBin.randomForest, mAtt);
+ randomForest->setName("random trees");
+ }
}
}
}
osg::Node*
-SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool calc_lights, bool use_random_objects);
+SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool calc_lights, bool use_random_objects, bool use_random_vegetation);
#endif // _SG_OBJ_HXX