mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-02 09:52:27 -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
|
// Even beyond munging the vertex format, we have to convert the
|
||||||
// Geom itself into a new primitive type the GSG can render
|
// Geom itself into a new primitive type the GSG can render
|
||||||
// directly.
|
// 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
|
// This decomposes everything in the primitive, so that if (for
|
||||||
// instance) the primitive contained both strips and fans, but
|
// instance) the primitive contained both strips and fans, but
|
||||||
// the GSG didn't support fans, it would decompose the strips
|
// 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
|
// Even beyond munging the vertex format, we have to convert the
|
||||||
// Geom itself into a new primitive type the GSG can render
|
// Geom itself into a new primitive type the GSG can render
|
||||||
// directly.
|
// 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
|
// This decomposes everything in the primitive, so that if (for
|
||||||
// instance) the primitive contained both strips and fans, but
|
// instance) the primitive contained both strips and fans, but
|
||||||
// the GSG didn't support fans, it would decompose the strips
|
// 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_point | Geom::GR_point_uniform_size |
|
||||||
Geom::GR_indexed_other |
|
Geom::GR_indexed_other |
|
||||||
Geom::GR_triangle_strip | Geom::GR_triangle_fan |
|
Geom::GR_triangle_strip | Geom::GR_triangle_fan |
|
||||||
|
Geom::GR_line_strip |
|
||||||
Geom::GR_flat_last_vertex;
|
Geom::GR_flat_last_vertex;
|
||||||
|
|
||||||
_supports_point_parameters = false;
|
_supports_point_parameters = false;
|
||||||
@ -551,6 +552,30 @@ reset() {
|
|||||||
_supported_geom_rendering |= Geom::GR_point_sprite;
|
_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");
|
_supports_vertex_blend = has_extension("GL_ARB_vertex_blend");
|
||||||
|
|
||||||
if (_supports_vertex_blend) {
|
if (_supports_vertex_blend) {
|
||||||
@ -3800,7 +3825,113 @@ draw_lines(const GeomPrimitivePipelineReader *reader, bool force) {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
bool CLP(GraphicsStateGuardian)::
|
bool CLP(GraphicsStateGuardian)::
|
||||||
draw_linestrips(const GeomPrimitivePipelineReader *reader, bool force) {
|
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;
|
PFNGLPOINTPARAMETERFVPROC _glPointParameterfv;
|
||||||
bool _supports_point_sprite;
|
bool _supports_point_sprite;
|
||||||
|
|
||||||
|
PFNGLPRIMITIVERESTARTINDEXPROC _glPrimitiveRestartIndex;
|
||||||
|
|
||||||
bool _supports_vertex_blend;
|
bool _supports_vertex_blend;
|
||||||
PFNGLWEIGHTPOINTERARBPROC _glWeightPointer;
|
PFNGLWEIGHTPOINTERARBPROC _glWeightPointer;
|
||||||
PFNGLVERTEXBLENDARBPROC _glVertexBlend;
|
PFNGLVERTEXBLENDARBPROC _glVertexBlend;
|
||||||
|
@ -1163,6 +1163,11 @@ extern "C" {
|
|||||||
/* reuse GL_TEXTURE_IMMUTABLE_FORMAT */
|
/* reuse GL_TEXTURE_IMMUTABLE_FORMAT */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef GL_VERSION_4_3
|
||||||
|
#define GL_VERSION_4_3 1
|
||||||
|
#define GL_PRIMITIVE_RESTART_FIXED_INDEX 0x8D69
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef GL_ARB_multitexture
|
#ifndef GL_ARB_multitexture
|
||||||
#define GL_TEXTURE0_ARB 0x84C0
|
#define GL_TEXTURE0_ARB 0x84C0
|
||||||
#define GL_TEXTURE1_ARB 0x84C1
|
#define GL_TEXTURE1_ARB 0x84C1
|
||||||
|
@ -125,6 +125,9 @@ PUBLISHED:
|
|||||||
// The union of all of the above composite types.
|
// The union of all of the above composite types.
|
||||||
GR_composite_bits = 0x01c00,
|
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.
|
// If the shade model requires a particular vertex for flat shading.
|
||||||
GR_flat_first_vertex = 0x02000,
|
GR_flat_first_vertex = 0x02000,
|
||||||
GR_flat_last_vertex = 0x04000,
|
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);
|
EXPCL_PANDA_GOBJ ostream &operator << (ostream &out, GeomEnums::Contents contents);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -89,7 +89,11 @@ get_primitive_type() const {
|
|||||||
int GeomLinestrips::
|
int GeomLinestrips::
|
||||||
get_geom_rendering() const {
|
get_geom_rendering() const {
|
||||||
if (is_indexed()) {
|
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 {
|
} else {
|
||||||
return GR_line_strip;
|
return GR_line_strip;
|
||||||
}
|
}
|
||||||
@ -106,6 +110,20 @@ get_min_num_vertices_per_primitive() const {
|
|||||||
return 2;
|
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
|
// Function: GeomLinestrips::draw
|
||||||
// Access: Public, Virtual
|
// Access: Public, Virtual
|
||||||
@ -138,9 +156,13 @@ decompose_impl() const {
|
|||||||
lines->set_shade_model(get_shade_model());
|
lines->set_shade_model(get_shade_model());
|
||||||
CPTA_int ends = get_ends();
|
CPTA_int ends = get_ends();
|
||||||
|
|
||||||
int vi = 0;
|
int num_unused = get_num_unused_vertices_per_primitive();
|
||||||
|
|
||||||
|
int vi = -num_unused;
|
||||||
int li = 0;
|
int li = 0;
|
||||||
while (li < (int)ends.size()) {
|
while (li < (int)ends.size()) {
|
||||||
|
// Skip unused vertices between tristrips.
|
||||||
|
vi += num_unused;
|
||||||
int end = ends[li];
|
int end = ends[li];
|
||||||
nassertr(vi + 1 <= end, lines.p());
|
nassertr(vi + 1 <= end, lines.p());
|
||||||
int v0 = get_vertex(vi);
|
int v0 = get_vertex(vi);
|
||||||
@ -210,6 +232,33 @@ rotate_impl() const {
|
|||||||
return new_vertices;
|
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
|
// Function: GeomLinestrips::register_with_read_factory
|
||||||
// Access: Public, Static
|
// Access: Public, Static
|
||||||
|
@ -34,6 +34,7 @@ public:
|
|||||||
virtual PrimitiveType get_primitive_type() const;
|
virtual PrimitiveType get_primitive_type() const;
|
||||||
virtual int get_geom_rendering() const;
|
virtual int get_geom_rendering() const;
|
||||||
virtual int get_min_num_vertices_per_primitive() const;
|
virtual int get_min_num_vertices_per_primitive() const;
|
||||||
|
virtual int get_num_unused_vertices_per_primitive() const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual bool draw(GraphicsStateGuardianBase *gsg,
|
virtual bool draw(GraphicsStateGuardianBase *gsg,
|
||||||
@ -43,6 +44,9 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
virtual CPT(GeomPrimitive) decompose_impl() const;
|
virtual CPT(GeomPrimitive) decompose_impl() const;
|
||||||
virtual CPT(GeomVertexArrayData) rotate_impl() const;
|
virtual CPT(GeomVertexArrayData) rotate_impl() const;
|
||||||
|
virtual bool requires_unused_vertices() const;
|
||||||
|
virtual void append_unused_vertices(GeomVertexArrayData *vertices,
|
||||||
|
int vertex);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static void register_with_read_factory();
|
static void register_with_read_factory();
|
||||||
|
@ -129,7 +129,7 @@ get_first_vertex() const {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: GeomPrimitive::get_num_vertices
|
// Function: GeomPrimitive::get_num_vertices
|
||||||
// Access: Published
|
// 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.
|
// primitives in this object.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
INLINE int GeomPrimitive::
|
INLINE int GeomPrimitive::
|
||||||
@ -310,6 +310,20 @@ get_index_stride() const {
|
|||||||
return reader.get_index_stride();
|
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
|
// Function: GeomPrimitive::get_ends
|
||||||
// Access: Published
|
// Access: Published
|
||||||
@ -679,6 +693,16 @@ get_read_pointer(bool force) const {
|
|||||||
return _vertices_reader->get_read_pointer(force);
|
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
|
// Function: GeomPrimitivePipelineReader::get_ends
|
||||||
// Access: Public
|
// Access: Public
|
||||||
|
@ -61,18 +61,18 @@ make_cow_copy() {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: GeomPrimitive::Constructor
|
// Function: GeomPrimitive::Constructor
|
||||||
// Access: Published
|
// Access: Published
|
||||||
// Description:
|
// Description:
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
GeomPrimitive::
|
GeomPrimitive::
|
||||||
GeomPrimitive(GeomPrimitive::UsageHint usage_hint) {
|
GeomPrimitive(GeomPrimitive::UsageHint usage_hint) {
|
||||||
CDWriter cdata(_cycler, true);
|
CDWriter cdata(_cycler, true);
|
||||||
cdata->_usage_hint = usage_hint;
|
cdata->_usage_hint = usage_hint;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: GeomPrimitive::Copy Constructor
|
// Function: GeomPrimitive::Copy Constructor
|
||||||
// Access: Published
|
// Access: Published
|
||||||
// Description:
|
// Description:
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
GeomPrimitive::
|
GeomPrimitive::
|
||||||
GeomPrimitive(const GeomPrimitive ©) :
|
GeomPrimitive(const GeomPrimitive ©) :
|
||||||
@ -80,7 +80,7 @@ GeomPrimitive(const GeomPrimitive ©) :
|
|||||||
_cycler(copy._cycler)
|
_cycler(copy._cycler)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: GeomPrimitive::Copy Assignment Operator
|
// Function: GeomPrimitive::Copy Assignment Operator
|
||||||
// Access: Published
|
// Access: Published
|
||||||
@ -98,7 +98,7 @@ operator = (const GeomPrimitive ©) {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: GeomPrimitive::Destructor
|
// Function: GeomPrimitive::Destructor
|
||||||
// Access: Published, Virtual
|
// Access: Published, Virtual
|
||||||
// Description:
|
// Description:
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
GeomPrimitive::
|
GeomPrimitive::
|
||||||
~GeomPrimitive() {
|
~GeomPrimitive() {
|
||||||
@ -197,7 +197,7 @@ add_vertex(int vertex) {
|
|||||||
|
|
||||||
int num_primitives = get_num_primitives();
|
int num_primitives = get_num_primitives();
|
||||||
if (num_primitives > 0 &&
|
if (num_primitives > 0 &&
|
||||||
requires_unused_vertices() &&
|
requires_unused_vertices() &&
|
||||||
get_num_vertices() == get_primitive_end(num_primitives - 1)) {
|
get_num_vertices() == get_primitive_end(num_primitives - 1)) {
|
||||||
// If we are beginning a new primitive, give the derived class a
|
// If we are beginning a new primitive, give the derived class a
|
||||||
// chance to insert some degenerate vertices.
|
// chance to insert some degenerate vertices.
|
||||||
@ -224,7 +224,7 @@ add_vertex(int vertex) {
|
|||||||
cdata->_got_minmax = false;
|
cdata->_got_minmax = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, we need to suddenly become an indexed primitive.
|
// Otherwise, we need to suddenly become an indexed primitive.
|
||||||
do_make_indexed(cdata);
|
do_make_indexed(cdata);
|
||||||
}
|
}
|
||||||
@ -288,7 +288,7 @@ add_consecutive_vertices(int start, int num_vertices) {
|
|||||||
cdata->_got_minmax = false;
|
cdata->_got_minmax = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, we need to suddenly become an indexed primitive.
|
// Otherwise, we need to suddenly become an indexed primitive.
|
||||||
do_make_indexed(cdata);
|
do_make_indexed(cdata);
|
||||||
}
|
}
|
||||||
@ -468,12 +468,18 @@ offset_vertices(int offset) {
|
|||||||
recompute_minmax(cdata);
|
recompute_minmax(cdata);
|
||||||
nassertv(cdata->_got_minmax);
|
nassertv(cdata->_got_minmax);
|
||||||
}
|
}
|
||||||
|
|
||||||
consider_elevate_index_type(cdata, cdata->_max_vertex + 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);
|
GeomVertexRewriter index(do_modify_vertices(cdata), 0);
|
||||||
while (!index.is_at_end()) {
|
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 {
|
} else {
|
||||||
@ -483,7 +489,7 @@ offset_vertices(int offset) {
|
|||||||
cdata->_modified = Geom::get_next_modified();
|
cdata->_modified = Geom::get_next_modified();
|
||||||
cdata->_got_minmax = false;
|
cdata->_got_minmax = false;
|
||||||
|
|
||||||
consider_elevate_index_type(cdata,
|
consider_elevate_index_type(cdata,
|
||||||
cdata->_first_vertex + cdata->_num_vertices - 1);
|
cdata->_first_vertex + cdata->_num_vertices - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -516,14 +522,19 @@ offset_vertices(int offset, int begin_row, int end_row) {
|
|||||||
|
|
||||||
if (is_indexed()) {
|
if (is_indexed()) {
|
||||||
CDWriter cdata(_cycler, true);
|
CDWriter cdata(_cycler, true);
|
||||||
|
|
||||||
|
int strip_cut_index = get_strip_cut_index(cdata->_index_type);
|
||||||
|
|
||||||
// Calculate the maximum vertex over our range.
|
// Calculate the maximum vertex over our range.
|
||||||
int max_vertex = 0;
|
int max_vertex = 0;
|
||||||
{
|
{
|
||||||
GeomVertexReader index_r(cdata->_vertices.get_read_pointer(), 0);
|
GeomVertexReader index_r(cdata->_vertices.get_read_pointer(), 0);
|
||||||
index_r.set_row_unsafe(begin_row);
|
index_r.set_row_unsafe(begin_row);
|
||||||
for (int j = begin_row; j < end_row; ++j) {
|
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);
|
GeomVertexRewriter index(do_modify_vertices(cdata), 0);
|
||||||
index.set_row_unsafe(begin_row);
|
index.set_row_unsafe(begin_row);
|
||||||
for (int j = begin_row; j < end_row; ++j) {
|
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 {
|
} else {
|
||||||
@ -544,7 +558,7 @@ offset_vertices(int offset, int begin_row, int end_row) {
|
|||||||
cdata->_modified = Geom::get_next_modified();
|
cdata->_modified = Geom::get_next_modified();
|
||||||
cdata->_got_minmax = false;
|
cdata->_got_minmax = false;
|
||||||
|
|
||||||
consider_elevate_index_type(cdata,
|
consider_elevate_index_type(cdata,
|
||||||
cdata->_first_vertex + cdata->_num_vertices - 1);
|
cdata->_first_vertex + cdata->_num_vertices - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -554,17 +568,20 @@ offset_vertices(int offset, int begin_row, int end_row) {
|
|||||||
// Access: Published
|
// Access: Published
|
||||||
// Description: Converts the primitive from indexed to nonindexed by
|
// Description: Converts the primitive from indexed to nonindexed by
|
||||||
// duplicating vertices as necessary into the indicated
|
// duplicating vertices as necessary into the indicated
|
||||||
// dest GeomVertexData.
|
// dest GeomVertexData. Note: does not support
|
||||||
|
// primitives with strip cut indices.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void GeomPrimitive::
|
void GeomPrimitive::
|
||||||
make_nonindexed(GeomVertexData *dest, const GeomVertexData *source) {
|
make_nonindexed(GeomVertexData *dest, const GeomVertexData *source) {
|
||||||
Thread *current_thread = Thread::get_current_thread();
|
Thread *current_thread = Thread::get_current_thread();
|
||||||
int num_vertices = get_num_vertices();
|
int num_vertices = get_num_vertices();
|
||||||
int dest_start = dest->get_num_rows();
|
int dest_start = dest->get_num_rows();
|
||||||
|
int strip_cut_index = get_strip_cut_index();
|
||||||
|
|
||||||
dest->set_num_rows(dest_start + num_vertices);
|
dest->set_num_rows(dest_start + num_vertices);
|
||||||
for (int i = 0; i < num_vertices; ++i) {
|
for (int i = 0; i < num_vertices; ++i) {
|
||||||
int v = get_vertex(i);
|
int v = get_vertex(i);
|
||||||
|
nassertd(v != strip_cut_index) continue;
|
||||||
dest->copy_row_from(dest_start + i, source, v, current_thread);
|
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 num_vertices = get_num_vertices();
|
||||||
int dest_start = dest->get_num_rows();
|
int dest_start = dest->get_num_rows();
|
||||||
|
int strip_cut_index = get_strip_cut_index();
|
||||||
|
|
||||||
for (int i = 0; i < num_vertices; ++i) {
|
for (int i = 0; i < num_vertices; ++i) {
|
||||||
int v = get_vertex(i);
|
int v = get_vertex(i);
|
||||||
|
if (v == strip_cut_index) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Try to add the relation { v : size() }. If that succeeds,
|
// Try to add the relation { v : size() }. If that succeeds,
|
||||||
// great; if it doesn't, look up whatever we previously added
|
// great; if it doesn't, look up whatever we previously added
|
||||||
// for v.
|
// for v.
|
||||||
pair<CopiedIndices::iterator, bool> result =
|
pair<CopiedIndices::iterator, bool> result =
|
||||||
copied_indices.insert(CopiedIndices::value_type(v, (int)copied_indices.size()));
|
copied_indices.insert(CopiedIndices::value_type(v, (int)copied_indices.size()));
|
||||||
int v2 = (*result.first).second + dest_start;
|
int v2 = (*result.first).second + dest_start;
|
||||||
index.add_data1i(v2);
|
index.add_data1i(v2);
|
||||||
@ -613,7 +634,7 @@ pack_vertices(GeomVertexData *dest, const GeomVertexData *source) {
|
|||||||
dest->copy_row_from(v2, source, v, current_thread);
|
dest->copy_row_from(v2, source, v, current_thread);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
set_vertices(new_vertices);
|
set_vertices(new_vertices);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -643,7 +664,7 @@ make_indexed() {
|
|||||||
// Function: GeomPrimitive::get_primitive_start
|
// Function: GeomPrimitive::get_primitive_start
|
||||||
// Access: Published
|
// Access: Published
|
||||||
// Description: Returns the element within the _vertices list at which
|
// 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
|
// If i is one more than the highest valid primitive
|
||||||
// vertex, the return value will be one more than the
|
// vertex, the return value will be one more than the
|
||||||
@ -723,7 +744,7 @@ get_primitive_num_vertices(int n) const {
|
|||||||
} else {
|
} else {
|
||||||
int num_unused_vertices_per_primitive = get_num_unused_vertices_per_primitive();
|
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;
|
return cdata->_ends[n] - cdata->_ends[n - 1] - num_unused_vertices_per_primitive;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// This is a simple primitive type like a triangle: each primitive
|
// 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
|
// Function: GeomPrimitive::get_primitive_min_vertex
|
||||||
// Access: Published
|
// Access: Published
|
||||||
@ -959,10 +1002,14 @@ make_points() const {
|
|||||||
int num_vertices = get_num_vertices();
|
int num_vertices = get_num_vertices();
|
||||||
if (is_indexed()) {
|
if (is_indexed()) {
|
||||||
CPT(GeomVertexArrayData) vertices = get_vertices();
|
CPT(GeomVertexArrayData) vertices = get_vertices();
|
||||||
|
int strip_cut_index = get_strip_cut_index();
|
||||||
GeomVertexReader index(vertices, 0);
|
GeomVertexReader index(vertices, 0);
|
||||||
for (int vi = 0; vi < num_vertices; ++vi) {
|
for (int vi = 0; vi < num_vertices; ++vi) {
|
||||||
nassertr(!index.is_at_end(), NULL);
|
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 {
|
} else {
|
||||||
int first_vertex = get_first_vertex();
|
int first_vertex = get_first_vertex();
|
||||||
@ -996,14 +1043,13 @@ make_points() const {
|
|||||||
// Access: Published
|
// Access: Published
|
||||||
// Description: Decomposes a complex primitive type into a simpler
|
// Description: Decomposes a complex primitive type into a simpler
|
||||||
// primitive type, for instance triangle strips to
|
// 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
|
// definition. If the decomposition cannot be
|
||||||
// performed, this might return the original object.
|
// performed, this might return the original object.
|
||||||
//
|
//
|
||||||
// This method is useful for application code that wants
|
// This method is useful for application code that wants
|
||||||
// to iterate through the set of triangles on the
|
// to use tesselation shaders on arbitrary geometry.
|
||||||
// primitive without having to write handlers for each
|
|
||||||
// possible kind of primitive type.
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
CPT(GeomPrimitive) GeomPrimitive::
|
CPT(GeomPrimitive) GeomPrimitive::
|
||||||
make_patches() const {
|
make_patches() const {
|
||||||
@ -1079,7 +1125,7 @@ request_resident() const {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: GeomPrimitive::output
|
// Function: GeomPrimitive::output
|
||||||
// Access: Published, Virtual
|
// Access: Published, Virtual
|
||||||
// Description:
|
// Description:
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void GeomPrimitive::
|
void GeomPrimitive::
|
||||||
output(ostream &out) const {
|
output(ostream &out) const {
|
||||||
@ -1090,7 +1136,7 @@ output(ostream &out) const {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: GeomPrimitive::write
|
// Function: GeomPrimitive::write
|
||||||
// Access: Published, Virtual
|
// Access: Published, Virtual
|
||||||
// Description:
|
// Description:
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void GeomPrimitive::
|
void GeomPrimitive::
|
||||||
write(ostream &out, int indent_level) const {
|
write(ostream &out, int indent_level) const {
|
||||||
@ -1448,7 +1494,7 @@ is_prepared(PreparedGraphicsObjects *prepared_objects) const {
|
|||||||
// rendered.
|
// rendered.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
IndexBufferContext *GeomPrimitive::
|
IndexBufferContext *GeomPrimitive::
|
||||||
prepare_now(PreparedGraphicsObjects *prepared_objects,
|
prepare_now(PreparedGraphicsObjects *prepared_objects,
|
||||||
GraphicsStateGuardianBase *gsg) {
|
GraphicsStateGuardianBase *gsg) {
|
||||||
nassertr(is_indexed(), NULL);
|
nassertr(is_indexed(), NULL);
|
||||||
|
|
||||||
@ -1558,11 +1604,44 @@ clear_prepared(PreparedGraphicsObjects *prepared_objects) {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: GeomPrimitive::get_highest_index_value
|
// Function: GeomPrimitive::get_highest_index_value
|
||||||
// Access: Private, Static
|
// Access: Private, Static
|
||||||
// Description: Returns the largest index value that can be stored in
|
// Description: Returns the largest index value that can be stored
|
||||||
// an index of the indicated type.
|
// in an index of the indicated type, minus one (to
|
||||||
|
// leave room for a potential strip cut index)
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
int GeomPrimitive::
|
int GeomPrimitive::
|
||||||
get_highest_index_value(NumericType index_type) {
|
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) {
|
switch (index_type) {
|
||||||
case NT_uint8:
|
case NT_uint8:
|
||||||
return 0xff;
|
return 0xff;
|
||||||
@ -1571,12 +1650,8 @@ get_highest_index_value(NumericType index_type) {
|
|||||||
return 0xffff;
|
return 0xffff;
|
||||||
|
|
||||||
case NT_uint32:
|
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:
|
default:
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1593,7 +1668,7 @@ get_highest_index_value(NumericType index_type) {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void GeomPrimitive::
|
void GeomPrimitive::
|
||||||
calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
|
calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
|
||||||
bool &found_any,
|
bool &found_any,
|
||||||
const GeomVertexData *vertex_data,
|
const GeomVertexData *vertex_data,
|
||||||
bool got_mat, const LMatrix4 &mat,
|
bool got_mat, const LMatrix4 &mat,
|
||||||
const InternalName *column_name,
|
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++) {
|
for (int i = 0; i < cdata->_num_vertices; i++) {
|
||||||
reader.set_row_unsafe(cdata->_first_vertex + i);
|
reader.set_row_unsafe(cdata->_first_vertex + i);
|
||||||
LPoint3 vertex = mat.xform_point(reader.get_data3());
|
LPoint3 vertex = mat.xform_point(reader.get_data3());
|
||||||
|
|
||||||
if (found_any) {
|
if (found_any) {
|
||||||
min_point.set(min(min_point[0], vertex[0]),
|
min_point.set(min(min_point[0], vertex[0]),
|
||||||
min(min_point[1], vertex[1]),
|
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++) {
|
for (int i = 0; i < cdata->_num_vertices; i++) {
|
||||||
reader.set_row_unsafe(cdata->_first_vertex + i);
|
reader.set_row_unsafe(cdata->_first_vertex + i);
|
||||||
const LVecBase3 &vertex = reader.get_data3();
|
const LVecBase3 &vertex = reader.get_data3();
|
||||||
|
|
||||||
if (found_any) {
|
if (found_any) {
|
||||||
min_point.set(min(min_point[0], vertex[0]),
|
min_point.set(min(min_point[0], vertex[0]),
|
||||||
min(min_point[1], vertex[1]),
|
min(min_point[1], vertex[1]),
|
||||||
@ -1650,13 +1725,17 @@ calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
|
|||||||
} else {
|
} else {
|
||||||
// Indexed case.
|
// Indexed case.
|
||||||
GeomVertexReader index(cdata->_vertices.get_read_pointer(), 0, current_thread);
|
GeomVertexReader index(cdata->_vertices.get_read_pointer(), 0, current_thread);
|
||||||
|
int strip_cut_index = get_strip_cut_index(cdata->_index_type);
|
||||||
|
|
||||||
if (got_mat) {
|
if (got_mat) {
|
||||||
while (!index.is_at_end()) {
|
while (!index.is_at_end()) {
|
||||||
int ii = index.get_data1i();
|
int ii = index.get_data1i();
|
||||||
|
if (ii == strip_cut_index) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
reader.set_row_unsafe(ii);
|
reader.set_row_unsafe(ii);
|
||||||
LPoint3 vertex = mat.xform_point(reader.get_data3());
|
LPoint3 vertex = mat.xform_point(reader.get_data3());
|
||||||
|
|
||||||
if (found_any) {
|
if (found_any) {
|
||||||
min_point.set(min(min_point[0], vertex[0]),
|
min_point.set(min(min_point[0], vertex[0]),
|
||||||
min(min_point[1], vertex[1]),
|
min(min_point[1], vertex[1]),
|
||||||
@ -1673,9 +1752,12 @@ calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
|
|||||||
} else {
|
} else {
|
||||||
while (!index.is_at_end()) {
|
while (!index.is_at_end()) {
|
||||||
int ii = index.get_data1i();
|
int ii = index.get_data1i();
|
||||||
|
if (ii == strip_cut_index) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
reader.set_row_unsafe(ii);
|
reader.set_row_unsafe(ii);
|
||||||
const LVecBase3 &vertex = reader.get_data3();
|
const LVecBase3 &vertex = reader.get_data3();
|
||||||
|
|
||||||
if (found_any) {
|
if (found_any) {
|
||||||
min_point.set(min(min_point[0], vertex[0]),
|
min_point.set(min(min_point[0], vertex[0]),
|
||||||
min(min_point[1], vertex[1]),
|
min(min_point[1], vertex[1]),
|
||||||
@ -1797,63 +1879,77 @@ recompute_minmax(GeomPrimitive::CData *cdata) {
|
|||||||
cdata->_max_vertex = 0;
|
cdata->_max_vertex = 0;
|
||||||
cdata->_mins.clear();
|
cdata->_mins.clear();
|
||||||
cdata->_maxs.clear();
|
cdata->_maxs.clear();
|
||||||
|
|
||||||
} else if (get_num_vertices_per_primitive() == 0) {
|
} else if (get_num_vertices_per_primitive() == 0) {
|
||||||
// This is a complex primitive type like a triangle strip; compute
|
// This is a complex primitive type like a triangle strip; compute
|
||||||
// the minmax of each primitive (as well as the overall minmax).
|
// the minmax of each primitive (as well as the overall minmax).
|
||||||
GeomVertexReader index(cdata->_vertices.get_read_pointer(), 0);
|
GeomVertexReader index(cdata->_vertices.get_read_pointer(), 0);
|
||||||
|
|
||||||
cdata->_mins = make_index_data();
|
cdata->_mins = make_index_data();
|
||||||
cdata->_maxs = make_index_data();
|
cdata->_maxs = make_index_data();
|
||||||
|
|
||||||
GeomVertexWriter mins(cdata->_mins.get_write_pointer(), 0);
|
GeomVertexWriter mins(cdata->_mins.get_write_pointer(), 0);
|
||||||
mins.reserve_num_rows(cdata->_ends.size());
|
mins.reserve_num_rows(cdata->_ends.size());
|
||||||
GeomVertexWriter maxs(cdata->_maxs.get_write_pointer(), 0);
|
GeomVertexWriter maxs(cdata->_maxs.get_write_pointer(), 0);
|
||||||
maxs.reserve_num_rows(cdata->_ends.size());
|
maxs.reserve_num_rows(cdata->_ends.size());
|
||||||
|
|
||||||
int pi = 0;
|
int pi = 0;
|
||||||
|
|
||||||
unsigned int vertex = index.get_data1i();
|
unsigned int vertex = index.get_data1i();
|
||||||
cdata->_min_vertex = vertex;
|
cdata->_min_vertex = vertex;
|
||||||
cdata->_max_vertex = vertex;
|
cdata->_max_vertex = vertex;
|
||||||
unsigned int min_prim = vertex;
|
unsigned int min_prim = vertex;
|
||||||
unsigned int max_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) {
|
for (int vi = 1; vi < num_vertices; ++vi) {
|
||||||
nassertv(!index.is_at_end());
|
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());
|
nassertv(pi < (int)cdata->_ends.size());
|
||||||
|
|
||||||
|
unsigned int vertex;
|
||||||
|
|
||||||
if (vi == cdata->_ends[pi]) {
|
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);
|
mins.add_data1i(min_prim);
|
||||||
maxs.add_data1i(max_prim);
|
maxs.add_data1i(max_prim);
|
||||||
min_prim = vertex;
|
min_prim = vertex;
|
||||||
max_prim = vertex;
|
max_prim = vertex;
|
||||||
++pi;
|
++pi;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
vertex = index.get_data1i();
|
||||||
min_prim = min(min_prim, vertex);
|
min_prim = min(min_prim, vertex);
|
||||||
max_prim = max(max_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);
|
mins.add_data1i(min_prim);
|
||||||
maxs.add_data1i(max_prim);
|
maxs.add_data1i(max_prim);
|
||||||
nassertv(mins.get_array_data()->get_num_rows() == (int)cdata->_ends.size());
|
nassertv(mins.get_array_data()->get_num_rows() == (int)cdata->_ends.size());
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// This is a simple primitive type like a triangle; just compute
|
// This is a simple primitive type like a triangle; just compute
|
||||||
// the overall minmax.
|
// the overall minmax.
|
||||||
GeomVertexReader index(cdata->_vertices.get_read_pointer(), 0);
|
GeomVertexReader index(cdata->_vertices.get_read_pointer(), 0);
|
||||||
|
|
||||||
cdata->_mins.clear();
|
cdata->_mins.clear();
|
||||||
cdata->_maxs.clear();
|
cdata->_maxs.clear();
|
||||||
|
|
||||||
unsigned int vertex = index.get_data1i();
|
unsigned int vertex = index.get_data1i();
|
||||||
cdata->_min_vertex = vertex;
|
cdata->_min_vertex = vertex;
|
||||||
cdata->_max_vertex = vertex;
|
cdata->_max_vertex = vertex;
|
||||||
|
|
||||||
for (int vi = 1; vi < num_vertices; ++vi) {
|
for (int vi = 1; vi < num_vertices; ++vi) {
|
||||||
nassertv(!index.is_at_end());
|
nassertv(!index.is_at_end());
|
||||||
unsigned int vertex = index.get_data1i();
|
unsigned int vertex = index.get_data1i();
|
||||||
@ -1862,7 +1958,7 @@ recompute_minmax(GeomPrimitive::CData *cdata) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cdata->_got_minmax = true;
|
cdata->_got_minmax = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1899,22 +1995,25 @@ do_make_indexed(CData *cdata) {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void GeomPrimitive::
|
void GeomPrimitive::
|
||||||
consider_elevate_index_type(CData *cdata, int vertex) {
|
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) {
|
switch (cdata->_index_type) {
|
||||||
case NT_uint8:
|
case NT_uint8:
|
||||||
if (vertex > 0xff) {
|
if (vertex >= 0xff) {
|
||||||
do_set_index_type(cdata, NT_uint16);
|
do_set_index_type(cdata, NT_uint16);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NT_uint16:
|
case NT_uint16:
|
||||||
if (vertex > 0xffff) {
|
if (vertex >= 0xffff) {
|
||||||
do_set_index_type(cdata, NT_uint32);
|
do_set_index_type(cdata, NT_uint32);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NT_uint32:
|
case NT_uint32:
|
||||||
// Not much we can do here.
|
// Not much we can do here.
|
||||||
nassertv(vertex <= 0x7fffffff);
|
nassertv(vertex < 0x7fffffff);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -1929,6 +2028,9 @@ consider_elevate_index_type(CData *cdata, int vertex) {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void GeomPrimitive::
|
void GeomPrimitive::
|
||||||
do_set_index_type(CData *cdata, GeomPrimitive::NumericType index_type) {
|
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;
|
cdata->_index_type = index_type;
|
||||||
|
|
||||||
if (gobj_cat.is_debug()) {
|
if (gobj_cat.is_debug()) {
|
||||||
@ -1938,7 +2040,7 @@ do_set_index_type(CData *cdata, GeomPrimitive::NumericType index_type) {
|
|||||||
|
|
||||||
if (!cdata->_vertices.is_null()) {
|
if (!cdata->_vertices.is_null()) {
|
||||||
CPT(GeomVertexArrayFormat) new_format = get_index_format();
|
CPT(GeomVertexArrayFormat) new_format = get_index_format();
|
||||||
|
|
||||||
CPT(GeomVertexArrayData) array_obj = cdata->_vertices.get_read_pointer();
|
CPT(GeomVertexArrayData) array_obj = cdata->_vertices.get_read_pointer();
|
||||||
if (array_obj->get_array_format() != new_format) {
|
if (array_obj->get_array_format() != new_format) {
|
||||||
PT(GeomVertexArrayData) new_vertices = make_index_data();
|
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);
|
GeomVertexReader from(array_obj, 0);
|
||||||
GeomVertexWriter to(new_vertices, 0);
|
GeomVertexWriter to(new_vertices, 0);
|
||||||
|
|
||||||
while (!from.is_at_end()) {
|
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->_vertices = new_vertices;
|
||||||
cdata->_got_minmax = false;
|
cdata->_got_minmax = false;
|
||||||
@ -2056,7 +2162,7 @@ int GeomPrimitive::CData::
|
|||||||
complete_pointers(TypedWritable **p_list, BamReader *manager) {
|
complete_pointers(TypedWritable **p_list, BamReader *manager) {
|
||||||
int pi = CycleData::complete_pointers(p_list, 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()) {
|
if (manager->get_file_minor_ver() < 6 && !_vertices.is_null()) {
|
||||||
// Older bam files might have a meaningless number in
|
// Older bam files might have a meaningless number in
|
||||||
@ -2106,7 +2212,7 @@ check_minmax() const {
|
|||||||
#ifdef DO_PIPELINING
|
#ifdef DO_PIPELINING
|
||||||
unref_delete((CycleData *)_cdata);
|
unref_delete((CycleData *)_cdata);
|
||||||
#endif
|
#endif
|
||||||
GeomPrimitive::CDWriter fresh_cdata(((GeomPrimitive *)_object.p())->_cycler,
|
GeomPrimitive::CDWriter fresh_cdata(((GeomPrimitive *)_object.p())->_cycler,
|
||||||
false, _current_thread);
|
false, _current_thread);
|
||||||
((GeomPrimitivePipelineReader *)this)->_cdata = fresh_cdata;
|
((GeomPrimitivePipelineReader *)this)->_cdata = fresh_cdata;
|
||||||
#ifdef DO_PIPELINING
|
#ifdef DO_PIPELINING
|
||||||
@ -2132,7 +2238,7 @@ check_minmax() const {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: GeomPrimitivePipelineReader::get_first_vertex
|
// Function: GeomPrimitivePipelineReader::get_first_vertex
|
||||||
// Access: Public
|
// Access: Public
|
||||||
// Description:
|
// Description:
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
int GeomPrimitivePipelineReader::
|
int GeomPrimitivePipelineReader::
|
||||||
get_first_vertex() const {
|
get_first_vertex() const {
|
||||||
@ -2170,7 +2276,7 @@ get_vertex(int i) const {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: GeomPrimitivePipelineReader::get_num_primitives
|
// Function: GeomPrimitivePipelineReader::get_num_primitives
|
||||||
// Access: Public
|
// Access: Public
|
||||||
// Description:
|
// Description:
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
int GeomPrimitivePipelineReader::
|
int GeomPrimitivePipelineReader::
|
||||||
get_num_primitives() const {
|
get_num_primitives() const {
|
||||||
|
@ -118,6 +118,7 @@ PUBLISHED:
|
|||||||
int get_primitive_start(int n) const;
|
int get_primitive_start(int n) const;
|
||||||
int get_primitive_end(int n) const;
|
int get_primitive_end(int n) const;
|
||||||
int get_primitive_num_vertices(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_num_faces() const;
|
||||||
INLINE int get_primitive_num_faces(int n) 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);
|
void set_nonindexed_vertices(int first_vertex, int num_vertices);
|
||||||
|
|
||||||
INLINE int get_index_stride() const;
|
INLINE int get_index_stride() const;
|
||||||
|
INLINE int get_strip_cut_index() const;
|
||||||
|
|
||||||
INLINE CPTA_int get_ends() const;
|
INLINE CPTA_int get_ends() const;
|
||||||
PTA_int modify_ends();
|
PTA_int modify_ends();
|
||||||
@ -194,6 +196,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
void clear_prepared(PreparedGraphicsObjects *prepared_objects);
|
void clear_prepared(PreparedGraphicsObjects *prepared_objects);
|
||||||
static int get_highest_index_value(NumericType index_type);
|
static int get_highest_index_value(NumericType index_type);
|
||||||
|
static int get_strip_cut_index(NumericType index_type);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual bool draw(GraphicsStateGuardianBase *gsg,
|
virtual bool draw(GraphicsStateGuardianBase *gsg,
|
||||||
@ -358,6 +361,7 @@ public:
|
|||||||
INLINE int get_index_stride() const;
|
INLINE int get_index_stride() const;
|
||||||
INLINE const GeomVertexArrayDataHandle *get_vertices_reader() const;
|
INLINE const GeomVertexArrayDataHandle *get_vertices_reader() const;
|
||||||
INLINE const unsigned char *get_read_pointer(bool force) 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 CPTA_int get_ends() const;
|
||||||
INLINE CPT(GeomVertexArrayData) get_mins() const;
|
INLINE CPT(GeomVertexArrayData) get_mins() const;
|
||||||
INLINE CPT(GeomVertexArrayData) get_maxs() 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
|
// Function: GeomTristrips::get_num_unused_vertices_per_primitive
|
||||||
// Access: Public, Virtual
|
// Access: Public, Virtual
|
||||||
@ -142,6 +153,7 @@ decompose_impl() const {
|
|||||||
CPTA_int ends = get_ends();
|
CPTA_int ends = get_ends();
|
||||||
|
|
||||||
int num_vertices = get_num_vertices();
|
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
|
// We need a slightly different algorithm for SM_flat_first_vertex
|
||||||
// than for SM_flat_last_vertex, to preserve the key vertex in the
|
// 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) {
|
if (get_shade_model() == SM_flat_first_vertex) {
|
||||||
// Preserve the first vertex of each component triangle as the
|
// Preserve the first vertex of each component triangle as the
|
||||||
// first vertex of each generated triangle.
|
// first vertex of each generated triangle.
|
||||||
int vi = -2;
|
int vi = -num_unused;
|
||||||
int li = 0;
|
int li = 0;
|
||||||
while (li < (int)ends.size()) {
|
while (li < (int)ends.size()) {
|
||||||
// Skip unused vertices between tristrips.
|
// Skip unused vertices between tristrips.
|
||||||
vi += 2;
|
vi += num_unused;
|
||||||
int end = ends[li];
|
int end = ends[li];
|
||||||
nassertr(vi + 2 <= end, NULL);
|
nassertr(vi + 2 <= end, NULL);
|
||||||
int v0 = get_vertex(vi);
|
int v0 = get_vertex(vi);
|
||||||
@ -192,11 +204,11 @@ decompose_impl() const {
|
|||||||
} else {
|
} else {
|
||||||
// Preserve the last vertex of each component triangle as the
|
// Preserve the last vertex of each component triangle as the
|
||||||
// last vertex of each generated triangle.
|
// last vertex of each generated triangle.
|
||||||
int vi = -2;
|
int vi = -num_unused;
|
||||||
int li = 0;
|
int li = 0;
|
||||||
while (li < (int)ends.size()) {
|
while (li < (int)ends.size()) {
|
||||||
// Skip unused vertices between tristrips.
|
// Skip unused vertices between tristrips.
|
||||||
vi += 2;
|
vi += num_unused;
|
||||||
int end = ends[li];
|
int end = ends[li];
|
||||||
nassertr(vi + 2 <= end, NULL);
|
nassertr(vi + 2 <= end, NULL);
|
||||||
int v0 = get_vertex(vi);
|
int v0 = get_vertex(vi);
|
||||||
|
@ -33,6 +33,7 @@ public:
|
|||||||
virtual PT(GeomPrimitive) make_copy() const;
|
virtual PT(GeomPrimitive) make_copy() const;
|
||||||
virtual PrimitiveType get_primitive_type() const;
|
virtual PrimitiveType get_primitive_type() const;
|
||||||
virtual int get_geom_rendering() 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;
|
virtual int get_num_unused_vertices_per_primitive() const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user