-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi,

This patch combines all the triangles, triangle strips and triangle fans
with the same material in a tile into one DrawElements primitive set.
This also reduces by a factor of 100 the number of Geodes that needs to
be processed by the cull phase.

On my machine I see a 1.5 ms decrease in cull and draw times and a .5ms
increase in "event" time, probably due to increased time in intersection
testing. I'll take a 1ms decrease in total frame time (9%) :)

Tim
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.7 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org

iD8DBQFGWG02eDhWHdXrDRURAlP4AKCEermb3De1Nt04N0uBTpzPKMRAkACgzu2/
wyxVgdDpZgrSmWO9OePmaAU=
=9NxH
-----END PGP SIGNATURE-----
Index: simgear/scene/tgdb/leaf.cxx
===================================================================
RCS file: /var/cvs/SimGear-0.3/source/simgear/scene/tgdb/leaf.cxx,v
retrieving revision 1.10
diff -d -u -r1.10 leaf.cxx
--- simgear/scene/tgdb/leaf.cxx 8 May 2007 06:11:15 -0000       1.10
+++ simgear/scene/tgdb/leaf.cxx 26 May 2007 16:55:18 -0000
@@ -97,7 +97,7 @@
   }
 };
 
-static void SGGenRandomSurfacePoints( osg::Geometry *leaf, double factor, 
+void SGGenRandomSurfacePoints( osg::Geometry *leaf, double factor, 
                                       osg::Vec3Array *lights )
 {
   osg::TriangleFunctor<SGRandomSurfacePointsFill> triangleFunctor;
@@ -227,3 +227,160 @@
     return geometry;
 }
 
+// Specialization of triangle index production and DrawElements type.
+namespace {
+// Trick to turn integers (e.g., GL_TRIANGLES) into types
+template <int v>
+struct Int2Type
+{
+    enum { value = v };
+};
+
+// Triangles use the vertices in order.
+template <class DEType>
+void addIndices(int baseIndex, int numIndices, DEType* de,
+               Int2Type<GL_TRIANGLES>)
+{
+    typedef typename DEType::value_type ValueType;
+    for (int i = 0; i < numIndices; ++i) {
+       de->push_back((ValueType)(baseIndex + i));
+    }
+}
+
+// Duplicate the vertex "swapping" of triangle strips using the
+// indicies of the vertex data.
+template <class DEType>
+void addIndices(int baseIndex, int numIndices, DEType* de,
+               Int2Type<GL_TRIANGLE_STRIP>)
+{
+    typedef typename DEType::value_type ValueType;
+    int index = baseIndex;
+
+    for (int i = 2; i < numIndices; ++i, ++index) {
+       de->push_back((ValueType)(index));
+       if (i % 2) {
+           de->push_back((ValueType)(index + 2));
+           de->push_back((ValueType)(index + 1));
+       } else {
+           de->push_back((ValueType)(index + 1));
+           de->push_back((ValueType)(index + 2));
+       }
+    }
+}
+
+// And again for triangle fans.
+template <class DEType>
+void addIndices(int baseIndex, int numIndices, DEType* de,
+               Int2Type<GL_TRIANGLE_FAN>)
+{
+    typedef typename DEType::value_type ValueType;
+    int index = baseIndex + 1;
+    for (int i = 2; i < numIndices; ++i, ++index) {
+       de->push_back((ValueType)(baseIndex));
+       de->push_back((ValueType)(index));
+       de->push_back((ValueType)(index + 1));
+    }
+}
+
+template <class GeomType>
+void addIndicesToGeometry(int baseIndex, int numIndices,
+                         osg::Geometry *geometry, GeomType)
+{
+    osg::PrimitiveSet* pset = geometry->getPrimitiveSet(0);
+    osg::DrawElementsUByte* db = dynamic_cast<osg::DrawElementsUByte*>(pset);
+    osg::DrawElementsUShort* ds = dynamic_cast<osg::DrawElementsUShort*>(pset);
+    osg::DrawElementsUInt* di = dynamic_cast<osg::DrawElementsUInt*>(pset);
+    if (db)
+       addIndices(baseIndex, numIndices, db, GeomType());
+    else if (ds)
+       addIndices(baseIndex, numIndices, ds, GeomType());
+    else
+       addIndices(baseIndex, numIndices, di, GeomType());
+}
+    
+} // namespace
+
+// Add leaf geometry to an existing osg::Geometry which has a
+// DrawElements primitive set. The caller must guarantee that the
+// DrawElements type (UByte, UShort or Uint) is big enough to contain
+// the indices for the new triangles.
+void SGAddLeafToDrawable(osg::Geometry* geometry, const GLenum ty,
+                        SGMaterial *mat,
+                        const point_list& nodes, const point_list& normals,
+                        const point_list& texcoords,
+                        const int_list& node_index,
+                        const int_list& normal_index,
+                        const int_list& tex_index)
+{
+    double tex_width = 1000.0, tex_height = 1000.0;
+
+    if (mat) {
+        // set the texture width and height values for this
+        // material
+        tex_width = mat->get_xsize();
+        tex_height = mat->get_ysize();
+    }
+    osg::Vec3Array* vl
+       = static_cast<osg::Vec3Array*>(geometry->getVertexArray());
+    osg::Vec3Array* nl
+       = static_cast<osg::Vec3Array*>(geometry->getNormalArray());
+    osg::Vec2Array* tl
+       = static_cast<osg::Vec2Array*>(geometry->getTexCoordArray(0));
+    int baseIndex = vl->size();
+    int i;
+
+    // vertices
+    int size = node_index.size();
+    for ( i = 0; i < size; ++i ) {
+        Point3D node = nodes[ node_index[i] ];
+        vl->push_back(osg::Vec3(node[0], node[1], node[2]));
+    }
+    // normals
+    if ( normal_index.size() ) {
+        // object file specifies normal indices (i.e. normal indices
+        // aren't 'implied'
+        for ( i = 0; i < size; ++i ) {
+            Point3D normal = normals[ normal_index[i] ];
+            nl->push_back(osg::Vec3(normal[0], normal[1], normal[2]));
+        }
+    } else {
+        // use implied normal indices.  normal index = vertex index.
+        for ( i = 0; i < size; ++i ) {
+            Point3D normal = normals[ node_index[i] ];
+            nl->push_back(osg::Vec3(normal[0], normal[1], normal[2]));
+        }
+    }
+    // texture coordinates
+    int tsize = tex_index.size();
+    Point3D texcoord;
+    if ( tsize == 1 ) {
+       SG_LOG( SG_TERRAIN, SG_ALERT, "Only 1 tex coord in leaf" );
+        Point3D texcoord = texcoords[ tex_index[0] ];
+        osg::Vec2 tmp2(texcoord[0], texcoord[1]);
+        if ( tex_width > 0 )
+            tmp2[0] *= (1000.0 / tex_width);
+        if ( tex_height > 0 )
+            tmp2[1] *= (1000.0 / tex_height);
+       for (i = 0; i < size; ++i)
+           tl->push_back(tmp2);
+    } else if ( size > 1 ) {
+        for ( i = 0; i < size; ++i ) {
+            Point3D texcoord = texcoords[ tex_index[i] ];
+            osg::Vec2 tmp2(texcoord[0], texcoord[1]);
+            if ( tex_width > 0 )
+                tmp2[0] *= (1000.0 / tex_width);
+            if ( tex_height > 0 )
+                tmp2[1] *= (1000.0 / tex_height);
+            tl ->push_back(tmp2);
+        }
+    }
+    if (ty == GL_TRIANGLES)
+       addIndicesToGeometry(baseIndex, size, geometry,
+                            Int2Type<GL_TRIANGLES>());
+    else if (ty == GL_TRIANGLE_STRIP)
+       addIndicesToGeometry(baseIndex, size, geometry,
+                            Int2Type<GL_TRIANGLE_STRIP>());
+    else
+       addIndicesToGeometry(baseIndex, size, geometry,
+                            Int2Type<GL_TRIANGLE_FAN>());
+}
Index: simgear/scene/tgdb/leaf.hxx
===================================================================
RCS file: /var/cvs/SimGear-0.3/source/simgear/scene/tgdb/leaf.hxx,v
retrieving revision 1.7
diff -d -u -r1.7 leaf.hxx
--- simgear/scene/tgdb/leaf.hxx 8 May 2007 06:11:15 -0000       1.7
+++ simgear/scene/tgdb/leaf.hxx 26 May 2007 16:55:18 -0000
@@ -35,6 +35,8 @@
 #include STL_STRING
 
 #include <osg/Array>
+#include <osg/Drawable>
+#include <osg/Geometry>
 #include <osg/Node>
 
 #include <simgear/math/sg_types.hxx>
@@ -44,7 +46,8 @@
 
 class SGMaterialLib;            // forward declaration.
 
-
+void SGGenRandomSurfacePoints( osg::Geometry *leaf, double factor, 
+                              osg::Vec3Array *lights );
 // Create a ssg leaf
 osg::Drawable* SGMakeLeaf( const string& path,
                      const GLenum ty, SGMaterial *mat,
@@ -55,4 +58,10 @@
                      const int_list& tex_index,
                      const bool calc_lights, osg::Vec3Array *lights );
 
+void SGAddLeafToDrawable(osg::Geometry* geom, const GLenum ty, SGMaterial *mat,
+                        const point_list& nodes, const point_list& normals,
+                        const point_list& texcoords,
+                        const int_list& node_index,
+                        const int_list& normal_index,
+                        const int_list& tex_index);
 #endif // _SG_LEAF_HXX
Index: simgear/scene/tgdb/obj.cxx
===================================================================
RCS file: /var/cvs/SimGear-0.3/source/simgear/scene/tgdb/obj.cxx,v
retrieving revision 1.21
diff -d -u -r1.21 obj.cxx
--- simgear/scene/tgdb/obj.cxx  8 May 2007 06:11:15 -0000       1.21
+++ simgear/scene/tgdb/obj.cxx  26 May 2007 16:55:18 -0000
@@ -420,8 +420,7 @@
     group_list::size_type i;
 
     osg::Geode* geode = new osg::Geode;
-    local_terrain->addChild( geode );
-
+    
     // generate points
     string_list const& pt_materials = obj.get_pt_materials();
     group_list const& pts_v = obj.get_pts_v();
@@ -507,52 +506,102 @@
     while ( lmi != leafMap.end() ) {
         SGMaterial *mat = findMaterial( lmi->first, path, matlib );
         list<Leaf> &leaf_list = lmi->second;
+       int numTris = 0;
+       int numVerts = 0;
         list<Leaf>::iterator li = leaf_list.begin();
-        while ( li != leaf_list.end() ) {
+       // Count the total number of vertices so that the proper width
+       // osg::DrawElements class can be created to index them.
+       while (li != leaf_list.end()) {
+           Leaf &leaf = *li;
+           int vertSize = 0;
+           if (leaf.type == GL_TRIANGLES) {
+               vertSize = tris_v[leaf.index].size();
+               numTris += vertSize / 3;
+           } else if (leaf.type == GL_TRIANGLE_STRIP) {
+               vertSize = strips_v[leaf.index].size();
+               numTris += vertSize - 2;
+           } else {
+               vertSize = fans_v[leaf.index].size();
+               numTris += vertSize - 2;
+           }
+           numVerts += vertSize;
+           ++li;
+       }
+       // Allocate the drawable and its arrays.
+       osg::Geometry* geometry = new osg::Geometry;
+       osg::Vec3Array* vl = new osg::Vec3Array;
+       vl->reserve(numVerts);
+       geometry->setVertexArray(vl);
+       osg::Vec3Array* nl = new osg::Vec3Array;
+       nl->reserve(numVerts);
+       geometry->setNormalArray(nl);
+       geometry->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
+       osg::Vec2Array* tl = new osg::Vec2Array;
+       tl->reserve(numVerts);
+       geometry->setTexCoordArray(0, tl);
+       osg::Vec4Array* cl = new osg::Vec4Array;
+       cl->push_back(osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
+       geometry->setColorArray(cl);
+       geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
+       if (numVerts < 256) {
+           osg::DrawElementsUByte* db
+               = new osg::DrawElementsUByte(osg::PrimitiveSet::TRIANGLES);
+           db->reserve(numTris * 3);
+           geometry->addPrimitiveSet(db);
+       } else if (numVerts < 65536) {
+           osg::DrawElementsUShort* ds
+               = new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES);
+           ds->reserve(numTris * 3);
+           geometry->addPrimitiveSet(ds);
+       } else {
+           osg::DrawElementsUInt* di
+               = new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLES);
+           di->reserve(numTris * 3);
+           geometry->addPrimitiveSet(di);
+       }
+       if (mat)
+           geometry->setStateSet(mat->get_state());
+       li = leaf_list.begin();
+       while ( li != leaf_list.end() ) {
             Leaf &leaf = *li;
             int ind = leaf.index;
             if ( leaf.type == GL_TRIANGLES ) {
-                osg::Drawable *leaf = SGMakeLeaf( path, GL_TRIANGLES, mat,
-                                            nodes, normals, texcoords,
-                                            tris_v[ind], tris_n[ind], 
tris_tc[ind],
-                                            is_base, ground_lights );
-                if ( random_object_branch ) {
-                    if ( mat ) {
-                        gen_random_surface_objects( leaf, random_object_branch,
-                                                    &center, mat );
-                    }
-                }
-                geode->addDrawable( leaf );
+               SGAddLeafToDrawable(geometry, GL_TRIANGLES, mat,
+                                    nodes, normals, texcoords,
+                                    tris_v[ind], tris_n[ind], tris_tc[ind]);
             } else if ( leaf.type == GL_TRIANGLE_STRIP ) {
-                osg::Drawable *leaf = SGMakeLeaf( path, GL_TRIANGLE_STRIP, mat,
-                                            nodes, normals, texcoords,
-                                            strips_v[ind], strips_n[ind], 
strips_tc[ind],
-                                            is_base, ground_lights );
-                if ( random_object_branch ) {
-                    if ( mat ) {
-                        gen_random_surface_objects( leaf, random_object_branch,
-                                                    &center, mat );
-                    }
-                }
-                geode->addDrawable( leaf );
+               SGAddLeafToDrawable(geometry, GL_TRIANGLE_STRIP, mat,
+                                    nodes, normals, texcoords,
+                                    strips_v[ind], strips_n[ind],
+                                    strips_tc[ind]);
             } else {
-                osg::Drawable *leaf = SGMakeLeaf( path, GL_TRIANGLE_FAN, mat,
-                                            nodes, normals, texcoords,
-                                            fans_v[ind], fans_n[ind], 
fans_tc[ind],
-                                            is_base, ground_lights );
-                if ( random_object_branch ) {
-                    if ( mat ) {
-                        gen_random_surface_objects( leaf, random_object_branch,
-                                                    &center, mat );
-                    }
-                }
-                geode->addDrawable( leaf );
+               SGAddLeafToDrawable(geometry, GL_TRIANGLE_FAN, mat,
+                                   nodes, normals, texcoords,
+                                   fans_v[ind], fans_n[ind], fans_tc[ind]);
             }
             ++li;
         }
+       if ( random_object_branch ) {
+           if ( mat ) {
+               gen_random_surface_objects(geometry, random_object_branch,
+                                           &center, mat );
+           }
+       }
+       geode->addDrawable(geometry);
+       if (is_base && mat) {
+           float coverage = mat->get_light_coverage();
+           if ( coverage > 0.0 ) {
+               if ( coverage < 10000.0 ) {
+                   SG_LOG(SG_INPUT, SG_ALERT, "Light coverage is "
+                          << coverage << ", pushing up to 10000");
+                   coverage = 10000;
+               }
+               SGGenRandomSurfacePoints(geometry, coverage, ground_lights);
+           }
+       }
         ++lmi;
     }
-
+    local_terrain->addChild( geode );
     return true;
 }
 
-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
Flightgear-devel mailing list
Flightgear-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/flightgear-devel

Reply via email to