From 061e9c78f145680b971ca9d19203919c562259f6 Mon Sep 17 00:00:00 2001 From: David Rose Date: Mon, 17 Jul 2006 22:16:05 +0000 Subject: [PATCH] automatically elevate geom indices to 32 bit if necessary --- panda/src/gobj/geomPrimitive.cxx | 133 ++++++++++++++++++++++++++----- panda/src/gobj/geomPrimitive.h | 3 + 2 files changed, 117 insertions(+), 19 deletions(-) diff --git a/panda/src/gobj/geomPrimitive.cxx b/panda/src/gobj/geomPrimitive.cxx index b2caba29e6..2fe0a6a5e0 100644 --- a/panda/src/gobj/geomPrimitive.cxx +++ b/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) { + nassertv(get_max_vertex() <= get_highest_index_value(index_type)); + CDWriter cdata(_cycler, true); - 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; - } - } + 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 diff --git a/panda/src/gobj/geomPrimitive.h b/panda/src/gobj/geomPrimitive.h index cf1dff007e..353d0b6420 100644 --- a/panda/src/gobj/geomPrimitive.h +++ b/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