mirror of
https://github.com/panda3d/panda3d.git
synced 2025-09-30 16:58:40 -04:00
Support strip cut indices and (using those) support direct rendering of linestrips in OpenGL
This commit is contained in:
parent
db0fd516a0
commit
a25a9e655e
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
@ -598,6 +598,8 @@ public:
|
||||
PFNGLPOINTPARAMETERFVPROC _glPointParameterfv;
|
||||
bool _supports_point_sprite;
|
||||
|
||||
PFNGLPRIMITIVERESTARTINDEXPROC _glPrimitiveRestartIndex;
|
||||
|
||||
bool _supports_vertex_blend;
|
||||
PFNGLWEIGHTPOINTERARBPROC _glWeightPointer;
|
||||
PFNGLVERTEXBLENDARBPROC _glVertexBlend;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -61,18 +61,18 @@ make_cow_copy() {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GeomPrimitive::Constructor
|
||||
// Access: Published
|
||||
// Description:
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
GeomPrimitive::
|
||||
GeomPrimitive(GeomPrimitive::UsageHint usage_hint) {
|
||||
CDWriter cdata(_cycler, true);
|
||||
cdata->_usage_hint = usage_hint;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GeomPrimitive::Copy Constructor
|
||||
// Access: Published
|
||||
// Description:
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
GeomPrimitive::
|
||||
GeomPrimitive(const GeomPrimitive ©) :
|
||||
@ -80,7 +80,7 @@ GeomPrimitive(const GeomPrimitive ©) :
|
||||
_cycler(copy._cycler)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GeomPrimitive::Copy Assignment Operator
|
||||
// Access: Published
|
||||
@ -98,7 +98,7 @@ operator = (const GeomPrimitive ©) {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GeomPrimitive::Destructor
|
||||
// Access: Published, Virtual
|
||||
// Description:
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
GeomPrimitive::
|
||||
~GeomPrimitive() {
|
||||
@ -197,7 +197,7 @@ add_vertex(int vertex) {
|
||||
|
||||
int num_primitives = get_num_primitives();
|
||||
if (num_primitives > 0 &&
|
||||
requires_unused_vertices() &&
|
||||
requires_unused_vertices() &&
|
||||
get_num_vertices() == get_primitive_end(num_primitives - 1)) {
|
||||
// If we are beginning a new primitive, give the derived class a
|
||||
// chance to insert some degenerate vertices.
|
||||
@ -224,7 +224,7 @@ add_vertex(int vertex) {
|
||||
cdata->_got_minmax = false;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Otherwise, we need to suddenly become an indexed primitive.
|
||||
do_make_indexed(cdata);
|
||||
}
|
||||
@ -288,7 +288,7 @@ add_consecutive_vertices(int start, int num_vertices) {
|
||||
cdata->_got_minmax = false;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Otherwise, we need to suddenly become an indexed primitive.
|
||||
do_make_indexed(cdata);
|
||||
}
|
||||
@ -468,12 +468,18 @@ offset_vertices(int offset) {
|
||||
recompute_minmax(cdata);
|
||||
nassertv(cdata->_got_minmax);
|
||||
}
|
||||
|
||||
|
||||
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 {
|
||||
@ -483,7 +489,7 @@ offset_vertices(int offset) {
|
||||
cdata->_modified = Geom::get_next_modified();
|
||||
cdata->_got_minmax = false;
|
||||
|
||||
consider_elevate_index_type(cdata,
|
||||
consider_elevate_index_type(cdata,
|
||||
cdata->_first_vertex + cdata->_num_vertices - 1);
|
||||
}
|
||||
}
|
||||
@ -516,14 +522,19 @@ 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 {
|
||||
@ -544,7 +558,7 @@ offset_vertices(int offset, int begin_row, int end_row) {
|
||||
cdata->_modified = Geom::get_next_modified();
|
||||
cdata->_got_minmax = false;
|
||||
|
||||
consider_elevate_index_type(cdata,
|
||||
consider_elevate_index_type(cdata,
|
||||
cdata->_first_vertex + cdata->_num_vertices - 1);
|
||||
}
|
||||
}
|
||||
@ -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,14 +613,18 @@ 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
|
||||
// for v.
|
||||
pair<CopiedIndices::iterator, bool> result =
|
||||
pair<CopiedIndices::iterator, bool> result =
|
||||
copied_indices.insert(CopiedIndices::value_type(v, (int)copied_indices.size()));
|
||||
int v2 = (*result.first).second + dest_start;
|
||||
index.add_data1i(v2);
|
||||
@ -613,7 +634,7 @@ pack_vertices(GeomVertexData *dest, const GeomVertexData *source) {
|
||||
dest->copy_row_from(v2, source, v, current_thread);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
set_vertices(new_vertices);
|
||||
}
|
||||
}
|
||||
@ -643,7 +664,7 @@ make_indexed() {
|
||||
// Function: GeomPrimitive::get_primitive_start
|
||||
// Access: Published
|
||||
// Description: Returns the element within the _vertices list at which
|
||||
// the nth primitive starts.
|
||||
// the nth primitive starts.
|
||||
//
|
||||
// If i is one more than the highest valid primitive
|
||||
// vertex, the return value will be one more than the
|
||||
@ -723,7 +744,7 @@ get_primitive_num_vertices(int n) const {
|
||||
} else {
|
||||
int num_unused_vertices_per_primitive = get_num_unused_vertices_per_primitive();
|
||||
return cdata->_ends[n] - cdata->_ends[n - 1] - num_unused_vertices_per_primitive;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// This is a simple primitive type like a triangle: each primitive
|
||||
@ -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 {
|
||||
@ -1079,7 +1125,7 @@ request_resident() const {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GeomPrimitive::output
|
||||
// Access: Published, Virtual
|
||||
// Description:
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void GeomPrimitive::
|
||||
output(ostream &out) const {
|
||||
@ -1090,7 +1136,7 @@ output(ostream &out) const {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GeomPrimitive::write
|
||||
// Access: Published, Virtual
|
||||
// Description:
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void GeomPrimitive::
|
||||
write(ostream &out, int indent_level) const {
|
||||
@ -1448,7 +1494,7 @@ is_prepared(PreparedGraphicsObjects *prepared_objects) const {
|
||||
// rendered.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
IndexBufferContext *GeomPrimitive::
|
||||
prepare_now(PreparedGraphicsObjects *prepared_objects,
|
||||
prepare_now(PreparedGraphicsObjects *prepared_objects,
|
||||
GraphicsStateGuardianBase *gsg) {
|
||||
nassertr(is_indexed(), NULL);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1593,7 +1668,7 @@ get_highest_index_value(NumericType index_type) {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void GeomPrimitive::
|
||||
calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
|
||||
bool &found_any,
|
||||
bool &found_any,
|
||||
const GeomVertexData *vertex_data,
|
||||
bool got_mat, const LMatrix4 &mat,
|
||||
const InternalName *column_name,
|
||||
@ -1613,7 +1688,7 @@ calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
|
||||
for (int i = 0; i < cdata->_num_vertices; i++) {
|
||||
reader.set_row_unsafe(cdata->_first_vertex + i);
|
||||
LPoint3 vertex = mat.xform_point(reader.get_data3());
|
||||
|
||||
|
||||
if (found_any) {
|
||||
min_point.set(min(min_point[0], vertex[0]),
|
||||
min(min_point[1], vertex[1]),
|
||||
@ -1631,7 +1706,7 @@ calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
|
||||
for (int i = 0; i < cdata->_num_vertices; i++) {
|
||||
reader.set_row_unsafe(cdata->_first_vertex + i);
|
||||
const LVecBase3 &vertex = reader.get_data3();
|
||||
|
||||
|
||||
if (found_any) {
|
||||
min_point.set(min(min_point[0], vertex[0]),
|
||||
min(min_point[1], vertex[1]),
|
||||
@ -1650,13 +1725,17 @@ 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());
|
||||
|
||||
|
||||
if (found_any) {
|
||||
min_point.set(min(min_point[0], vertex[0]),
|
||||
min(min_point[1], vertex[1]),
|
||||
@ -1673,9 +1752,12 @@ 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();
|
||||
|
||||
|
||||
if (found_any) {
|
||||
min_point.set(min(min_point[0], vertex[0]),
|
||||
min(min_point[1], vertex[1]),
|
||||
@ -1797,63 +1879,77 @@ recompute_minmax(GeomPrimitive::CData *cdata) {
|
||||
cdata->_max_vertex = 0;
|
||||
cdata->_mins.clear();
|
||||
cdata->_maxs.clear();
|
||||
|
||||
|
||||
} else if (get_num_vertices_per_primitive() == 0) {
|
||||
// This is a complex primitive type like a triangle strip; compute
|
||||
// the minmax of each primitive (as well as the overall minmax).
|
||||
GeomVertexReader index(cdata->_vertices.get_read_pointer(), 0);
|
||||
|
||||
|
||||
cdata->_mins = make_index_data();
|
||||
cdata->_maxs = make_index_data();
|
||||
|
||||
|
||||
GeomVertexWriter mins(cdata->_mins.get_write_pointer(), 0);
|
||||
mins.reserve_num_rows(cdata->_ends.size());
|
||||
GeomVertexWriter maxs(cdata->_maxs.get_write_pointer(), 0);
|
||||
maxs.reserve_num_rows(cdata->_ends.size());
|
||||
|
||||
|
||||
int pi = 0;
|
||||
|
||||
|
||||
unsigned int vertex = index.get_data1i();
|
||||
cdata->_min_vertex = vertex;
|
||||
cdata->_max_vertex = vertex;
|
||||
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;
|
||||
max_prim = vertex;
|
||||
++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());
|
||||
|
||||
|
||||
} else {
|
||||
// This is a simple primitive type like a triangle; just compute
|
||||
// the overall minmax.
|
||||
GeomVertexReader index(cdata->_vertices.get_read_pointer(), 0);
|
||||
|
||||
|
||||
cdata->_mins.clear();
|
||||
cdata->_maxs.clear();
|
||||
|
||||
|
||||
unsigned int vertex = index.get_data1i();
|
||||
cdata->_min_vertex = vertex;
|
||||
cdata->_max_vertex = vertex;
|
||||
|
||||
|
||||
for (int vi = 1; vi < num_vertices; ++vi) {
|
||||
nassertv(!index.is_at_end());
|
||||
unsigned int vertex = index.get_data1i();
|
||||
@ -1862,7 +1958,7 @@ recompute_minmax(GeomPrimitive::CData *cdata) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
cdata->_got_minmax = true;
|
||||
}
|
||||
|
||||
@ -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()) {
|
||||
@ -1938,7 +2040,7 @@ do_set_index_type(CData *cdata, GeomPrimitive::NumericType index_type) {
|
||||
|
||||
if (!cdata->_vertices.is_null()) {
|
||||
CPT(GeomVertexArrayFormat) new_format = get_index_format();
|
||||
|
||||
|
||||
CPT(GeomVertexArrayData) array_obj = cdata->_vertices.get_read_pointer();
|
||||
if (array_obj->get_array_format() != new_format) {
|
||||
PT(GeomVertexArrayData) new_vertices = make_index_data();
|
||||
@ -1946,9 +2048,13 @@ do_set_index_type(CData *cdata, GeomPrimitive::NumericType index_type) {
|
||||
|
||||
GeomVertexReader from(array_obj, 0);
|
||||
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;
|
||||
@ -2056,7 +2162,7 @@ int GeomPrimitive::CData::
|
||||
complete_pointers(TypedWritable **p_list, BamReader *manager) {
|
||||
int pi = CycleData::complete_pointers(p_list, manager);
|
||||
|
||||
_vertices = DCAST(GeomVertexArrayData, p_list[pi++]);
|
||||
_vertices = DCAST(GeomVertexArrayData, p_list[pi++]);
|
||||
|
||||
if (manager->get_file_minor_ver() < 6 && !_vertices.is_null()) {
|
||||
// Older bam files might have a meaningless number in
|
||||
@ -2106,7 +2212,7 @@ check_minmax() const {
|
||||
#ifdef DO_PIPELINING
|
||||
unref_delete((CycleData *)_cdata);
|
||||
#endif
|
||||
GeomPrimitive::CDWriter fresh_cdata(((GeomPrimitive *)_object.p())->_cycler,
|
||||
GeomPrimitive::CDWriter fresh_cdata(((GeomPrimitive *)_object.p())->_cycler,
|
||||
false, _current_thread);
|
||||
((GeomPrimitivePipelineReader *)this)->_cdata = fresh_cdata;
|
||||
#ifdef DO_PIPELINING
|
||||
@ -2132,7 +2238,7 @@ check_minmax() const {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GeomPrimitivePipelineReader::get_first_vertex
|
||||
// Access: Public
|
||||
// Description:
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int GeomPrimitivePipelineReader::
|
||||
get_first_vertex() const {
|
||||
@ -2170,7 +2276,7 @@ get_vertex(int i) const {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GeomPrimitivePipelineReader::get_num_primitives
|
||||
// Access: Public
|
||||
// Description:
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int GeomPrimitivePipelineReader::
|
||||
get_num_primitives() const {
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
Loading…
x
Reference in New Issue
Block a user