Browse Source

pfm-vis-max-vertices

David Rose 14 years ago
parent
commit
d5f8a968a2

+ 12 - 0
panda/src/grutil/config_grutil.cxx

@@ -73,6 +73,18 @@ ConfigVariableBool pfm_reverse_dimensions
           "backwards, in the form height width instead of width height, "
           "on input.  Does not affect output, which is always written width height."));
 
+ConfigVariableInt pfm_vis_max_vertices
+("pfm-vis-max-vertices", 65535,
+ PRC_DESC("Specifies the maximum number of vertex entries that may appear in "
+          "a single generated mesh.  If the mesh would require more than that, "
+          "the mesh is subdivided into smaller pieces."));
+
+ConfigVariableInt pfm_vis_max_indices
+("pfm-vis-max-indices", 1048576,
+ PRC_DESC("Specifies the maximum number of vertex references that may appear in "
+          "a single generated mesh.  If the mesh would require more than that, "
+          "the mesh is subdivided into smaller pieces."));
+
 ////////////////////////////////////////////////////////////////////
 //     Function: init_libgrutil
 //  Description: Initializes the library.  This must be called at

+ 2 - 0
panda/src/grutil/config_grutil.h

@@ -37,6 +37,8 @@ extern ConfigVariableDouble scene_graph_analyzer_meter_side_margins;
 
 extern ConfigVariableBool pfm_force_littleendian;
 extern ConfigVariableBool pfm_reverse_dimensions;
+extern ConfigVariableInt pfm_vis_max_vertices;
+extern ConfigVariableInt pfm_vis_max_indices;
 
 extern EXPCL_PANDA_GRUTIL void init_libgrutil();
 

+ 156 - 112
panda/src/grutil/pfmFile.cxx

@@ -669,12 +669,10 @@ generate_vis_mesh(bool double_sided) const {
   
   PT(GeomNode) gnode = new GeomNode("");
 
-  PT(Geom) geom1 = make_vis_mesh_geom(false);
-  gnode->add_geom(geom1);
+  make_vis_mesh_geom(gnode, false);
 
   if (double_sided) {
-    PT(Geom) geom2 = make_vis_mesh_geom(true);
-    gnode->add_geom(geom2);
+    make_vis_mesh_geom(gnode, true);
   }
 
   return NodePath(gnode);
@@ -686,12 +684,48 @@ generate_vis_mesh(bool double_sided) const {
 //  Description: Returns a triangle mesh for the pfm.  If inverted is
 //               true, the mesh is facing the opposite direction.
 ////////////////////////////////////////////////////////////////////
-PT(Geom) PfmFile::
-make_vis_mesh_geom(bool inverted) const {
+void PfmFile::
+make_vis_mesh_geom(GeomNode *gnode, bool inverted) const {
+  int num_x_cells = 1;
+  int num_y_cells = 1;
+
+  int x_size = _x_size;
+  int y_size = _y_size;
+
+  // This is the number of independent vertices we will require.
+  int num_vertices = x_size * y_size;
+
+  // This is the max number of vertex indices we might add to the
+  // GeomTriangles.  (We might actually add fewer than this due to
+  // omitting the occasional missing data point.)
+  int max_indices = (x_size - 1) * (y_size - 1) * 6;
+
+  while (num_vertices > pfm_vis_max_vertices || max_indices > pfm_vis_max_indices) {
+    // Too many vertices in one mesh.  Subdivide the mesh into smaller
+    // pieces.
+    if (num_x_cells > num_y_cells) {
+      ++num_y_cells;
+    } else {
+      ++num_x_cells;
+    }
+
+    x_size = (_x_size + num_x_cells - 1) / num_x_cells + 1;
+    y_size = (_y_size + num_y_cells - 1) / num_y_cells + 1;
+
+    num_vertices = x_size * y_size;
+    max_indices = (x_size - 1) * (y_size - 1) * 6;
+  }
+
+  // OK, now we know how many cells we need.
+  if (grutil_cat.is_debug()) {
+    grutil_cat.debug()
+      << "Generating mesh with " << num_x_cells << " x " << num_y_cells
+      << " pieces.\n";
+  }
 
   CPT(GeomVertexFormat) format;
   if (_vis_inverse) {
-    // We need a 3-d texture coordinate if we're inverted the vis.
+    // We need a 3-d texture coordinate if we're inverting the vis.
     // But we don't need normals in that case.
     GeomVertexArrayFormat *v3t3 = new GeomVertexArrayFormat
       (InternalName::get_vertex(), 3, 
@@ -705,122 +739,132 @@ make_vis_mesh_geom(bool inverted) const {
     format = GeomVertexFormat::get_v3n3t2();
   }
 
-  PT(GeomVertexData) vdata = new GeomVertexData
-    ("mesh", format, Geom::UH_static);
-  int num_vertices = _x_size * _y_size;
-  vdata->set_num_rows(num_vertices);
-  GeomVertexWriter vertex(vdata, InternalName::get_vertex());
-  GeomVertexWriter normal(vdata, InternalName::get_normal());
-  GeomVertexWriter texcoord(vdata, InternalName::get_texcoord());
+  for (int yci = 0; yci < num_y_cells; ++yci) {
+    int y_begin = (yci * _y_size) / num_y_cells;
+    int y_end = ((yci + 1) * _y_size) / num_y_cells;
 
-  for (int yi = 0; yi < _y_size; ++yi) {
-    for (int xi = 0; xi < _x_size; ++xi) {
-      const LPoint3f &point = get_point(xi, yi);
-      LPoint2f uv(float(xi) / float(_x_size - 1),
-                  float(yi) / float(_y_size - 1));
+    // Include the first vertex from the next strip in this strip's
+    // vertices, so we are connected.
+    y_end = min(y_end + 1, _y_size);
 
-      if (_vis_inverse) {
-        vertex.add_data2f(uv);
-        texcoord.add_data3f(point);
-      } else {
-        vertex.add_data3f(point);
-        texcoord.add_data2f(uv);
+    y_size = y_end - y_begin;
+    if (y_size == 0) {
+      continue;
+    }
 
-        // Calculate the normal based on two neighboring vertices.
-        LPoint3f v[3];
-        v[0] = get_point(xi, yi);
-        if (xi + 1 < _x_size) {
-          v[1] = get_point(xi + 1, yi);
-        } else {
-          v[1] = v[0];
-          v[0] = get_point(xi - 1, yi);
-        }
-        
-        if (yi + 1 < _y_size) {
-          v[2] = get_point(xi, yi + 1);
-        } else {
-          v[2] = v[0];
-          v[0] = get_point(xi, yi - 1);
-        }
+    for (int xci = 0; xci < num_x_cells; ++xci) {
+      int x_begin = (xci * _x_size) / num_x_cells;
+      int x_end = ((xci + 1) * _x_size) / num_x_cells;
+      x_end = min(x_end + 1, _x_size);
+      x_size = x_end - x_begin;
+      if (x_size == 0) {
+        continue;
+      }
+
+      num_vertices = x_size * y_size;
+      max_indices = (x_size - 1) * (y_size - 1) * 6;
+
+      ostringstream mesh_name;
+      mesh_name << "mesh_" << xci << "_" << yci;
+      PT(GeomVertexData) vdata = new GeomVertexData
+        (mesh_name.str(), format, Geom::UH_static);
+
+      vdata->set_num_rows(num_vertices);
+      GeomVertexWriter vertex(vdata, InternalName::get_vertex());
+      GeomVertexWriter normal(vdata, InternalName::get_normal());
+      GeomVertexWriter texcoord(vdata, InternalName::get_texcoord());
+
+      for (int yi = y_begin; yi < y_end; ++yi) {
+        for (int xi = x_begin; xi < x_end; ++xi) {
+          const LPoint3f &point = get_point(xi, yi);
+          LPoint2f uv(float(xi) / float(_x_size - 1),
+                      float(yi) / float(_y_size - 1));
+
+          if (_vis_inverse) {
+            vertex.add_data2f(uv);
+            texcoord.add_data3f(point);
+          } else {
+            vertex.add_data3f(point);
+            texcoord.add_data2f(uv);
+            
+            // Calculate the normal based on two neighboring vertices.
+            LPoint3f v[3];
+            v[0] = get_point(xi, yi);
+            if (xi + 1 < _x_size) {
+              v[1] = get_point(xi + 1, yi);
+            } else {
+              v[1] = v[0];
+              v[0] = get_point(xi - 1, yi);
+            }
+            
+            if (yi + 1 < _y_size) {
+              v[2] = get_point(xi, yi + 1);
+            } else {
+              v[2] = v[0];
+              v[0] = get_point(xi, yi - 1);
+            }
         
-        LVector3f n = LVector3f::zero();
-        for (int i = 0; i < 3; ++i) {
-          const LPoint3f &v0 = v[i];
-          const LPoint3f &v1 = v[(i + 1) % 3];
-          n[0] += v0[1] * v1[2] - v0[2] * v1[1];
-          n[1] += v0[2] * v1[0] - v0[0] * v1[2];
-          n[2] += v0[0] * v1[1] - v0[1] * v1[0];
+            LVector3f n = LVector3f::zero();
+            for (int i = 0; i < 3; ++i) {
+              const LPoint3f &v0 = v[i];
+              const LPoint3f &v1 = v[(i + 1) % 3];
+              n[0] += v0[1] * v1[2] - v0[2] * v1[1];
+              n[1] += v0[2] * v1[0] - v0[0] * v1[2];
+              n[2] += v0[0] * v1[1] - v0[1] * v1[0];
+            }
+            n.normalize();
+            if (inverted) {
+              n = -n;
+            }
+            normal.add_data3f(n);
+          }
         }
-        n.normalize();
-        if (inverted) {
-          n = -n;
-        }
-        normal.add_data3f(n);
       }
-    }
-  }
   
-  PT(Geom) geom = new Geom(vdata);
-  PT(GeomTriangles) tris = new GeomTriangles(Geom::UH_static);
-
-  if (num_vertices > 0xffff) {
-    // We need 32-bit indices.
-    tris->set_index_type(Geom::NT_uint32);
-  }
-
-  // We get direct access to the vertices data so we can speed things
-  // up by pre-specifying the number of vertices.  Need a better
-  // interface to do this same thing using the high-level access
-  // methods.
-  int num_indices = (_x_size - 1) * (_y_size - 1) * 6;
-
-  PT(GeomVertexArrayData) indices = tris->modify_vertices();
-  indices->set_num_rows(num_indices);
-  GeomVertexWriter index(indices, 0);
-
-  int actual_num_indices = 0;
-  for (int yi = 0; yi < _y_size - 1; ++yi) {
-    for (int xi = 0; xi < _x_size - 1; ++xi) {
-
-      if (_zero_special) {
-        if (get_point(xi, yi) == LPoint3f::zero() ||
-            get_point(xi, yi + 1) == LPoint3f::zero() ||
-            get_point(xi + 1, yi + 1) == LPoint3f::zero() ||
-            get_point(xi + 1, yi) == LPoint3f::zero()) {
-          continue;
+      PT(Geom) geom = new Geom(vdata);
+      PT(GeomTriangles) tris = new GeomTriangles(Geom::UH_static);
+
+      tris->reserve_num_vertices(max_indices);
+
+      for (int yi = y_begin; yi < y_end - 1; ++yi) {
+        for (int xi = x_begin; xi < x_end - 1; ++xi) {
+
+          if (_zero_special) {
+            if (get_point(xi, yi) == LPoint3f::zero() ||
+                get_point(xi, yi + 1) == LPoint3f::zero() ||
+                get_point(xi + 1, yi + 1) == LPoint3f::zero() ||
+                get_point(xi + 1, yi) == LPoint3f::zero()) {
+              continue;
+            }
+          }
+
+          int xi0 = xi - x_begin;
+          int yi0 = yi - y_begin;
+
+          int vi0 = ((xi0) + (yi0) * x_size);
+          int vi1 = ((xi0) + (yi0 + 1) * x_size);
+          int vi2 = ((xi0 + 1) + (yi0 + 1) * x_size);
+          int vi3 = ((xi0 + 1) + (yi0) * x_size);
+          
+          if (inverted) {
+            tris->add_vertices(vi2, vi0, vi1);
+            tris->close_primitive();
+            
+            tris->add_vertices(vi3, vi0, vi2);
+            tris->close_primitive();
+          } else {
+            tris->add_vertices(vi2, vi1, vi0);
+            tris->close_primitive();
+            
+            tris->add_vertices(vi3, vi2, vi0);
+            tris->close_primitive();
+          }
         }
       }
-
-      int vi0 = ((xi) + (yi) * _x_size);
-      int vi1 = ((xi) + (yi + 1) * _x_size);
-      int vi2 = ((xi + 1) + (yi + 1) * _x_size);
-      int vi3 = ((xi + 1) + (yi) * _x_size);
-
-      if (inverted) {
-        index.add_data1i(vi2);
-        index.add_data1i(vi0);
-        index.add_data1i(vi1);
-        
-        index.add_data1i(vi3);
-        index.add_data1i(vi0);
-        index.add_data1i(vi2);
-      } else {
-        index.add_data1i(vi2);
-        index.add_data1i(vi1);
-        index.add_data1i(vi0);
-        
-        index.add_data1i(vi3);
-        index.add_data1i(vi2);
-        index.add_data1i(vi0);
-      }
-
-      actual_num_indices += 6;
+      geom->add_primitive(tris);
+      gnode->add_geom(geom);
     }
   }
-  indices->set_num_rows(actual_num_indices);
-  geom->add_primitive(tris);
-
-  return geom;
 }
 
 

+ 3 - 1
panda/src/grutil/pfmFile.h

@@ -20,6 +20,8 @@
 #include "nodePath.h"
 #include "boundingHexahedron.h"
 
+class GeomNode;
+
 ////////////////////////////////////////////////////////////////////
 //       Class : PfmFile
 // Description : Defines a pfm file, a 2-d table of floating-point
@@ -70,7 +72,7 @@ PUBLISHED:
   NodePath generate_vis_mesh(bool double_sided) const;
 
 private:
-  PT(Geom) make_vis_mesh_geom(bool inverted) const;
+  void make_vis_mesh_geom(GeomNode *gnode, bool inverted) const;
 
   void compute_sample_point(LPoint3f &result,
                             double x, double y, double sample_radius) const;