00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #ifdef HAVE_CONFIG_H
00023 # include <simgear_config.h>
00024 #endif
00025
00026 #include <algorithm>
00027 #include <vector>
00028 #include <string>
00029 #include <map>
00030
00031 #include <boost/tuple/tuple_comparison.hpp>
00032
00033 #include <osg/Geode>
00034 #include <osg/Geometry>
00035 #include <osg/Math>
00036 #include <osg/MatrixTransform>
00037 #include <osg/Matrix>
00038
00039 #include <osgDB/ReadFile>
00040 #include <osgDB/FileUtils>
00041
00042 #include <simgear/debug/logstream.hxx>
00043 #include <simgear/math/sg_random.h>
00044 #include <simgear/misc/sg_path.hxx>
00045 #include <simgear/scene/material/Effect.hxx>
00046 #include <simgear/scene/material/EffectGeode.hxx>
00047 #include <simgear/props/props.hxx>
00048 #include <simgear/scene/util/QuadTreeBuilder.hxx>
00049 #include <simgear/scene/util/RenderConstants.hxx>
00050 #include <simgear/scene/util/StateAttributeFactory.hxx>
00051 #include <simgear/structure/OSGUtils.hxx>
00052
00053 #include "ShaderGeometry.hxx"
00054 #include "TreeBin.hxx"
00055
00056 #define SG_TREE_QUAD_TREE_DEPTH 3
00057
00058 using namespace osg;
00059
00060 namespace simgear
00061 {
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072 struct TreesBoundingBoxCallback : public Drawable::ComputeBoundingBoxCallback
00073 {
00074 TreesBoundingBoxCallback() {}
00075 TreesBoundingBoxCallback(const TreesBoundingBoxCallback&, const CopyOp&) {}
00076 META_Object(simgear, TreesBoundingBoxCallback);
00077 virtual BoundingBox computeBound(const Drawable&) const;
00078 };
00079
00080 BoundingBox
00081 TreesBoundingBoxCallback::computeBound(const Drawable& drawable) const
00082 {
00083 BoundingBox bb;
00084 const Geometry* geom = static_cast<const Geometry*>(&drawable);
00085 const Vec3Array* v = static_cast<const Vec3Array*>(geom->getVertexArray());
00086 const Vec3Array* pos = static_cast<const Vec3Array*>(geom->getColorArray());
00087 const Vec3Array* params
00088 = static_cast<const Vec3Array*>(geom->getNormalArray());
00089 const FloatArray* rot
00090 = static_cast<const FloatArray*>(geom->getFogCoordArray());
00091 float w = (*params)[0].x();
00092 float h = (*params)[0].y();
00093 Geometry::PrimitiveSetList primSets = geom->getPrimitiveSetList();
00094 FloatArray::const_iterator rotitr = rot->begin();
00095 for (Geometry::PrimitiveSetList::const_iterator psitr = primSets.begin(),
00096 psend = primSets.end();
00097 psitr != psend;
00098 ++psitr, ++rotitr) {
00099 Matrixd trnsfrm = (Matrixd::scale(w, w, h)
00100 * Matrixd::rotate(*rotitr, Vec3(0.0f, 0.0f, 1.0f)));
00101 DrawArrays* da = static_cast<DrawArrays*>(psitr->get());
00102 GLint psFirst = da->getFirst();
00103 GLint psEndVert = psFirst + da->getCount();
00104 for (GLint i = psFirst;i < psEndVert; ++i) {
00105 Vec3 pt = (*v)[i];
00106 pt = pt * trnsfrm;
00107 pt += (*pos)[i];
00108 bb.expandBy(pt);
00109 }
00110 }
00111 return bb;
00112 }
00113
00114 Geometry* makeSharedTreeGeometry(int numQuads)
00115 {
00116
00117 mt seed;
00118 mt_init(&seed, unsigned(123));
00119
00120 osg::Vec3Array* v = new osg::Vec3Array;
00121 osg::Vec2Array* t = new osg::Vec2Array;
00122 v->reserve(numQuads * 4);
00123 t->reserve(numQuads * 4);
00124 for (int i = 0; i < numQuads; ++i) {
00125
00126 float h = (mt_rand(&seed) + mt_rand(&seed)) / 2.0f + 0.5f;
00127 float cw = h * .5;
00128 v->push_back(Vec3(0.0f, -cw, 0.0f));
00129 v->push_back(Vec3(0.0f, cw, 0.0f));
00130 v->push_back(Vec3(0.0f, cw, h));
00131 v->push_back(Vec3(0.0f,-cw, h));
00132
00133
00134
00135
00136 float variety = mt_rand(&seed);
00137 t->push_back(Vec2(variety, 0.0f));
00138 t->push_back(Vec2(variety + 1.0f, 0.0f));
00139 t->push_back(Vec2(variety + 1.0f, 1.0f));
00140 t->push_back(Vec2(variety, 1.0f));
00141 }
00142 Geometry* result = new Geometry;
00143 result->setVertexArray(v);
00144 result->setTexCoordArray(0, t);
00145 result->setComputeBoundingBoxCallback(new TreesBoundingBoxCallback);
00146 result->setUseDisplayList(false);
00147 return result;
00148 }
00149
00150 ref_ptr<Geometry> sharedTreeGeometry;
00151
00152 Geometry* createTreeGeometry(float width, float height, int varieties)
00153 {
00154 if (!sharedTreeGeometry)
00155 sharedTreeGeometry = makeSharedTreeGeometry(1600);
00156 Geometry* quadGeom = simgear::clone(sharedTreeGeometry.get(),
00157 CopyOp::SHALLOW_COPY);
00158 Vec3Array* params = new Vec3Array;
00159 params->push_back(Vec3(width, height, (float)varieties));
00160 quadGeom->setNormalArray(params);
00161 quadGeom->setNormalBinding(Geometry::BIND_OVERALL);
00162
00163 quadGeom->setColorArray(new Vec3Array);
00164 quadGeom->setColorBinding(Geometry::BIND_PER_VERTEX);
00165 FloatArray* rotation = new FloatArray(2);
00166 (*rotation)[0] = 0.0;
00167 (*rotation)[1] = PI_2;
00168 quadGeom->setFogCoordArray(rotation);
00169 quadGeom->setFogCoordBinding(Geometry::BIND_PER_PRIMITIVE_SET);
00170
00171
00172
00173 for (int i = 0; i < 2; ++i)
00174 quadGeom->addPrimitiveSet(new DrawArrays(PrimitiveSet::QUADS));
00175 return quadGeom;
00176 }
00177
00178 EffectGeode* createTreeGeode(float width, float height, int varieties)
00179 {
00180 EffectGeode* result = new EffectGeode;
00181 result->addDrawable(createTreeGeometry(width, height, varieties));
00182 return result;
00183 }
00184
00185 void addTreeToLeafGeode(Geode* geode, const SGVec3f& p)
00186 {
00187 Vec3 pos = toOsg(p);
00188 unsigned int numDrawables = geode->getNumDrawables();
00189 Geometry* geom
00190 = static_cast<Geometry*>(geode->getDrawable(numDrawables - 1));
00191 Vec3Array* posArray = static_cast<Vec3Array*>(geom->getColorArray());
00192 if (posArray->size()
00193 >= static_cast<Vec3Array*>(geom->getVertexArray())->size()) {
00194 Vec3Array* paramsArray
00195 = static_cast<Vec3Array*>(geom->getNormalArray());
00196 Vec3 params = (*paramsArray)[0];
00197 geom = createTreeGeometry(params.x(), params.y(), params.z());
00198 posArray = static_cast<Vec3Array*>(geom->getColorArray());
00199 geode->addDrawable(geom);
00200 }
00201 posArray->insert(posArray->end(), 4, pos);
00202 size_t numVerts = posArray->size();
00203 for (int i = 0; i < 2; ++i) {
00204 DrawArrays* primSet
00205 = static_cast<DrawArrays*>(geom->getPrimitiveSet(i));
00206 primSet->setCount(numVerts);
00207 }
00208 }
00209
00210 typedef std::map<std::string, osg::ref_ptr<Effect> > EffectMap;
00211
00212 static EffectMap treeEffectMap;
00213
00214
00215 namespace
00216 {
00217 struct MakeTreesLeaf
00218 {
00219 MakeTreesLeaf(float range, int varieties, float width, float height,
00220 Effect* effect) :
00221 _range(range), _varieties(varieties),
00222 _width(width), _height(height), _effect(effect) {}
00223
00224 MakeTreesLeaf(const MakeTreesLeaf& rhs) :
00225 _range(rhs._range),
00226 _varieties(rhs._varieties), _width(rhs._width), _height(rhs._height),
00227 _effect(rhs._effect)
00228 {}
00229
00230 LOD* operator() () const
00231 {
00232 LOD* result = new LOD;
00233 EffectGeode* geode = createTreeGeode(_width, _height, _varieties);
00234 geode->setEffect(_effect.get());
00235 result->addChild(geode, 0, _range);
00236 return result;
00237 }
00238 float _range;
00239 int _varieties;
00240 float _width;
00241 float _height;
00242 ref_ptr<Effect> _effect;
00243 };
00244
00245 struct AddTreesLeafObject
00246 {
00247 void operator() (LOD* lod, const TreeBin::Tree& tree) const
00248 {
00249 Geode* geode = static_cast<Geode*>(lod->getChild(0));
00250 addTreeToLeafGeode(geode, tree.position);
00251 }
00252 };
00253
00254 struct GetTreeCoord
00255 {
00256 Vec3 operator() (const TreeBin::Tree& tree) const
00257 {
00258 return toOsg(tree.position);
00259 }
00260 };
00261
00262 typedef QuadTreeBuilder<LOD*, TreeBin::Tree, MakeTreesLeaf, AddTreesLeafObject,
00263 GetTreeCoord> ShaderGeometryQuadtree;
00264 }
00265
00266 struct TreeTransformer
00267 {
00268 TreeTransformer(Matrix& mat_) : mat(mat_) {}
00269 TreeBin::Tree operator()(const TreeBin::Tree& tree) const
00270 {
00271 Vec3 pos = toOsg(tree.position);
00272 return TreeBin::Tree(toSG(pos * mat));
00273 }
00274 Matrix mat;
00275 };
00276
00277
00278
00279
00280
00281 osg::Group* createForest(TreeBin& forest, const osg::Matrix& transform)
00282 {
00283 Matrix transInv = Matrix::inverse(transform);
00284 static Matrix ident;
00285
00286 ref_ptr<Group> group;
00287
00288 Effect* effect = 0;
00289 EffectMap::iterator iter = treeEffectMap.find(forest.texture);
00290 if (iter == treeEffectMap.end()) {
00291 SGPropertyNode_ptr effectProp = new SGPropertyNode;
00292 makeChild(effectProp, "inherits-from")->setStringValue("Effects/tree");
00293 SGPropertyNode* params = makeChild(effectProp, "parameters");
00294
00295 params->getChild("texture", 0, true)->getChild("image", 0, true)
00296 ->setStringValue(forest.texture);
00297 effect = makeEffect(effectProp, true);
00298 treeEffectMap.insert(EffectMap::value_type(forest.texture, effect));
00299 } else {
00300 effect = iter->second.get();
00301 }
00302
00303 {
00304 ShaderGeometryQuadtree
00305 quadtree(GetTreeCoord(), AddTreesLeafObject(),
00306 SG_TREE_QUAD_TREE_DEPTH,
00307 MakeTreesLeaf(forest.range, forest.texture_varieties,
00308 forest.width, forest.height, effect));
00309
00310
00311
00312 std::vector<TreeBin::Tree> rotatedTrees;
00313 rotatedTrees.reserve(forest._trees.size());
00314 std::transform(forest._trees.begin(), forest._trees.end(),
00315 std::back_inserter(rotatedTrees),
00316 TreeTransformer(transInv));
00317 quadtree.buildQuadTree(rotatedTrees.begin(), rotatedTrees.end());
00318 group = quadtree.getRoot();
00319 }
00320 MatrixTransform* mt = new MatrixTransform(transform);
00321 for (size_t i = 0; i < group->getNumChildren(); ++i)
00322 mt->addChild(group->getChild(i));
00323 return mt;
00324 }
00325
00326 }