Browse Source

define preserve-triangle-strips

David Rose 18 years ago
parent
commit
872c141de0

+ 1 - 1
panda/src/egg2pg/eggLoader.cxx

@@ -422,7 +422,7 @@ make_polyset(EggBin *egg_bin, PandaNode *parent, const LMatrix4d *transform,
           }
           }
         }
         }
       }
       }
-      
+
       geom_node->add_geom(geom, render_state->_state);
       geom_node->add_geom(geom, render_state->_state);
     }
     }
   }
   }

+ 8 - 0
panda/src/gobj/config_gobj.cxx

@@ -206,6 +206,14 @@ ConfigVariableBool connect_triangle_strips
           "triangle strip may help performance by reducing the number "
           "triangle strip may help performance by reducing the number "
           "of separate graphics calls that have to be made."));
           "of separate graphics calls that have to be made."));
 
 
+ConfigVariableBool preserve_triangle_strips
+("preserve-triangle-strips", false,
+ PRC_DESC("Set this true to indicate a preference for keeping triangle strips "
+          "when possible, instead of decomposing them into triangles.  When "
+          "this is true, flatten_strong and unify operations may be less "
+          "effective at combining multiple Geoms together, but they will "
+          "not implicitly decompose triangle strips."));
+
 ConfigVariableEnum<AutoTextureScale> textures_power_2
 ConfigVariableEnum<AutoTextureScale> textures_power_2
 ("textures-power-2", ATS_down,
 ("textures-power-2", ATS_down,
  PRC_DESC("Specify whether textures should automatically be constrained to "
  PRC_DESC("Specify whether textures should automatically be constrained to "

+ 1 - 0
panda/src/gobj/config_gobj.h

@@ -55,6 +55,7 @@ extern EXPCL_PANDA ConfigVariableBool hardware_point_sprites;
 extern EXPCL_PANDA ConfigVariableBool matrix_palette;
 extern EXPCL_PANDA ConfigVariableBool matrix_palette;
 extern EXPCL_PANDA ConfigVariableBool display_list_animation;
 extern EXPCL_PANDA ConfigVariableBool display_list_animation;
 extern EXPCL_PANDA ConfigVariableBool connect_triangle_strips;
 extern EXPCL_PANDA ConfigVariableBool connect_triangle_strips;
+extern EXPCL_PANDA ConfigVariableBool preserve_triangle_strips;
 
 
 extern EXPCL_PANDA ConfigVariableEnum<AutoTextureScale> textures_power_2;
 extern EXPCL_PANDA ConfigVariableEnum<AutoTextureScale> textures_power_2;
 extern EXPCL_PANDA ConfigVariableEnum<AutoTextureScale> textures_square;
 extern EXPCL_PANDA ConfigVariableEnum<AutoTextureScale> textures_square;

+ 110 - 53
panda/src/gobj/geom.cxx

@@ -551,75 +551,84 @@ unify_in_place(int max_indices) {
 
 
   CDWriter cdata(_cycler, true, current_thread);
   CDWriter cdata(_cycler, true, current_thread);
 
 
-  PT(GeomPrimitive) new_prim;
+  typedef pmap<TypeHandle, PT(GeomPrimitive) > NewPrims;
+
+  NewPrims new_prims;
 
 
   Primitives::const_iterator pi;
   Primitives::const_iterator pi;
   for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) {
   for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) {
     CPT(GeomPrimitive) primitive = (*pi).get_read_pointer();
     CPT(GeomPrimitive) primitive = (*pi).get_read_pointer();
-    if (new_prim == (GeomPrimitive *)NULL) {
-      // The first primitive type we come across is copied directly.
-      new_prim = primitive->make_copy();
+    NewPrims::iterator npi = new_prims.find(primitive->get_type());
+    if (npi == new_prims.end()) {
+      // This is the first primitive of this type.  Just store it.
+      new_prims.insert(NewPrims::value_type(primitive->get_type(), primitive->make_copy()));
+
     } else {
     } else {
-      // Thereafter, we must try to merge primitives.  If they are not
-      // the same type, we have to decompose both of them.
-      if (new_prim->get_type() != primitive->get_type()) {
-        CPT(GeomPrimitive) decomposed = new_prim->decompose();
-        new_prim = (GeomPrimitive *)decomposed.p();
-        primitive = primitive->decompose();
-
-        nassertv(new_prim->get_type() == primitive->get_type());
-      }
+      // We have already encountered another primitive of this type.
+      // Combine them.
+      combine_primitives((*npi).second, primitive, current_thread);
+    }
+  }
 
 
-      // Now simply copy in the vertices.
-      int num_primitives = primitive->get_num_primitives();
-      for (int pi = 0; pi < num_primitives; ++pi) {
-        int start = primitive->get_primitive_start(pi);
-        int end = primitive->get_primitive_end(pi);
-        for (int vi = start; vi < end; ++vi) {
-          new_prim->add_vertex(primitive->get_vertex(vi));
-        }
-        new_prim->close_primitive();
+  // Now, we have one or more primitives, but only one of each type.
+  if (!preserve_triangle_strips) {
+    // Recombine them into a single primitive by decomposing.
+    PT(GeomPrimitive) new_prim;
+    NewPrims::iterator npi;
+    for (npi = new_prims.begin(); npi != new_prims.end(); ++npi) {
+      CPT(GeomPrimitive) prim = (*npi).second->decompose();
+      if (new_prim.is_null()) {
+        new_prim = prim->make_copy();
+      } else {
+        combine_primitives(new_prim, prim, current_thread);
       }
       }
     }
     }
+
+    new_prims.clear();
+    new_prims.insert(NewPrims::value_type(new_prim->get_type(), new_prim));
   }
   }
 
 
-  // Now we have just one primitive.
-  nassertv(new_prim->check_valid(cdata->_data.get_read_pointer()));
+  // Finally, iterate through the remaining primitives, and copy them
+  // to the output list.
+  cdata->_primitives.clear();
+  NewPrims::iterator npi;
+  for (npi = new_prims.begin(); npi != new_prims.end(); ++npi) {
+    GeomPrimitive *prim = (*npi).second;
 
 
-  // The new primitive, naturally, inherits the Geom's overall shade
-  // model.
-  new_prim->set_shade_model(cdata->_shade_model);
+    nassertv(prim->check_valid(cdata->_data.get_read_pointer()));
 
 
-  cdata->_primitives.clear();
+    // Each new primitive, naturally, inherits the Geom's overall
+    // shade model.
+    prim->set_shade_model(cdata->_shade_model);
 
 
-  // Should we split it up again to satisfy max_indices?
-  if (new_prim->get_num_vertices() > max_indices) {
-    // Copy new_prim into smaller prims, no one of which has more than
-    // max_indices vertices.
-
-    int i = 0;
-
-    while (i < new_prim->get_num_primitives()) {
-      PT(GeomPrimitive) smaller = new_prim->make_copy();
-      smaller->clear_vertices();
-      while (i < new_prim->get_num_primitives() && 
-             smaller->get_num_vertices() + new_prim->get_primitive_num_vertices(i) < max_indices) {
-        int start = new_prim->get_primitive_start(i);
-        int end = new_prim->get_primitive_end(i);
-        for (int n = start; n < end; ++n) {
-          smaller->add_vertex(new_prim->get_vertex(n));
+    // Should we split it up again to satisfy max_indices?
+    if (prim->get_num_vertices() > max_indices) {
+      // Copy prim into smaller prims, no one of which has more than
+      // max_indices vertices.
+      int i = 0;
+      
+      while (i < prim->get_num_primitives()) {
+        PT(GeomPrimitive) smaller = prim->make_copy();
+        smaller->clear_vertices();
+        while (i < prim->get_num_primitives() && 
+               smaller->get_num_vertices() + prim->get_primitive_num_vertices(i) < max_indices) {
+          int start = prim->get_primitive_start(i);
+          int end = prim->get_primitive_end(i);
+          for (int n = start; n < end; ++n) {
+            smaller->add_vertex(prim->get_vertex(n));
+          }
+          smaller->close_primitive();
+          
+          ++i;
         }
         }
-        smaller->close_primitive();
-
-        ++i;
+      
+        cdata->_primitives.push_back(smaller.p());
       }
       }
-
-      cdata->_primitives.push_back(smaller.p());
+      
+    } else {
+      // The prim has few enough vertices; keep it.
+      cdata->_primitives.push_back(prim);
     }
     }
-
-  } else {
-    // The new_prim has few enough vertices; keep it.
-    cdata->_primitives.push_back(new_prim.p());
   }
   }
 
 
   cdata->_modified = Geom::get_next_modified();
   cdata->_modified = Geom::get_next_modified();
@@ -1206,6 +1215,54 @@ reset_geom_rendering(Geom::CData *cdata) {
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: Geom::combine_primitives
+//       Access: Private
+//  Description: Combines two primitives of the same type into a
+//               single primitive.  a_prim is modified to append the
+//               vertices from b_prim, which is unmodified.
+////////////////////////////////////////////////////////////////////
+void Geom::
+combine_primitives(GeomPrimitive *a_prim, const GeomPrimitive *b_prim,
+                   Thread *current_thread) {
+  nassertv(a_prim != b_prim);
+  nassertv(a_prim->get_type() == b_prim->get_type());
+
+  CPT(GeomPrimitive) b_prim2 = b_prim;
+
+  if (a_prim->get_index_type() != b_prim2->get_index_type()) {
+    GeomPrimitive::NumericType index_type = max(a_prim->get_index_type(), b_prim2->get_index_type());
+    a_prim->set_index_type(index_type);
+    if (b_prim2->get_index_type() != index_type) {
+      PT(GeomPrimitive) b_prim_copy = b_prim2->make_copy();
+      b_prim_copy->set_index_type(index_type);
+      b_prim2 = b_prim_copy;
+    }
+  }
+
+  if (!b_prim2->is_indexed()) {
+    PT(GeomPrimitive) b_prim_copy = b_prim2->make_copy();
+    b_prim_copy->make_indexed();
+    b_prim2 = b_prim_copy;
+  }
+
+  PT(GeomVertexArrayDataHandle) a_handle = a_prim->modify_vertices()->modify_handle(current_thread);
+  size_t orig_a_vertices = a_handle->get_num_rows();
+
+  CPT(GeomVertexArrayDataHandle) b_handle = b_prim2->get_vertices()->get_handle(current_thread);
+  a_handle->copy_subdata_from(a_handle->get_data_size_bytes(), 0,
+                              b_handle, 0, b_handle->get_data_size_bytes());
+  a_prim->clear_minmax();
+  if (a_prim->is_composite()) {
+    // Also copy the ends array.
+    PTA_int a_ends = a_prim->modify_ends();
+    CPTA_int b_ends = b_prim2->get_ends();
+    for (size_t i = 0; i < b_ends.size(); ++i) {
+      a_ends.push_back(b_ends[i] + orig_a_vertices);
+    }
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: Geom::register_with_read_factory
 //     Function: Geom::register_with_read_factory
 //       Access: Public, Static
 //       Access: Public, Static

+ 3 - 0
panda/src/gobj/geom.h

@@ -171,6 +171,9 @@ private:
   void reset_usage_hint(CData *cdata);
   void reset_usage_hint(CData *cdata);
   void reset_geom_rendering(CData *cdata);
   void reset_geom_rendering(CData *cdata);
 
 
+  void combine_primitives(GeomPrimitive *a_prim, const GeomPrimitive *b_prim,
+                          Thread *current_thread);
+
 private:
 private:
   typedef pvector<COWPT(GeomPrimitive) > Primitives;
   typedef pvector<COWPT(GeomPrimitive) > Primitives;
 
 

+ 9 - 1
panda/src/gobj/geomPrimitive.cxx

@@ -166,7 +166,9 @@ set_index_type(GeomPrimitive::NumericType index_type) {
   nassertv(get_max_vertex() <= get_highest_index_value(index_type));
   nassertv(get_max_vertex() <= get_highest_index_value(index_type));
 
 
   CDWriter cdata(_cycler, true);
   CDWriter cdata(_cycler, true);
-  do_set_index_type(cdata, index_type);
+  if (cdata->_index_type != index_type) {
+    do_set_index_type(cdata, index_type);
+  }
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -948,6 +950,12 @@ modify_ends() {
 
 
   cdata->_modified = Geom::get_next_modified();
   cdata->_modified = Geom::get_next_modified();
   cdata->_got_minmax = false;
   cdata->_got_minmax = false;
+
+  if (cdata->_ends.get_ref_count() > 1) {
+    PTA_int new_ends;
+    new_ends.v() = cdata->_ends.v();
+    cdata->_ends = new_ends;
+  }
   return cdata->_ends;
   return cdata->_ends;
 }
 }
 
 

+ 17 - 14
panda/src/gobj/geomVertexArrayData.cxx

@@ -732,28 +732,30 @@ copy_subdata_from(size_t to_start, size_t to_size,
   other->check_resident();
   other->check_resident();
 
 
   VertexDataBuffer &to_buffer = _cdata->_buffer;
   VertexDataBuffer &to_buffer = _cdata->_buffer;
-  to_start = min(to_start, to_buffer.get_size());
-  to_size = min(to_size, to_buffer.get_size() - to_start);
+  size_t to_buffer_orig_size = to_buffer.get_size();
+  to_start = min(to_start, to_buffer_orig_size);
+  to_size = min(to_size, to_buffer_orig_size - to_start);
 
 
   const VertexDataBuffer &from_buffer = other->_cdata->_buffer;
   const VertexDataBuffer &from_buffer = other->_cdata->_buffer;
-  from_start = min(from_start, from_buffer.get_size());
-  from_size = min(from_size, from_buffer.get_size() - from_start);
+  size_t from_buffer_orig_size = from_buffer.get_size();
+  from_start = min(from_start, from_buffer_orig_size);
+  from_size = min(from_size, from_buffer_orig_size - from_start);
 
 
   if (from_size < to_size) {
   if (from_size < to_size) {
     // Reduce the array.
     // Reduce the array.
     unsigned char *pointer = to_buffer.get_write_pointer();
     unsigned char *pointer = to_buffer.get_write_pointer();
     memmove(pointer + to_start + to_size, 
     memmove(pointer + to_start + to_size, 
             pointer + to_start + from_size,
             pointer + to_start + from_size,
-            from_size - (to_start + to_size));
-    to_buffer.clean_realloc(to_buffer.get_size() + from_size - to_size);
+            to_buffer_orig_size - (to_start + to_size));
+    to_buffer.clean_realloc(to_buffer_orig_size + from_size - to_size);
 
 
   } else if (to_size < from_size) {
   } else if (to_size < from_size) {
     // Expand the array.
     // Expand the array.
-    to_buffer.clean_realloc(to_buffer.get_size() + from_size - to_size);
+    to_buffer.clean_realloc(to_buffer_orig_size + from_size - to_size);
     unsigned char *pointer = to_buffer.get_write_pointer();
     unsigned char *pointer = to_buffer.get_write_pointer();
     memmove(pointer + to_start + to_size, 
     memmove(pointer + to_start + to_size, 
             pointer + to_start + from_size,
             pointer + to_start + from_size,
-            from_size - (to_start + from_size));
+            to_buffer_orig_size - (to_start + to_size));
   }
   }
 
 
   // Now copy the data.
   // Now copy the data.
@@ -805,8 +807,9 @@ set_subdata(size_t start, size_t size, const string &data) {
   check_resident();
   check_resident();
 
 
   VertexDataBuffer &to_buffer = _cdata->_buffer;
   VertexDataBuffer &to_buffer = _cdata->_buffer;
-  start = min(start, to_buffer.get_size());
-  size = min(size, to_buffer.get_size() - start);
+  size_t to_buffer_orig_size = to_buffer.get_size();
+  start = min(start, to_buffer_orig_size);
+  size = min(size, to_buffer_orig_size - start);
   
   
   size_t from_size = data.size();
   size_t from_size = data.size();
 
 
@@ -815,16 +818,16 @@ set_subdata(size_t start, size_t size, const string &data) {
     unsigned char *pointer = to_buffer.get_write_pointer();
     unsigned char *pointer = to_buffer.get_write_pointer();
     memmove(pointer + start + size, 
     memmove(pointer + start + size, 
             pointer + start + from_size,
             pointer + start + from_size,
-            from_size - (start + size));
-    to_buffer.clean_realloc(to_buffer.get_size() + from_size - size);
+            to_buffer_orig_size - (start + size));
+    to_buffer.clean_realloc(to_buffer_orig_size + from_size - size);
 
 
   } else if (size < from_size) {
   } else if (size < from_size) {
     // Expand the array.
     // Expand the array.
-    to_buffer.clean_realloc(to_buffer.get_size() + from_size - size);
+    to_buffer.clean_realloc(to_buffer_orig_size + from_size - size);
     unsigned char *pointer = to_buffer.get_write_pointer();
     unsigned char *pointer = to_buffer.get_write_pointer();
     memmove(pointer + start + size, 
     memmove(pointer + start + size, 
             pointer + start + from_size,
             pointer + start + from_size,
-            from_size - (start + from_size));
+            to_buffer_orig_size - (start + size));
   }
   }
 
 
   // Now copy the data.
   // Now copy the data.