]> git.mxchange.org Git - simgear.git/blobdiff - simgear/scene/tgdb/TreeBin.cxx
Merge branch 'maint' into next
[simgear.git] / simgear / scene / tgdb / TreeBin.cxx
index b4219f33be85a70a8bd1d9a31be0d69887e5f1af..a530ba32d3216489a8d703f055fcdcb069c5a1e7 100644 (file)
  */
 
 #include <algorithm>
+#include <vector>
 #include <string>
 #include <map>
 
+#include <boost/tuple/tuple_comparison.hpp>
+
 #include <osg/AlphaFunc>
 #include <osg/Billboard>
 #include <osg/BlendFunc>
@@ -64,8 +67,17 @@ using namespace osg;
 namespace simgear
 {
 
+// memoize geometry
+typedef boost::tuple<float, float, int> ForestTuple;
+typedef std::map<ForestTuple, ref_ptr<Geometry> > OrthQuadMap;
+
 osg::Geometry* createOrthQuads(float w, float h, int varieties, const osg::Matrix& rotate)
 {
+    static OrthQuadMap orthQuadMap;
+    OrthQuadMap::iterator giter
+        = orthQuadMap.find(ForestTuple(w, h, varieties));
+    if (giter != orthQuadMap.end())
+        return giter->second.get();
 
     //const osg::Vec3& pos = osg::Vec3(0.0f,0.0f,0.0f),
     // set up the coords
@@ -123,6 +135,7 @@ osg::Geometry* createOrthQuads(float w, float h, int varieties, const osg::Matri
     // No color for now; that's used to pass the position.
     geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,8));
 
+    orthQuadMap.insert(std::make_pair(ForestTuple(w, h, varieties), geom));
     return geom;
 }
 
@@ -136,14 +149,12 @@ osg::Geometry* createOrthQuads(float w, float h, int varieties, const osg::Matri
     "  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"
-    "  vec3 N = normalize(gl_NormalMatrix * gl_Normal);\n"
-    "  vec3 diffuse = gl_FrontMaterial.diffuse.rgb * max(0.0, dot(N, gl_LightSource[0].position.xyz));\n"
-    "  vec3 backDiffuse = gl_FrontMaterial.diffuse.rgb * max(0.0, dot(-N, gl_LightSource[0].position.xyz));\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"
-    " float fogCoord = abs(ecPosition.z);\n"
+    "  float n = dot(normalize(gl_LightSource[0].position.xyz), normalize(-ecPosition));\n"
+    "  vec3 diffuse = gl_FrontMaterial.diffuse.rgb * max(0.1, n);\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 = gl_FrontColor;\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"
     "}\n";
@@ -201,26 +212,41 @@ struct AddTreesLeafObject
 
 struct GetTreeCoord
 {
-    GetTreeCoord(const Matrix& transform) : _transform(transform) {}
-    GetTreeCoord(const GetTreeCoord& rhs) : _transform(rhs._transform) {}
     Vec3 operator() (const TreeBin::Tree& tree) const
     {
-        return tree.position.osg() * _transform;
+        return tree.position.osg();
     }
-    Matrix _transform;
 };
 
 typedef QuadTreeBuilder<LOD*, TreeBin::Tree, MakeTreesLeaf, AddTreesLeafObject,
                         GetTreeCoord> ShaderGeometryQuadtree;
 }
 
+struct TreeTransformer
+{
+    TreeTransformer(Matrix& mat_) : mat(mat_) {}
+    TreeBin::Tree operator()(const TreeBin::Tree& tree) const
+    {
+        const Vec3& pos = tree.position.osg();
+        return TreeBin::Tree(SGVec3f(pos * mat), tree.texture_index,
+                             tree.scale);
+    }
+    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 tree geometry for all the forests of the same type.
+
 osg::Group* createForest(TreeBin& forest, const osg::Matrix& transform)
 {
+    Matrix transInv = Matrix::inverse(transform);
+    static Matrix ident;
     // Set up some shared structures. 
     osg::Geometry* shared_geometry = createOrthQuads(forest.width, 
                                                      forest.height, 
                                                      forest.texture_varieties,
-                                                     transform);
+                                                     ident);
 
     ref_ptr<Group> group;
 
@@ -256,9 +282,9 @@ osg::Group* createForest(TreeBin& forest, const osg::Matrix& transform)
             // DonĀ“t track vertex color
             material->setColorMode(Material::OFF);
             material->setAmbient(Material::FRONT_AND_BACK,
-                                 Vec4(.8f, .8f, .8f, 1.0f));
+                                 Vec4(1.0f, 1.0f, 1.0f, 1.0f));
             material->setDiffuse(Material::FRONT_AND_BACK,
-                                 Vec4(.2f, .2f, .2f, 1.0f));
+                                 Vec4(1.0f, 1.0f, 1.0f, 1.0f));
         }
         stateset->setAttributeAndModes(alphaFunc.get());
         stateset->setAttribute(program.get());
@@ -273,17 +299,28 @@ osg::Group* createForest(TreeBin& forest, const osg::Matrix& transform)
     }
     // Now, create a quadtree for the forest.
     {
-        ShaderGeometryQuadtree quadtree(GetTreeCoord(Matrix::inverse(transform)),
+        ShaderGeometryQuadtree quadtree(GetTreeCoord(),
                                         AddTreesLeafObject(),
                                         SG_TREE_QUAD_TREE_DEPTH,
                                         MakeTreesLeaf(forest.range,
                                                       shared_geometry,
                                                       forest.texture_varieties));
-        quadtree.buildQuadTree(forest._trees.begin(), forest._trees.end());
+        // Transform tree positions from the "geocentric" positions we
+        // get from the scenery polys into the local Z-up coordinate
+        // system.
+        std::vector<TreeBin::Tree> rotatedTrees;
+        rotatedTrees.reserve(forest._trees.size());
+        std::transform(forest._trees.begin(), forest._trees.end(),
+                       std::back_inserter(rotatedTrees),
+                       TreeTransformer(transInv));
+        quadtree.buildQuadTree(rotatedTrees.begin(), rotatedTrees.end());
         group = quadtree.getRoot();
     }
-    group->setStateSet(stateset);
-    return group.release();    
+    MatrixTransform* mt = new MatrixTransform(transform);
+    for (int i = 0; i < group->getNumChildren(); ++i)
+        mt->addChild(group->getChild(i));
+    mt->setStateSet(stateset);
+    return mt;
 }
 
 }