Browse Source

automatically elevate geom indices to 32 bit if necessary

David Rose 19 years ago
parent
commit
061e9c78f1
2 changed files with 117 additions and 19 deletions
  1. 114 19
      panda/src/gobj/geomPrimitive.cxx
  2. 3 0
      panda/src/gobj/geomPrimitive.h

+ 114 - 19
panda/src/gobj/geomPrimitive.cxx

@@ -142,32 +142,23 @@ set_usage_hint(GeomPrimitive::UsageHint usage_hint) {
 //               Normally, this should be either NT_uint16 or
 //               NT_uint32.
 //
+//               The index type must be large enough to include all of
+//               the index values in the primitive.  It may be
+//               automatically elevated, if necessary, to a larger
+//               index type, by a subsequent call to add_index() that
+//               names an index value that does not fit in the index
+//               type you specify.
+//
 //               Don't call this in a downstream thread unless you
 //               don't mind it blowing away other changes you might
 //               have recently made in an upstream thread.
 ////////////////////////////////////////////////////////////////////
 void GeomPrimitive::
 set_index_type(GeomPrimitive::NumericType index_type) {
-  CDWriter cdata(_cycler, true);
-  cdata->_index_type = index_type;
+  nassertv(get_max_vertex() <= get_highest_index_value(index_type));
 
-  if (cdata->_vertices != (GeomVertexArrayData *)NULL) {
-    CPT(GeomVertexArrayFormat) new_format = get_index_format();
-    
-    if (cdata->_vertices->get_array_format() != new_format) {
-      PT(GeomVertexArrayData) new_vertices = make_index_data();
-      new_vertices->set_num_rows(cdata->_vertices->get_num_rows());
-
-      GeomVertexReader from(cdata->_vertices, 0);
-      GeomVertexWriter to(new_vertices, 0);
-      
-      while (!from.is_at_end()) {
-        to.set_data1i(from.get_data1i());
-      }
-      cdata->_vertices = new_vertices;
-      cdata->_got_minmax = false;
-    }
-  }
+  CDWriter cdata(_cycler, true);
+  do_set_index_type(cdata, index_type);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -188,6 +179,8 @@ void GeomPrimitive::
 add_vertex(int vertex) {
   CDWriter cdata(_cycler, true);
 
+  consider_elevate_index_type(cdata, vertex);
+
   int num_primitives = get_num_primitives();
   if (num_primitives > 0 &&
       requires_unused_vertices() && 
@@ -249,6 +242,8 @@ add_consecutive_vertices(int start, int num_vertices) {
 
   CDWriter cdata(_cycler, true);
 
+  consider_elevate_index_type(cdata, end);
+
   int num_primitives = get_num_primitives();
   if (num_primitives > 0 &&
       get_num_vertices() == get_primitive_end(num_primitives - 1)) {
@@ -382,6 +377,12 @@ clear_vertices() {
   CDWriter cdata(_cycler, true);
   cdata->_first_vertex = 0;
   cdata->_num_vertices = 0;
+
+  // Since we might have automatically elevated the index type by
+  // adding vertices, we should automatically lower it again when we
+  // call clear_vertices().
+  cdata->_index_type = NT_uint16;
+
   cdata->_vertices.clear();
   cdata->_ends.clear();
   cdata->_mins.clear();
@@ -403,6 +404,11 @@ clear_vertices() {
 void GeomPrimitive::
 offset_vertices(int offset) {
   if (is_indexed()) {
+    {
+      CDWriter cdata(_cycler, true);
+      consider_elevate_index_type(cdata, get_max_vertex() + offset);
+    }
+
     GeomVertexRewriter index(modify_vertices(), 0);
     while (!index.is_at_end()) {
       index.set_data1i(index.get_data1i() + offset);
@@ -410,9 +416,13 @@ offset_vertices(int offset) {
 
   } else {
     CDWriter cdata(_cycler, true);
+
     cdata->_first_vertex += offset;
     cdata->_modified = Geom::get_next_modified();
     cdata->_got_minmax = false;
+
+    consider_elevate_index_type(cdata, 
+                                cdata->_first_vertex + cdata->_num_vertices - 1);
   }
 }
 
@@ -1111,6 +1121,31 @@ clear_prepared(PreparedGraphicsObjects *prepared_objects) {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GeomPrimitive::get_highest_index_value
+//       Access: Private, Static
+//  Description: Returns the largest index value that can be stored in
+//               an index of the indicated type.
+////////////////////////////////////////////////////////////////////
+int GeomPrimitive::
+get_highest_index_value(NumericType index_type) {
+  switch (index_type) {
+  case NT_uint8:
+    return 0xff;
+
+  case NT_uint16:
+    return 0xffff;
+
+  case NT_uint32:
+    // We don't actually allow use of the sign bit, since all of our
+    // functions receive an "int" instead of an "unsigned int".
+    return 0x7fffffff;
+
+  default:
+    return 0;
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomPrimitive::calc_tight_bounds
 //       Access: Public, Virtual
@@ -1382,6 +1417,66 @@ do_make_indexed(CData *cdata) {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GeomPrimitive::consider_elevate_index_type
+//       Access: Private
+//  Description: If the indicated new vertex index won't fit in the
+//               specified index type, automatically elevates the
+//               index type to the next available size.
+////////////////////////////////////////////////////////////////////
+void GeomPrimitive::
+consider_elevate_index_type(CData *cdata, int vertex) {
+  switch (cdata->_index_type) {
+  case NT_uint8:
+    if (vertex > 0xff) {
+      do_set_index_type(cdata, NT_uint16);
+    }
+    break;
+
+  case NT_uint16:
+    if (vertex > 0xffff) {
+      do_set_index_type(cdata, NT_uint32);
+    }
+    break;
+
+  case NT_uint32:
+    // Not much we can do here.
+    nassertv(vertex <= 0x7fffffff);
+    break;
+
+  default:
+    break;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomPrimitive::do_set_index_type
+//       Access: Private
+//  Description: The private implementation of set_index_type().
+////////////////////////////////////////////////////////////////////
+void GeomPrimitive::
+do_set_index_type(CData *cdata, GeomPrimitive::NumericType index_type) {
+  cdata->_index_type = index_type;
+
+  if (cdata->_vertices != (GeomVertexArrayData *)NULL) {
+    CPT(GeomVertexArrayFormat) new_format = get_index_format();
+    
+    if (cdata->_vertices->get_array_format() != new_format) {
+      PT(GeomVertexArrayData) new_vertices = make_index_data();
+      new_vertices->set_num_rows(cdata->_vertices->get_num_rows());
+
+      GeomVertexReader from(cdata->_vertices, 0);
+      GeomVertexWriter to(new_vertices, 0);
+      
+      while (!from.is_at_end()) {
+        to.set_data1i(from.get_data1i());
+      }
+      cdata->_vertices = new_vertices;
+      cdata->_got_minmax = false;
+    }
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomPrimitive::write_datagram
 //       Access: Public, Virtual

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

@@ -184,6 +184,7 @@ protected:
 
 private:
   void clear_prepared(PreparedGraphicsObjects *prepared_objects);
+  static int get_highest_index_value(NumericType index_type);
 
 public:
   virtual void draw(GraphicsStateGuardianBase *gsg,
@@ -207,6 +208,8 @@ private:
 
   void recompute_minmax(CData *cdata);
   void do_make_indexed(CData *cdata);
+  void consider_elevate_index_type(CData *cdata, int vertex);
+  void do_set_index_type(CData *cdata, NumericType index_type);
 
 private:
   // A GeomPrimitive keeps a list (actually, a map) of all the