Support strip cut indices and (using those) support direct rendering of linestrips in OpenGL

This commit is contained in:
rdb 2014-09-25 00:16:44 +00:00
parent db0fd516a0
commit a25a9e655e
12 changed files with 423 additions and 77 deletions

View File

@ -178,7 +178,10 @@ munge_geom_impl(CPT(Geom) &geom, CPT(GeomVertexData) &vertex_data,
// Even beyond munging the vertex format, we have to convert the
// Geom itself into a new primitive type the GSG can render
// directly.
if ((unsupported_bits & Geom::GR_composite_bits) != 0) {
// If we don't support a strip cut index, it might be faster to
// just decompose it rather than draw them one by one.
if ((unsupported_bits & Geom::GR_composite_bits) != 0 ||
(unsupported_bits & Geom::GR_strip_cut_index) != 0) {
// This decomposes everything in the primitive, so that if (for
// instance) the primitive contained both strips and fans, but
// the GSG didn't support fans, it would decompose the strips
@ -224,7 +227,10 @@ premunge_geom_impl(CPT(Geom) &geom, CPT(GeomVertexData) &vertex_data) {
// Even beyond munging the vertex format, we have to convert the
// Geom itself into a new primitive type the GSG can render
// directly.
if ((unsupported_bits & Geom::GR_composite_bits) != 0) {
// If we don't support a strip cut index, it might be faster to
// just decompose it rather than draw them one by one.
if ((unsupported_bits & Geom::GR_composite_bits) != 0 ||
(unsupported_bits & Geom::GR_strip_cut_index) != 0) {
// This decomposes everything in the primitive, so that if (for
// instance) the primitive contained both strips and fans, but
// the GSG didn't support fans, it would decompose the strips

View File

@ -515,6 +515,7 @@ reset() {
Geom::GR_point | Geom::GR_point_uniform_size |
Geom::GR_indexed_other |
Geom::GR_triangle_strip | Geom::GR_triangle_fan |
Geom::GR_line_strip |
Geom::GR_flat_last_vertex;
_supports_point_parameters = false;
@ -551,6 +552,30 @@ reset() {
_supported_geom_rendering |= Geom::GR_point_sprite;
}
_glPrimitiveRestartIndex = NULL;
if (is_at_least_gl_version(4, 3) || has_extension("GL_ARB_ES3_compatibility")) {
// As long as we enable this, OpenGL will always use the highest possible index
// for a numeric type as strip cut index, which coincides with our convention.
// This saves us a call to glPrimitiveRestartIndex.
glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
_supported_geom_rendering |= Geom::GR_strip_cut_index;
} else if (is_at_least_gl_version(3, 1)) {
glEnable(GL_PRIMITIVE_RESTART);
_supported_geom_rendering |= Geom::GR_strip_cut_index;
_glPrimitiveRestartIndex = (PFNGLPRIMITIVERESTARTINDEXPROC)
get_extension_func("glPrimitiveRestartIndex");
} else if (has_extension("GL_NV_primitive_restart")) {
glEnable(GL_PRIMITIVE_RESTART_NV);
_supported_geom_rendering |= Geom::GR_strip_cut_index;
_glPrimitiveRestartIndex = (PFNGLPRIMITIVERESTARTINDEXPROC)
get_extension_func("glPrimitiveRestartIndexNV");
}
_supports_vertex_blend = has_extension("GL_ARB_vertex_blend");
if (_supports_vertex_blend) {
@ -3800,7 +3825,113 @@ draw_lines(const GeomPrimitivePipelineReader *reader, bool force) {
////////////////////////////////////////////////////////////////////
bool CLP(GraphicsStateGuardian)::
draw_linestrips(const GeomPrimitivePipelineReader *reader, bool force) {
return false;
PStatGPUTimer timer(this, _draw_primitive_pcollector, reader->get_current_thread());
report_my_gl_errors();
#ifndef NDEBUG
if (GLCAT.is_spam()) {
GLCAT.spam() << "draw_linestrips: " << *(reader->get_object()) << "\n";
}
#endif // NDEBUG
#ifdef SUPPORT_IMMEDIATE_MODE
if (_use_sender) {
draw_immediate_composite_primitives(reader, GL_LINE_STRIP);
} else
#endif // SUPPORT_IMMEDIATE_MODE
{
if (reader->is_indexed() &&
(_supported_geom_rendering & GeomEnums::GR_strip_cut_index) != 0) {
// One long triangle strip, connected by strip cut indices.
if (_glPrimitiveRestartIndex != NULL) {
_glPrimitiveRestartIndex(reader->get_strip_cut_index());
}
int num_vertices = reader->get_num_vertices();
_vertices_other_pcollector.add_level(num_vertices);
_primitive_batches_other_pcollector.add_level(1);
const unsigned char *client_pointer;
if (!setup_primitive(client_pointer, reader, force)) {
return false;
}
#ifndef OPENGLES
if (_supports_geometry_instancing && _instance_count > 0) {
_glDrawElementsInstanced(GL_LINE_STRIP, num_vertices,
get_numeric_type(reader->get_index_type()),
client_pointer, _instance_count);
} else
#endif
{
_glDrawRangeElements(GL_LINE_STRIP,
reader->get_min_vertex(),
reader->get_max_vertex(),
num_vertices,
get_numeric_type(reader->get_index_type()),
client_pointer);
}
} else {
// Send the individual line strips, stepping over the
// strip-cut indices.
CPTA_int ends = reader->get_ends();
_primitive_batches_other_pcollector.add_level(ends.size());
if (reader->is_indexed()) {
const unsigned char *client_pointer;
if (!setup_primitive(client_pointer, reader, force)) {
return false;
}
int index_stride = reader->get_index_stride();
GeomVertexReader mins(reader->get_mins(), 0);
GeomVertexReader maxs(reader->get_maxs(), 0);
nassertr(reader->get_mins()->get_num_rows() == (int)ends.size() &&
reader->get_maxs()->get_num_rows() == (int)ends.size(), false);
unsigned int start = 0;
for (size_t i = 0; i < ends.size(); i++) {
_vertices_other_pcollector.add_level(ends[i] - start);
#ifndef OPENGLES
if (_supports_geometry_instancing && _instance_count > 0) {
_glDrawElementsInstanced(GL_LINE_STRIP, ends[i] - start,
get_numeric_type(reader->get_index_type()),
client_pointer + start * index_stride,
_instance_count);
} else
#endif
{
_glDrawRangeElements(GL_LINE_STRIP,
mins.get_data1i(), maxs.get_data1i(),
ends[i] - start,
get_numeric_type(reader->get_index_type()),
client_pointer + start * index_stride);
}
start = ends[i] + 1;
}
} else {
unsigned int start = 0;
int first_vertex = reader->get_first_vertex();
for (size_t i = 0; i < ends.size(); i++) {
_vertices_other_pcollector.add_level(ends[i] - start);
#ifndef OPENGLES
if (_supports_geometry_instancing && _instance_count > 0) {
_glDrawArraysInstanced(GL_LINE_STRIP, first_vertex + start,
ends[i] - start, _instance_count);
} else
#endif
{
glDrawArrays(GL_LINE_STRIP, first_vertex + start,
ends[i] - start);
}
start = ends[i] + 1;
}
}
}
}
report_my_gl_errors();
return true;
}
////////////////////////////////////////////////////////////////////

View File

@ -598,6 +598,8 @@ public:
PFNGLPOINTPARAMETERFVPROC _glPointParameterfv;
bool _supports_point_sprite;
PFNGLPRIMITIVERESTARTINDEXPROC _glPrimitiveRestartIndex;
bool _supports_vertex_blend;
PFNGLWEIGHTPOINTERARBPROC _glWeightPointer;
PFNGLVERTEXBLENDARBPROC _glVertexBlend;

View File

@ -1163,6 +1163,11 @@ extern "C" {
/* reuse GL_TEXTURE_IMMUTABLE_FORMAT */
#endif
#ifndef GL_VERSION_4_3
#define GL_VERSION_4_3 1
#define GL_PRIMITIVE_RESTART_FIXED_INDEX 0x8D69
#endif
#ifndef GL_ARB_multitexture
#define GL_TEXTURE0_ARB 0x84C0
#define GL_TEXTURE1_ARB 0x84C1

View File

@ -125,6 +125,9 @@ PUBLISHED:
// The union of all of the above composite types.
GR_composite_bits = 0x01c00,
// If strip-cut indices are used to restart a composite primitive.
GR_strip_cut_index = 0x20000,
// If the shade model requires a particular vertex for flat shading.
GR_flat_first_vertex = 0x02000,
GR_flat_last_vertex = 0x04000,
@ -216,4 +219,3 @@ EXPCL_PANDA_GOBJ ostream &operator << (ostream &out, GeomEnums::NumericType nume
EXPCL_PANDA_GOBJ ostream &operator << (ostream &out, GeomEnums::Contents contents);
#endif

View File

@ -89,7 +89,11 @@ get_primitive_type() const {
int GeomLinestrips::
get_geom_rendering() const {
if (is_indexed()) {
return GR_line_strip | GR_indexed_other;
if (get_num_primitives() > 1) {
return GR_line_strip | GR_indexed_other | GR_strip_cut_index;
} else {
return GR_line_strip | GR_indexed_other;
}
} else {
return GR_line_strip;
}
@ -106,6 +110,20 @@ get_min_num_vertices_per_primitive() const {
return 2;
}
////////////////////////////////////////////////////////////////////
// Function: GeomLinestrips::get_num_unused_vertices_per_primitive
// Access: Public, Virtual
// Description: Returns the number of vertices that are added between
// primitives that aren't, strictly speaking, part of
// the primitives themselves. This is used, for
// instance, to define degenerate triangles to connect
// otherwise disconnected triangle strips.
////////////////////////////////////////////////////////////////////
int GeomLinestrips::
get_num_unused_vertices_per_primitive() const {
return 1;
}
////////////////////////////////////////////////////////////////////
// Function: GeomLinestrips::draw
// Access: Public, Virtual
@ -138,9 +156,13 @@ decompose_impl() const {
lines->set_shade_model(get_shade_model());
CPTA_int ends = get_ends();
int vi = 0;
int num_unused = get_num_unused_vertices_per_primitive();
int vi = -num_unused;
int li = 0;
while (li < (int)ends.size()) {
// Skip unused vertices between tristrips.
vi += num_unused;
int end = ends[li];
nassertr(vi + 1 <= end, lines.p());
int v0 = get_vertex(vi);
@ -210,6 +232,33 @@ rotate_impl() const {
return new_vertices;
}
////////////////////////////////////////////////////////////////////
// Function: GeomLinestrips::requires_unused_vertices
// Access: Protected, Virtual
// Description: Should be redefined to return true in any primitive
// that implements append_unused_vertices().
////////////////////////////////////////////////////////////////////
bool GeomLinestrips::
requires_unused_vertices() const {
return true;
}
////////////////////////////////////////////////////////////////////
// Function: GeomLinestrips::append_unused_vertices
// Access: Protected, Virtual
// Description: Called when a new primitive is begun (other than the
// first primitive), this should add some degenerate
// vertices between primitives, if the primitive type
// requires that. The second parameter is the first
// vertex that begins the new primitive.
////////////////////////////////////////////////////////////////////
void GeomLinestrips::
append_unused_vertices(GeomVertexArrayData *vertices, int vertex) {
GeomVertexWriter to(vertices, 0);
to.set_row_unsafe(vertices->get_num_rows());
to.add_data1i(get_strip_cut_index());
}
////////////////////////////////////////////////////////////////////
// Function: GeomLinestrips::register_with_read_factory
// Access: Public, Static

View File

@ -34,6 +34,7 @@ public:
virtual PrimitiveType get_primitive_type() const;
virtual int get_geom_rendering() const;
virtual int get_min_num_vertices_per_primitive() const;
virtual int get_num_unused_vertices_per_primitive() const;
public:
virtual bool draw(GraphicsStateGuardianBase *gsg,
@ -43,6 +44,9 @@ public:
protected:
virtual CPT(GeomPrimitive) decompose_impl() const;
virtual CPT(GeomVertexArrayData) rotate_impl() const;
virtual bool requires_unused_vertices() const;
virtual void append_unused_vertices(GeomVertexArrayData *vertices,
int vertex);
public:
static void register_with_read_factory();

View File

@ -129,7 +129,7 @@ get_first_vertex() const {
////////////////////////////////////////////////////////////////////
// Function: GeomPrimitive::get_num_vertices
// Access: Published
// Description: Returns the number of vertices used by all the
// Description: Returns the number of indices used by all the
// primitives in this object.
////////////////////////////////////////////////////////////////////
INLINE int GeomPrimitive::
@ -310,6 +310,20 @@ get_index_stride() const {
return reader.get_index_stride();
}
////////////////////////////////////////////////////////////////////
// Function: GeomPrimitive::get_strip_cut_index
// Access: Published
// Description: If relevant, returns the index value that may be
// used in some cases to signify the end of a
// primitive. This is typically the highest value
// that the numeric type can store.
////////////////////////////////////////////////////////////////////
INLINE int GeomPrimitive::
get_strip_cut_index() const {
CDReader cdata(_cycler);
return get_strip_cut_index(cdata->_index_type);
}
////////////////////////////////////////////////////////////////////
// Function: GeomPrimitive::get_ends
// Access: Published
@ -679,6 +693,16 @@ get_read_pointer(bool force) const {
return _vertices_reader->get_read_pointer(force);
}
////////////////////////////////////////////////////////////////////
// Function: GeomPrimitivePipelineReader::get_strip_cut_index
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE int GeomPrimitivePipelineReader::
get_strip_cut_index() const {
return GeomPrimitive::get_strip_cut_index(_cdata->_index_type);
}
////////////////////////////////////////////////////////////////////
// Function: GeomPrimitivePipelineReader::get_ends
// Access: Public

View File

@ -471,9 +471,15 @@ offset_vertices(int offset) {
consider_elevate_index_type(cdata, cdata->_max_vertex + offset);
int strip_cut_index = get_strip_cut_index(cdata->_index_type);
GeomVertexRewriter index(do_modify_vertices(cdata), 0);
while (!index.is_at_end()) {
index.set_data1i(index.get_data1i() + offset);
int vertex = index.get_data1i();
if (vertex != strip_cut_index) {
index.set_data1i(vertex + offset);
}
}
} else {
@ -517,13 +523,18 @@ offset_vertices(int offset, int begin_row, int end_row) {
if (is_indexed()) {
CDWriter cdata(_cycler, true);
int strip_cut_index = get_strip_cut_index(cdata->_index_type);
// Calculate the maximum vertex over our range.
int max_vertex = 0;
{
GeomVertexReader index_r(cdata->_vertices.get_read_pointer(), 0);
index_r.set_row_unsafe(begin_row);
for (int j = begin_row; j < end_row; ++j) {
max_vertex = max(max_vertex, index_r.get_data1i());
int vertex = index_r.get_data1i();
if (vertex != strip_cut_index) {
max_vertex = max(max_vertex, vertex);
}
}
}
@ -532,7 +543,10 @@ offset_vertices(int offset, int begin_row, int end_row) {
GeomVertexRewriter index(do_modify_vertices(cdata), 0);
index.set_row_unsafe(begin_row);
for (int j = begin_row; j < end_row; ++j) {
index.set_data1i(index.get_data1i() + offset);
int vertex = index.get_data1i();
if (vertex != strip_cut_index) {
index.set_data1i(vertex + offset);
}
}
} else {
@ -554,17 +568,20 @@ offset_vertices(int offset, int begin_row, int end_row) {
// Access: Published
// Description: Converts the primitive from indexed to nonindexed by
// duplicating vertices as necessary into the indicated
// dest GeomVertexData.
// dest GeomVertexData. Note: does not support
// primitives with strip cut indices.
////////////////////////////////////////////////////////////////////
void GeomPrimitive::
make_nonindexed(GeomVertexData *dest, const GeomVertexData *source) {
Thread *current_thread = Thread::get_current_thread();
int num_vertices = get_num_vertices();
int dest_start = dest->get_num_rows();
int strip_cut_index = get_strip_cut_index();
dest->set_num_rows(dest_start + num_vertices);
for (int i = 0; i < num_vertices; ++i) {
int v = get_vertex(i);
nassertd(v != strip_cut_index) continue;
dest->copy_row_from(dest_start + i, source, v, current_thread);
}
@ -596,9 +613,13 @@ pack_vertices(GeomVertexData *dest, const GeomVertexData *source) {
int num_vertices = get_num_vertices();
int dest_start = dest->get_num_rows();
int strip_cut_index = get_strip_cut_index();
for (int i = 0; i < num_vertices; ++i) {
int v = get_vertex(i);
if (v == strip_cut_index) {
continue;
}
// Try to add the relation { v : size() }. If that succeeds,
// great; if it doesn't, look up whatever we previously added
@ -732,6 +753,28 @@ get_primitive_num_vertices(int n) const {
}
}
////////////////////////////////////////////////////////////////////
// Function: GeomPrimitive::get_num_used_vertices
// Access: Published
// Description: Returns the number of vertices used by all of the
// primitives. This is the same as summing
// get_primitive_num_vertices(n) for n in
// get_num_primitives(). It is like get_num_vertices
// except that it excludes all of the degenerate
// vertices and strip-cut indices.
////////////////////////////////////////////////////////////////////
int GeomPrimitive::
get_num_used_vertices() const {
int num_primitives = get_num_primitives();
if (num_primitives > 0) {
return get_num_vertices() - ((num_primitives - 1) *
get_num_unused_vertices_per_primitive());
} else {
return 0;
}
}
////////////////////////////////////////////////////////////////////
// Function: GeomPrimitive::get_primitive_min_vertex
// Access: Published
@ -959,10 +1002,14 @@ make_points() const {
int num_vertices = get_num_vertices();
if (is_indexed()) {
CPT(GeomVertexArrayData) vertices = get_vertices();
int strip_cut_index = get_strip_cut_index();
GeomVertexReader index(vertices, 0);
for (int vi = 0; vi < num_vertices; ++vi) {
nassertr(!index.is_at_end(), NULL);
bits.set_bit(index.get_data1i());
int vertex = index.get_data1i();
if (vertex != strip_cut_index) {
bits.set_bit(vertex);
}
}
} else {
int first_vertex = get_first_vertex();
@ -996,14 +1043,13 @@ make_points() const {
// Access: Published
// Description: Decomposes a complex primitive type into a simpler
// primitive type, for instance triangle strips to
// triangles, puts these in a new GeomPatches objectand returns a pointer to the new primitive
// triangles, puts these in a new GeomPatches object
// and returns a pointer to the new primitive
// definition. If the decomposition cannot be
// performed, this might return the original object.
//
// This method is useful for application code that wants
// to iterate through the set of triangles on the
// primitive without having to write handlers for each
// possible kind of primitive type.
// to use tesselation shaders on arbitrary geometry.
////////////////////////////////////////////////////////////////////
CPT(GeomPrimitive) GeomPrimitive::
make_patches() const {
@ -1558,11 +1604,44 @@ 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.
// Description: Returns the largest index value that can be stored
// in an index of the indicated type, minus one (to
// leave room for a potential strip cut index)
////////////////////////////////////////////////////////////////////
int GeomPrimitive::
get_highest_index_value(NumericType index_type) {
// Reserve the highest possible index because implementations use
// this as a strip-cut index.
switch (index_type) {
case NT_uint8:
return 0xff - 1;
case NT_uint16:
return 0xffff - 1;
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 - 1;
default:
return 0;
}
}
////////////////////////////////////////////////////////////////////
// Function: GeomPrimitive::get_strip_cut_index
// Access: Private, Static
// Description: Returns the index of the indicated type that is
// reserved for use as a strip cut index, if enabled
// for the primitive. When the renderer encounters
// this index, it will restart the primitive. This
// is guaranteed not to point to an actual vertex.
////////////////////////////////////////////////////////////////////
int GeomPrimitive::
get_strip_cut_index(NumericType index_type) {
// Reserve the highest possible index because implementations use
// this as a strip-cut index.
switch (index_type) {
case NT_uint8:
return 0xff;
@ -1571,12 +1650,8 @@ get_highest_index_value(NumericType index_type) {
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;
return -1;
}
}
@ -1650,10 +1725,14 @@ calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
} else {
// Indexed case.
GeomVertexReader index(cdata->_vertices.get_read_pointer(), 0, current_thread);
int strip_cut_index = get_strip_cut_index(cdata->_index_type);
if (got_mat) {
while (!index.is_at_end()) {
int ii = index.get_data1i();
if (ii == strip_cut_index) {
continue;
}
reader.set_row_unsafe(ii);
LPoint3 vertex = mat.xform_point(reader.get_data3());
@ -1673,6 +1752,9 @@ calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
} else {
while (!index.is_at_end()) {
int ii = index.get_data1i();
if (ii == strip_cut_index) {
continue;
}
reader.set_row_unsafe(ii);
const LVecBase3 &vertex = reader.get_data3();
@ -1819,14 +1901,23 @@ recompute_minmax(GeomPrimitive::CData *cdata) {
unsigned int min_prim = vertex;
unsigned int max_prim = vertex;
int num_unused_vertices = get_num_unused_vertices_per_primitive();
for (int vi = 1; vi < num_vertices; ++vi) {
nassertv(!index.is_at_end());
unsigned int vertex = index.get_data1i();
cdata->_min_vertex = min(cdata->_min_vertex, vertex);
cdata->_max_vertex = max(cdata->_max_vertex, vertex);
nassertv(pi < (int)cdata->_ends.size());
unsigned int vertex;
if (vi == cdata->_ends[pi]) {
// Skip unused vertices, since they won't be very relevant and
// may contain a strip-cut index, which would distort the result.
if (num_unused_vertices > 0) {
vi += num_unused_vertices;
index.set_row_unsafe(vi);
}
vertex = index.get_data1i();
mins.add_data1i(min_prim);
maxs.add_data1i(max_prim);
min_prim = vertex;
@ -1834,10 +1925,15 @@ recompute_minmax(GeomPrimitive::CData *cdata) {
++pi;
} else {
vertex = index.get_data1i();
min_prim = min(min_prim, vertex);
max_prim = max(max_prim, vertex);
}
cdata->_min_vertex = min(cdata->_min_vertex, vertex);
cdata->_max_vertex = max(cdata->_max_vertex, vertex);
}
mins.add_data1i(min_prim);
maxs.add_data1i(max_prim);
nassertv(mins.get_array_data()->get_num_rows() == (int)cdata->_ends.size());
@ -1899,22 +1995,25 @@ do_make_indexed(CData *cdata) {
////////////////////////////////////////////////////////////////////
void GeomPrimitive::
consider_elevate_index_type(CData *cdata, int vertex) {
// Note that we reserve the highest possible index of a particular
// index type (ie. -1) because this is commonly used as a strip-cut
// (also known as primitive restart) index.
switch (cdata->_index_type) {
case NT_uint8:
if (vertex > 0xff) {
if (vertex >= 0xff) {
do_set_index_type(cdata, NT_uint16);
}
break;
case NT_uint16:
if (vertex > 0xffff) {
if (vertex >= 0xffff) {
do_set_index_type(cdata, NT_uint32);
}
break;
case NT_uint32:
// Not much we can do here.
nassertv(vertex <= 0x7fffffff);
nassertv(vertex < 0x7fffffff);
break;
default:
@ -1929,6 +2028,9 @@ consider_elevate_index_type(CData *cdata, int vertex) {
////////////////////////////////////////////////////////////////////
void GeomPrimitive::
do_set_index_type(CData *cdata, GeomPrimitive::NumericType index_type) {
int old_strip_cut_index = get_strip_cut_index(cdata->_index_type);
int new_strip_cut_index = get_strip_cut_index(index_type);
cdata->_index_type = index_type;
if (gobj_cat.is_debug()) {
@ -1948,7 +2050,11 @@ do_set_index_type(CData *cdata, GeomPrimitive::NumericType index_type) {
GeomVertexWriter to(new_vertices, 0);
while (!from.is_at_end()) {
to.set_data1i(from.get_data1i());
int index = from.get_data1i();
if (index == old_strip_cut_index) {
index = new_strip_cut_index;
}
to.set_data1i(index);
}
cdata->_vertices = new_vertices;
cdata->_got_minmax = false;

View File

@ -118,6 +118,7 @@ PUBLISHED:
int get_primitive_start(int n) const;
int get_primitive_end(int n) const;
int get_primitive_num_vertices(int n) const;
int get_num_used_vertices() const;
INLINE int get_num_faces() const;
INLINE int get_primitive_num_faces(int n) const;
@ -163,6 +164,7 @@ PUBLISHED:
void set_nonindexed_vertices(int first_vertex, int num_vertices);
INLINE int get_index_stride() const;
INLINE int get_strip_cut_index() const;
INLINE CPTA_int get_ends() const;
PTA_int modify_ends();
@ -194,6 +196,7 @@ public:
private:
void clear_prepared(PreparedGraphicsObjects *prepared_objects);
static int get_highest_index_value(NumericType index_type);
static int get_strip_cut_index(NumericType index_type);
public:
virtual bool draw(GraphicsStateGuardianBase *gsg,
@ -358,6 +361,7 @@ public:
INLINE int get_index_stride() const;
INLINE const GeomVertexArrayDataHandle *get_vertices_reader() const;
INLINE const unsigned char *get_read_pointer(bool force) const;
INLINE int get_strip_cut_index() const;
INLINE CPTA_int get_ends() const;
INLINE CPT(GeomVertexArrayData) get_mins() const;
INLINE CPT(GeomVertexArrayData) get_maxs() const;

View File

@ -95,6 +95,17 @@ get_geom_rendering() const {
}
}
////////////////////////////////////////////////////////////////////
// Function: GeomTristrips::get_min_num_vertices_per_primitive
// Access: Public, Virtual
// Description: Returns the minimum number of vertices that must be
// added before close_primitive() may legally be called.
////////////////////////////////////////////////////////////////////
int GeomTristrips::
get_min_num_vertices_per_primitive() const {
return 3;
}
////////////////////////////////////////////////////////////////////
// Function: GeomTristrips::get_num_unused_vertices_per_primitive
// Access: Public, Virtual
@ -142,6 +153,7 @@ decompose_impl() const {
CPTA_int ends = get_ends();
int num_vertices = get_num_vertices();
int num_unused = get_num_unused_vertices_per_primitive();
// We need a slightly different algorithm for SM_flat_first_vertex
// than for SM_flat_last_vertex, to preserve the key vertex in the
@ -150,11 +162,11 @@ decompose_impl() const {
if (get_shade_model() == SM_flat_first_vertex) {
// Preserve the first vertex of each component triangle as the
// first vertex of each generated triangle.
int vi = -2;
int vi = -num_unused;
int li = 0;
while (li < (int)ends.size()) {
// Skip unused vertices between tristrips.
vi += 2;
vi += num_unused;
int end = ends[li];
nassertr(vi + 2 <= end, NULL);
int v0 = get_vertex(vi);
@ -192,11 +204,11 @@ decompose_impl() const {
} else {
// Preserve the last vertex of each component triangle as the
// last vertex of each generated triangle.
int vi = -2;
int vi = -num_unused;
int li = 0;
while (li < (int)ends.size()) {
// Skip unused vertices between tristrips.
vi += 2;
vi += num_unused;
int end = ends[li];
nassertr(vi + 2 <= end, NULL);
int v0 = get_vertex(vi);

View File

@ -33,6 +33,7 @@ public:
virtual PT(GeomPrimitive) make_copy() const;
virtual PrimitiveType get_primitive_type() const;
virtual int get_geom_rendering() const;
virtual int get_min_num_vertices_per_primitive() const;
virtual int get_num_unused_vertices_per_primitive() const;
public: