diff --git a/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx b/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx index 2a228620b7..187b232948 100644 --- a/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx +++ b/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx @@ -2711,6 +2711,7 @@ begin_draw_primitives(const qpGeom *geom, const qpGeomMunger *munger, //////////////////////////////////////////////////////////////////// void DXGraphicsStateGuardian8:: draw_triangles(const qpGeomTriangles *primitive) { + _vertices_tri_pcollector.add_level(primitive->get_num_vertices()); if (_vbuffer_active) { IndexBufferContext *ibc = ((qpGeomPrimitive *)primitive)->prepare_now(get_prepared_objects(), this); nassertv(ibc != (IndexBufferContext *)NULL); @@ -2744,41 +2745,75 @@ void DXGraphicsStateGuardian8:: draw_tristrips(const qpGeomTristrips *primitive) { int min_vertex = primitive->get_min_vertex(); int max_vertex = primitive->get_max_vertex(); - CPTA_ushort vertices = primitive->get_flat_first_vertices(); - CPTA_int ends = primitive->get_ends(); - CPTA_ushort mins = primitive->get_mins(); - CPTA_ushort maxs = primitive->get_maxs(); - nassertv(mins.size() == ends.size() && maxs.size() == ends.size()); + // CPTA_ushort vertices = primitive->get_flat_first_vertices(); + CPTA_ushort vertices = primitive->get_vertices(); - if (_vbuffer_active) { - IndexBufferContext *ibc = ((qpGeomPrimitive *)primitive)->prepare_now(get_prepared_objects(), this); - nassertv(ibc != (IndexBufferContext *)NULL); - apply_index_buffer(ibc); + if (connect_triangle_strips && _current_fill_mode != RenderModeAttrib::M_wireframe) { + // One long triangle strip, connected by the degenerate vertices + // that have already been set up within the primitive. + _vertices_tristrip_pcollector.add_level(primitive->get_num_vertices()); + if (_vbuffer_active) { + IndexBufferContext *ibc = ((qpGeomPrimitive *)primitive)->prepare_now(get_prepared_objects(), this); + nassertv(ibc != (IndexBufferContext *)NULL); + apply_index_buffer(ibc); - unsigned int start = 0; - for (size_t i = 0; i < ends.size(); i++) { _pD3DDevice->DrawIndexedPrimitive (D3DPT_TRIANGLESTRIP, - mins[i], maxs[i] - mins[i] + 1, - start, ends[i] - start - 2); - - start = ends[i]; + primitive->get_min_vertex(), + primitive->get_max_vertex() - primitive->get_min_vertex() + 1, + 0, primitive->get_num_vertices() - 2); + + } else { + _pD3DDevice->DrawIndexedPrimitiveUP + (D3DPT_TRIANGLESTRIP, + primitive->get_min_vertex(), + primitive->get_max_vertex() - primitive->get_min_vertex() + 1, + primitive->get_num_vertices() - 2, + vertices, D3DFMT_INDEX16, + _vertex_data->get_array(0)->get_data(), + _vertex_data->get_format()->get_array(0)->get_stride()); } } else { - CPTA_uchar array_data = _vertex_data->get_array(0)->get_data(); - int stride = _vertex_data->get_format()->get_array(0)->get_stride(); - - unsigned int start = 0; - for (size_t i = 0; i < ends.size(); i++) { - _pD3DDevice->DrawIndexedPrimitiveUP - (D3DPT_TRIANGLESTRIP, - mins[i], maxs[i] - mins[i] + 1, - ends[i] - start - 2, - vertices + start, D3DFMT_INDEX16, - array_data, stride); + // Send the individual triangle strips, stepping over the + // degenerate vertices. + CPTA_int ends = primitive->get_ends(); + CPTA_ushort mins = primitive->get_mins(); + CPTA_ushort maxs = primitive->get_maxs(); + nassertv(mins.size() == ends.size() && maxs.size() == ends.size()); + + if (_vbuffer_active) { + IndexBufferContext *ibc = ((qpGeomPrimitive *)primitive)->prepare_now(get_prepared_objects(), this); + nassertv(ibc != (IndexBufferContext *)NULL); + apply_index_buffer(ibc); - start = ends[i]; + unsigned int start = 0; + for (size_t i = 0; i < ends.size(); i++) { + _vertices_tristrip_pcollector.add_level(ends[i] - start); + _pD3DDevice->DrawIndexedPrimitive + (D3DPT_TRIANGLESTRIP, + mins[i], maxs[i] - mins[i] + 1, + start, ends[i] - start - 2); + + start = ends[i] + 2; + } + + } else { + CPTA_uchar array_data = _vertex_data->get_array(0)->get_data(); + int stride = _vertex_data->get_format()->get_array(0)->get_stride(); + + unsigned int start = 0; + for (size_t i = 0; i < ends.size(); i++) { + _vertices_tristrip_pcollector.add_level(ends[i] - start); + _pD3DDevice->DrawIndexedPrimitiveUP + (D3DPT_TRIANGLESTRIP, + mins[i], maxs[i] - mins[i] + 1, + ends[i] - start - 2, + vertices + start, D3DFMT_INDEX16, + array_data, stride); + + start = ends[i] + 2; + } } } } diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index f852899827..013b384778 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -2247,22 +2247,36 @@ draw_triangles(const qpGeomTriangles *primitive) { //////////////////////////////////////////////////////////////////// void CLP(GraphicsStateGuardian):: draw_tristrips(const qpGeomTristrips *primitive) { - _vertices_tristrip_pcollector.add_level(primitive->get_num_vertices()); const unsigned short *client_pointer = setup_primitive(primitive); - CPTA_int ends = primitive->get_ends(); - CPTA_ushort mins = primitive->get_mins(); - CPTA_ushort maxs = primitive->get_maxs(); - nassertv(mins.size() == ends.size() && maxs.size() == ends.size()); - - unsigned int start = 0; - for (size_t i = 0; i < ends.size(); i++) { + if (connect_triangle_strips && _render_mode != RenderModeAttrib::M_wireframe) { + // One long triangle strip, connected by the degenerate vertices + // that have already been set up within the primitive. + _vertices_tristrip_pcollector.add_level(primitive->get_num_vertices()); _glDrawRangeElements(GL_TRIANGLE_STRIP, - mins[i], maxs[i], ends[i] - start, - GL_UNSIGNED_SHORT, client_pointer + start); - start = ends[i]; - } + primitive->get_min_vertex(), + primitive->get_max_vertex(), + primitive->get_num_vertices(), + GL_UNSIGNED_SHORT, client_pointer); + } else { + // Send the individual triangle strips, stepping over the + // degenerate vertices. + CPTA_int ends = primitive->get_ends(); + CPTA_ushort mins = primitive->get_mins(); + CPTA_ushort maxs = primitive->get_maxs(); + nassertv(mins.size() == ends.size() && maxs.size() == ends.size()); + + unsigned int start = 0; + for (size_t i = 0; i < ends.size(); i++) { + _vertices_tristrip_pcollector.add_level(ends[i] - start); + _glDrawRangeElements(GL_TRIANGLE_STRIP, + mins[i], maxs[i], ends[i] - start, + GL_UNSIGNED_SHORT, client_pointer + start); + start = ends[i] + 2; + } + } + report_my_gl_errors(); } @@ -2273,7 +2287,7 @@ draw_tristrips(const qpGeomTristrips *primitive) { //////////////////////////////////////////////////////////////////// void CLP(GraphicsStateGuardian):: draw_lines(const qpGeomLines *primitive) { - _vertices_tri_pcollector.add_level(primitive->get_num_vertices()); + _vertices_other_pcollector.add_level(primitive->get_num_vertices()); const unsigned short *client_pointer = setup_primitive(primitive); _glDrawRangeElements(GL_LINES, @@ -2292,7 +2306,7 @@ draw_lines(const qpGeomLines *primitive) { //////////////////////////////////////////////////////////////////// void CLP(GraphicsStateGuardian):: draw_points(const qpGeomPoints *primitive) { - _vertices_tri_pcollector.add_level(primitive->get_num_vertices()); + _vertices_other_pcollector.add_level(primitive->get_num_vertices()); const unsigned short *client_pointer = setup_primitive(primitive); _glDrawRangeElements(GL_POINTS, diff --git a/panda/src/gobj/config_gobj.cxx b/panda/src/gobj/config_gobj.cxx index 31a62a7f05..f0d3dd9b80 100644 --- a/panda/src/gobj/config_gobj.cxx +++ b/panda/src/gobj/config_gobj.cxx @@ -142,6 +142,15 @@ ConfigVariableBool matrix_palette "because its support seems to be buggy in certain drivers " "(ATI FireGL T2 8.103 in particular.)")); +ConfigVariableBool connect_triangle_strips +("connect-triangle-strips", true, + PRC_DESC("Set this true to set a batch of triangle strips to the graphics " + "card as one long triangle strip, connected by degenerate " + "triangles, or false to send them as separate triangle strips " + "with no degenerate triangles. In many cases, using one long " + "triangle strip can help performance by reducing the number " + "of separate graphics calls that have to be made.")); + ConfigVariableBool use_qpgeom ("use-qpgeom", false, PRC_DESC("A temporary variable while the experimental Geom rewrite is " diff --git a/panda/src/gobj/config_gobj.h b/panda/src/gobj/config_gobj.h index 6cb112eec7..5ac62631d2 100644 --- a/panda/src/gobj/config_gobj.h +++ b/panda/src/gobj/config_gobj.h @@ -55,6 +55,7 @@ extern EXPCL_PANDA ConfigVariableBool vertex_buffers; extern EXPCL_PANDA ConfigVariableBool display_lists; extern EXPCL_PANDA ConfigVariableBool hardware_animated_vertices; extern EXPCL_PANDA ConfigVariableBool matrix_palette; +extern EXPCL_PANDA ConfigVariableBool connect_triangle_strips; extern EXPCL_PANDA ConfigVariableBool use_qpgeom; diff --git a/panda/src/gobj/qpgeomLines.cxx b/panda/src/gobj/qpgeomLines.cxx index 55eaa89d0b..8b6457b734 100644 --- a/panda/src/gobj/qpgeomLines.cxx +++ b/panda/src/gobj/qpgeomLines.cxx @@ -56,7 +56,7 @@ qpGeomLines:: //////////////////////////////////////////////////////////////////// // Function: qpGeomLines::make_copy -// Access: Published, Virtual +// Access: Public, Virtual // Description: //////////////////////////////////////////////////////////////////// PT(qpGeomPrimitive) qpGeomLines:: @@ -66,7 +66,7 @@ make_copy() const { //////////////////////////////////////////////////////////////////// // Function: qpGeomLines::get_primitive_type -// Access: Published, Virtual +// Access: Public, Virtual // Description: Returns the fundamental rendering type of this // primitive: whether it is points, lines, or polygons. // This is used primarily to set up the appropriate @@ -80,7 +80,7 @@ get_primitive_type() const { //////////////////////////////////////////////////////////////////// // Function: qpGeomLines::get_num_vertices_per_primitive -// Access: Published, Virtual +// Access: Public, Virtual // Description: If the primitive type is a simple type in which all // primitives have the same number of vertices, like // lines, returns the number of vertices per diff --git a/panda/src/gobj/qpgeomLines.h b/panda/src/gobj/qpgeomLines.h index ecf1d611d5..7fd9c031be 100644 --- a/panda/src/gobj/qpgeomLines.h +++ b/panda/src/gobj/qpgeomLines.h @@ -34,6 +34,7 @@ PUBLISHED: qpGeomLines(const qpGeomLines ©); virtual ~qpGeomLines(); +public: virtual PT(qpGeomPrimitive) make_copy() const; virtual PrimitiveType get_primitive_type() const; diff --git a/panda/src/gobj/qpgeomLinestrips.cxx b/panda/src/gobj/qpgeomLinestrips.cxx index 3ae551fe21..6c45b92b88 100644 --- a/panda/src/gobj/qpgeomLinestrips.cxx +++ b/panda/src/gobj/qpgeomLinestrips.cxx @@ -57,7 +57,7 @@ qpGeomLinestrips:: //////////////////////////////////////////////////////////////////// // Function: qpGeomLinestrips::make_copy -// Access: Published, Virtual +// Access: Public, Virtual // Description: //////////////////////////////////////////////////////////////////// PT(qpGeomPrimitive) qpGeomLinestrips:: @@ -67,7 +67,7 @@ make_copy() const { //////////////////////////////////////////////////////////////////// // Function: qpGeomLinestrips::get_primitive_type -// Access: Published, Virtual +// Access: Public, Virtual // Description: Returns the fundamental rendering type of this // primitive: whether it is points, lines, or polygons. // This is used primarily to set up the appropriate diff --git a/panda/src/gobj/qpgeomLinestrips.h b/panda/src/gobj/qpgeomLinestrips.h index 775086cab4..e42e48c162 100644 --- a/panda/src/gobj/qpgeomLinestrips.h +++ b/panda/src/gobj/qpgeomLinestrips.h @@ -34,6 +34,7 @@ PUBLISHED: qpGeomLinestrips(const qpGeomLinestrips ©); virtual ~qpGeomLinestrips(); +public: virtual PT(qpGeomPrimitive) make_copy() const; virtual PrimitiveType get_primitive_type() const; diff --git a/panda/src/gobj/qpgeomPoints.cxx b/panda/src/gobj/qpgeomPoints.cxx index c43f6de155..97bd339a46 100644 --- a/panda/src/gobj/qpgeomPoints.cxx +++ b/panda/src/gobj/qpgeomPoints.cxx @@ -56,7 +56,7 @@ qpGeomPoints:: //////////////////////////////////////////////////////////////////// // Function: qpGeomPoints::make_copy -// Access: Published, Virtual +// Access: Public, Virtual // Description: //////////////////////////////////////////////////////////////////// PT(qpGeomPrimitive) qpGeomPoints:: @@ -66,7 +66,7 @@ make_copy() const { //////////////////////////////////////////////////////////////////// // Function: qpGeomPoints::get_primitive_type -// Access: Published, Virtual +// Access: Public, Virtual // Description: Returns the fundamental rendering type of this // primitive: whether it is points, lines, or polygons. // This is used primarily to set up the appropriate @@ -80,7 +80,7 @@ get_primitive_type() const { //////////////////////////////////////////////////////////////////// // Function: qpGeomPoints::get_num_vertices_per_primitive -// Access: Published, Virtual +// Access: Public, Virtual // Description: If the primitive type is a simple type in which all // primitives have the same number of vertices, like // points, returns the number of vertices per diff --git a/panda/src/gobj/qpgeomPoints.h b/panda/src/gobj/qpgeomPoints.h index 2b5a208280..6fe7fd7739 100644 --- a/panda/src/gobj/qpgeomPoints.h +++ b/panda/src/gobj/qpgeomPoints.h @@ -34,6 +34,7 @@ PUBLISHED: qpGeomPoints(const qpGeomPoints ©); virtual ~qpGeomPoints(); +public: virtual PT(qpGeomPrimitive) make_copy() const; virtual PrimitiveType get_primitive_type() const; diff --git a/panda/src/gobj/qpgeomPrimitive.I b/panda/src/gobj/qpgeomPrimitive.I index 1a34f96117..67bd9d086b 100644 --- a/panda/src/gobj/qpgeomPrimitive.I +++ b/panda/src/gobj/qpgeomPrimitive.I @@ -94,137 +94,103 @@ get_vertex(int i) const { } //////////////////////////////////////////////////////////////////// -// Function: qpGeomPrimitive::get_vertices +// Function: qpGeomPrimitive::get_num_faces // Access: Published -// Description: Returns a const pointer to the vertex index array so -// application code can read it directly. Do not -// attempt to modify the returned array; use -// modify_vertices() or set_vertices() for this. +// Description: Returns the number of triangles or other fundamental +// type (such as line segments) represented by all the +// primitives in this object. //////////////////////////////////////////////////////////////////// -INLINE CPTA_ushort qpGeomPrimitive:: -get_vertices() const { - CDReader cdata(_cycler); - return cdata->_vertices; -} +INLINE int qpGeomPrimitive:: +get_num_faces() const { + int num_vertices_per_primitive = get_num_vertices_per_primitive(); -//////////////////////////////////////////////////////////////////// -// Function: qpGeomPrimitive::get_flat_first_vertices -// Access: Published -// Description: Returns a const pointer to the vertex index array, -// suitable for traversing for a renderer that expects -// the key vertex of each triangle in a flat-shaded -// model to be the triangle's first vertex (as DirectX -// does). -// -// The result of this is dependent on the value -// specified to set_shade_model(). If the shade model -// indicates flat_last_vertex, this will return the -// vertices rotated to bring them into first_vertex -// compliance; otherwise, it will be the unmodified -// result from get_vertices(). -//////////////////////////////////////////////////////////////////// -INLINE CPTA_ushort qpGeomPrimitive:: -get_flat_first_vertices() const { - CDReader cdata(_cycler); - if (cdata->_shade_model == SM_flat_last_vertex) { - if (cdata->_rotated_vertices == (const ushort *)NULL) { - return ((qpGeomPrimitive *)this)->do_rotate(cdata); - } - return cdata->_rotated_vertices; + if (num_vertices_per_primitive == 0) { + int num_primitives = get_num_primitives(); + int num_vertices = get_num_vertices(); + int min_num_vertices_per_primitive = get_min_num_vertices_per_primitive(); + int num_unused_vertices_per_primitive = get_num_unused_vertices_per_primitive(); + return num_vertices - (num_primitives * (min_num_vertices_per_primitive - 1)) - ((num_primitives - 1) * num_unused_vertices_per_primitive); } else { - return cdata->_vertices; + return get_num_primitives(); } } //////////////////////////////////////////////////////////////////// -// Function: qpGeomPrimitive::get_flat_last_vertices +// Function: qpGeomPrimitive::get_primitive_num_faces // Access: Published -// Description: Returns a const pointer to the vertex index array, -// suitable for traversing for a renderer that expects -// the key vertex of each triangle in a flat-shaded -// model to be the triangle's last vertex (as OpenGL -// does). -// -// The result of this is dependent on the value -// specified to set_shade_model(). If the shade model -// indicates flat_first_vertex, this will return the -// vertices rotated to bring them into last_vertex -// compliance; otherwise, it will be the unmodified -// result from get_vertices(). +// Description: Returns the number of triangles or other fundamental +// type (such as line segments) represented by the nth +// primitive in this object. //////////////////////////////////////////////////////////////////// -INLINE CPTA_ushort qpGeomPrimitive:: -get_flat_last_vertices() const { - CDReader cdata(_cycler); - if (cdata->_shade_model == SM_flat_first_vertex) { - if (cdata->_rotated_vertices == (const ushort *)NULL) { - return ((qpGeomPrimitive *)this)->do_rotate(cdata); - } - return cdata->_rotated_vertices; +INLINE int qpGeomPrimitive:: +get_primitive_num_faces(int n) const { + int num_vertices_per_primitive = get_num_vertices_per_primitive(); + + if (num_vertices_per_primitive == 0) { + return get_primitive_num_vertices(n) - get_min_num_vertices_per_primitive() + 1; } else { - return cdata->_vertices; + return 1; } } //////////////////////////////////////////////////////////////////// -// Function: qpGeomPrimitive::get_ends +// Function: qpGeomPrimitive::get_min_vertex // Access: Published -// Description: Returns a const pointer to the primitive ends -// array so application code can read it directly. Do -// not attempt to modify the returned array; use -// modify_ends() or set_ends() for this. -// -// Note that simple primitive types, like triangles, do -// not have a ends array: since all the primitives -// have the same number of vertices, it is not needed. +// Description: Returns the minimum vertex index number used by all +// the primitives in this object. //////////////////////////////////////////////////////////////////// -INLINE CPTA_int qpGeomPrimitive:: -get_ends() const { - CDReader cdata(_cycler); - return cdata->_ends; -} - -//////////////////////////////////////////////////////////////////// -// Function: qpGeomPrimitive::get_mins -// Access: Published -// Description: Returns a const pointer to the primitive mins -// array so application code can read it directly. Do -// not attempt to modify the returned array; use -// modify_mins() or set_mins() for this. -// -// Note that simple primitive types, like triangles, do -// not have a mins array. -//////////////////////////////////////////////////////////////////// -INLINE CPTA_ushort qpGeomPrimitive:: -get_mins() const { +INLINE int qpGeomPrimitive:: +get_min_vertex() const { CDReader cdata(_cycler); if (!cdata->_got_minmax) { CDWriter cdataw(((qpGeomPrimitive *)this)->_cycler, cdata); ((qpGeomPrimitive *)this)->recompute_minmax(cdataw); - return cdataw->_mins; + return cdataw->_min_vertex; } - return cdata->_mins; + return cdata->_min_vertex; } //////////////////////////////////////////////////////////////////// -// Function: qpGeomPrimitive::get_maxs +// Function: qpGeomPrimitive::get_primitive_min_vertex // Access: Published -// Description: Returns a const pointer to the primitive maxs -// array so application code can read it directly. Do -// not attempt to modify the returned array; use -// modify_maxs() or set_maxs() for this. -// -// Note that simple primitive types, like triangles, do -// not have a maxs array. +// Description: Returns the minimum vertex index number used by the +// nth primitive in this object. //////////////////////////////////////////////////////////////////// -INLINE CPTA_ushort qpGeomPrimitive:: -get_maxs() const { +INLINE int qpGeomPrimitive:: +get_primitive_min_vertex(int n) const { + CPTA_ushort mins = get_mins(); + nassertr(n >= 0 && n < (int)mins.size(), -1); + return mins[n]; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomPrimitive::get_max_vertex +// Access: Published +// Description: Returns the maximum vertex index number used by all +// the primitives in this object. +//////////////////////////////////////////////////////////////////// +INLINE int qpGeomPrimitive:: +get_max_vertex() const { CDReader cdata(_cycler); if (!cdata->_got_minmax) { CDWriter cdataw(((qpGeomPrimitive *)this)->_cycler, cdata); ((qpGeomPrimitive *)this)->recompute_minmax(cdataw); - return cdataw->_maxs; + return cdataw->_max_vertex; } - return cdata->_maxs; + return cdata->_max_vertex; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomPrimitive::get_primitive_max_vertex +// Access: Published +// Description: Returns the maximum vertex index number used by the +// nth primitive in this object. +//////////////////////////////////////////////////////////////////// +INLINE int qpGeomPrimitive:: +get_primitive_max_vertex(int n) const { + CPTA_ushort maxs = get_maxs(); + nassertr(n >= 0 && n < (int)maxs.size(), -1); + return maxs[n]; } //////////////////////////////////////////////////////////////////// @@ -253,74 +219,137 @@ get_modified() const { } //////////////////////////////////////////////////////////////////// -// Function: qpGeomPrimitive::get_min_vertex -// Access: Published -// Description: Returns the minimum vertex index number used by the -// primitives in this object. +// Function: qpGeomPrimitive::get_vertices +// Access: Public +// Description: Returns a const pointer to the vertex index array so +// application code can read it directly. Do not +// attempt to modify the returned array; use +// modify_vertices() or set_vertices() for this. //////////////////////////////////////////////////////////////////// -INLINE int qpGeomPrimitive:: -get_min_vertex() const { +INLINE CPTA_ushort qpGeomPrimitive:: +get_vertices() const { + CDReader cdata(_cycler); + return cdata->_vertices; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomPrimitive::get_flat_first_vertices +// Access: Public +// Description: Returns a const pointer to the vertex index array, +// suitable for traversing for a renderer that expects +// the key vertex of each triangle in a flat-shaded +// model to be the triangle's first vertex (as DirectX +// does). +// +// The result of this is dependent on the value +// specified to set_shade_model(). If the shade model +// indicates flat_last_vertex, this will return the +// vertices rotated to bring them into first_vertex +// compliance; otherwise, it will be the unmodified +// result from get_vertices(). +//////////////////////////////////////////////////////////////////// +INLINE CPTA_ushort qpGeomPrimitive:: +get_flat_first_vertices() const { + CDReader cdata(_cycler); + if (cdata->_shade_model == SM_flat_last_vertex) { + if (cdata->_rotated_vertices == (const ushort *)NULL) { + return ((qpGeomPrimitive *)this)->do_rotate(cdata); + } + return cdata->_rotated_vertices; + } else { + return cdata->_vertices; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomPrimitive::get_flat_last_vertices +// Access: Public +// Description: Returns a const pointer to the vertex index array, +// suitable for traversing for a renderer that expects +// the key vertex of each triangle in a flat-shaded +// model to be the triangle's last vertex (as OpenGL +// does). +// +// The result of this is dependent on the value +// specified to set_shade_model(). If the shade model +// indicates flat_first_vertex, this will return the +// vertices rotated to bring them into last_vertex +// compliance; otherwise, it will be the unmodified +// result from get_vertices(). +//////////////////////////////////////////////////////////////////// +INLINE CPTA_ushort qpGeomPrimitive:: +get_flat_last_vertices() const { + CDReader cdata(_cycler); + if (cdata->_shade_model == SM_flat_first_vertex) { + if (cdata->_rotated_vertices == (const ushort *)NULL) { + return ((qpGeomPrimitive *)this)->do_rotate(cdata); + } + return cdata->_rotated_vertices; + } else { + return cdata->_vertices; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomPrimitive::get_ends +// Access: Public +// Description: Returns a const pointer to the primitive ends +// array so application code can read it directly. Do +// not attempt to modify the returned array; use +// modify_ends() or set_ends() for this. +// +// Note that simple primitive types, like triangles, do +// not have a ends array: since all the primitives +// have the same number of vertices, it is not needed. +//////////////////////////////////////////////////////////////////// +INLINE CPTA_int qpGeomPrimitive:: +get_ends() const { + CDReader cdata(_cycler); + return cdata->_ends; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomPrimitive::get_mins +// Access: Public +// Description: Returns a const pointer to the primitive mins +// array so application code can read it directly. Do +// not attempt to modify the returned array; use +// modify_mins() or set_mins() for this. +// +// Note that simple primitive types, like triangles, do +// not have a mins array. +//////////////////////////////////////////////////////////////////// +INLINE CPTA_ushort qpGeomPrimitive:: +get_mins() const { CDReader cdata(_cycler); if (!cdata->_got_minmax) { CDWriter cdataw(((qpGeomPrimitive *)this)->_cycler, cdata); ((qpGeomPrimitive *)this)->recompute_minmax(cdataw); - return cdataw->_min_vertex; + return cdataw->_mins; } - return cdata->_min_vertex; + return cdata->_mins; } //////////////////////////////////////////////////////////////////// -// Function: qpGeomPrimitive::get_min_vertex -// Access: Published -// Description: Returns the minimum vertex index number used by the -// ith primitive in this object. +// Function: qpGeomPrimitive::get_maxs +// Access: Public +// Description: Returns a const pointer to the primitive maxs +// array so application code can read it directly. Do +// not attempt to modify the returned array; use +// modify_maxs() or set_maxs() for this. +// +// Note that simple primitive types, like triangles, do +// not have a maxs array. //////////////////////////////////////////////////////////////////// -INLINE int qpGeomPrimitive:: -get_min_vertex(int i) const { - CPTA_ushort mins = get_mins(); - nassertr(i >= 0 && i < (int)mins.size(), -1); - return mins[i]; -} - -//////////////////////////////////////////////////////////////////// -// Function: qpGeomPrimitive::get_max_vertex -// Access: Published -// Description: Returns the maximum vertex index number used by the -// primitives in this object. -//////////////////////////////////////////////////////////////////// -INLINE int qpGeomPrimitive:: -get_max_vertex() const { +INLINE CPTA_ushort qpGeomPrimitive:: +get_maxs() const { CDReader cdata(_cycler); if (!cdata->_got_minmax) { CDWriter cdataw(((qpGeomPrimitive *)this)->_cycler, cdata); ((qpGeomPrimitive *)this)->recompute_minmax(cdataw); - return cdataw->_max_vertex; + return cdataw->_maxs; } - return cdata->_max_vertex; -} - -//////////////////////////////////////////////////////////////////// -// Function: qpGeomPrimitive::get_max_vertex -// Access: Published -// Description: Returns the maximum vertex index number used by the -// ith primitive in this object. -//////////////////////////////////////////////////////////////////// -INLINE int qpGeomPrimitive:: -get_max_vertex(int i) const { - CPTA_ushort maxs = get_maxs(); - nassertr(i >= 0 && i < (int)maxs.size(), -1); - return maxs[i]; -} - -//////////////////////////////////////////////////////////////////// -// Function: qpGeomPrimitive::get_primitive_end -// Access: Published -// Description: Returns the element within the _vertices list at which -// the ith primitive ends. -//////////////////////////////////////////////////////////////////// -INLINE int qpGeomPrimitive:: -get_primitive_end(int i) const { - return get_primitive_start(i + 1); + return cdata->_maxs; } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/gobj/qpgeomPrimitive.cxx b/panda/src/gobj/qpgeomPrimitive.cxx index aa77eb9048..c9b9fed202 100644 --- a/panda/src/gobj/qpgeomPrimitive.cxx +++ b/panda/src/gobj/qpgeomPrimitive.cxx @@ -98,6 +98,15 @@ add_vertex(int vertex) { clear_cache(); CDWriter cdata(_cycler); + + int num_primitives = get_num_primitives(); + if (num_primitives > 0 && + cdata->_vertices.size() == get_primitive_end(num_primitives - 1)) { + // If we are beginning a new primitive, give the derived class a + // chance to insert some degenerate vertices. + append_unused_vertices(cdata->_vertices, vertex); + } + cdata->_vertices.push_back(short_vertex); cdata->_rotated_vertices.clear(); @@ -166,9 +175,10 @@ add_consecutive_vertices(int start, int num_vertices) { // Access: Published // Description: Indicates that the previous n calls to add_vertex(), // since the last call to close_primitive(), have fully -// defined a new primitive. +// defined a new primitive. Returns true if successful, +// false otherwise. //////////////////////////////////////////////////////////////////// -void qpGeomPrimitive:: +bool qpGeomPrimitive:: close_primitive() { clear_cache(); int num_vertices_per_primitive = get_num_vertices_per_primitive(); @@ -183,22 +193,35 @@ close_primitive() { num_added = (int)cdata->_vertices.size(); } else { num_added = (int)cdata->_vertices.size() - cdata->_ends.back(); + num_added -= get_num_unused_vertices_per_primitive(); } - nassertv(num_added >= get_min_num_vertices_per_primitive()); + nassertr(num_added >= get_min_num_vertices_per_primitive(), false); #endif cdata->_ends.push_back((int)cdata->_vertices.size()); +#ifndef NDEBUG if (cdata->_got_minmax) { - nassertv((cdata->_mins.size() == cdata->_ends.size()) && - (cdata->_maxs.size() == cdata->_ends.size())); + nassertd((cdata->_mins.size() == cdata->_ends.size()) && + (cdata->_maxs.size() == cdata->_ends.size())) { + cdata->_got_minmax = false; + } } +#endif } else { +#ifndef NDEBUG // This is a simple primitive type like a triangle: each primitive // uses the same number of vertices. Assert that we added the // correct number of vertices. - nassertv((int)cdata->_vertices.size() % num_vertices_per_primitive == 0); + int num_vertices_per_primitive = get_num_vertices_per_primitive(); + int num_unused_vertices_per_primitive = get_num_unused_vertices_per_primitive(); + + int num_vertices = cdata->_vertices.size(); + nassertr((num_vertices + num_unused_vertices_per_primitive) % (num_vertices_per_primitive + num_unused_vertices_per_primitive) == 0, false) +#endif } + + return true; } //////////////////////////////////////////////////////////////////// @@ -219,121 +242,6 @@ clear_vertices() { cdata->_got_minmax = false; } -//////////////////////////////////////////////////////////////////// -// Function: qpGeomPrimitive::modify_vertices -// Access: Published -// Description: Returns a modifiable pointer to the vertex index -// list, so application code can directly fiddle with -// this data. Use with caution, since there are no -// checks that the data will be left in a stable state. -//////////////////////////////////////////////////////////////////// -PTA_ushort qpGeomPrimitive:: -modify_vertices() { - clear_cache(); - CDWriter cdata(_cycler); - cdata->_rotated_vertices.clear(); - cdata->_got_minmax = false; - return cdata->_vertices; -} - -//////////////////////////////////////////////////////////////////// -// Function: qpGeomPrimitive::set_vertices -// Access: Published -// Description: Completely replaces the vertex index list with a new -// table. Chances are good that you should also replace -// the ends list with set_ends() at the same time. -//////////////////////////////////////////////////////////////////// -void qpGeomPrimitive:: -set_vertices(CPTA_ushort vertices) { - clear_cache(); - CDWriter cdata(_cycler); - cdata->_vertices = (PTA_ushort &)vertices; - cdata->_rotated_vertices.clear(); - cdata->_got_minmax = false; -} - -//////////////////////////////////////////////////////////////////// -// Function: qpGeomPrimitive::modify_ends -// Access: Published -// Description: Returns a modifiable pointer to the primitive ends -// array, so application code can directly fiddle with -// this data. Use with caution, since there are no -// checks that the data will be left in a stable state. -// -// Note that simple primitive types, like triangles, do -// not have a ends array: since all the primitives -// have the same number of vertices, it is not needed. -//////////////////////////////////////////////////////////////////// -PTA_int qpGeomPrimitive:: -modify_ends() { - clear_cache(); - CDWriter cdata(_cycler); - cdata->_rotated_vertices.clear(); - cdata->_got_minmax = false; - return cdata->_ends; -} - -//////////////////////////////////////////////////////////////////// -// Function: qpGeomPrimitive::set_ends -// Access: Published -// Description: Completely replaces the primitive ends array with -// a new table. Chances are good that you should also -// replace the vertices list with set_vertices() at the -// same time. -// -// Note that simple primitive types, like triangles, do -// not have a ends array: since all the primitives -// have the same number of vertices, it is not needed. -//////////////////////////////////////////////////////////////////// -void qpGeomPrimitive:: -set_ends(CPTA_int ends) { - clear_cache(); - CDWriter cdata(_cycler); - cdata->_ends = (PTA_int &)ends; - cdata->_rotated_vertices.clear(); - cdata->_got_minmax = false; -} - -//////////////////////////////////////////////////////////////////// -// Function: qpGeomPrimitive::get_num_bytes -// Access: Published -// Description: Returns the number of bytes consumed by the primitive -// and its index table(s). -//////////////////////////////////////////////////////////////////// -int qpGeomPrimitive:: -get_num_bytes() const { - CDReader cdata(_cycler); - return (cdata->_vertices.size() + cdata->_mins.size() + cdata->_maxs.size()) * sizeof(short) + - cdata->_ends.size() * sizeof(int) + sizeof(qpGeomPrimitive); -} - -//////////////////////////////////////////////////////////////////// -// Function: qpGeomPrimitive::get_num_vertices_per_primitive -// Access: Published, Virtual -// Description: If the primitive type is a simple type in which all -// primitives have the same number of vertices, like -// triangles, returns the number of vertices per -// primitive. If the primitive type is a more complex -// type in which different primitives might have -// different numbers of vertices, for instance a -// triangle strip, returns 0. -//////////////////////////////////////////////////////////////////// -int qpGeomPrimitive:: -get_num_vertices_per_primitive() const { - return 0; -} - -//////////////////////////////////////////////////////////////////// -// Function: qpGeomPrimitive::get_min_num_vertices_per_primitive -// Access: Published, Virtual -// Description: Returns the minimum number of vertices that must be -// added before close_primitive() may legally be called. -//////////////////////////////////////////////////////////////////// -int qpGeomPrimitive:: -get_min_num_vertices_per_primitive() const { - return 3; -} - //////////////////////////////////////////////////////////////////// // Function: qpGeomPrimitive::get_num_primitives // Access: Published @@ -362,56 +270,86 @@ get_num_primitives() const { // Function: qpGeomPrimitive::get_primitive_start // Access: Published // Description: Returns the element within the _vertices list at which -// the ith 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 -// last valid vertex. Thus, it is always true that the -// vertices used by a particular primitive i are the set -// get_primitive_start(i) <= vi < get_primitive_start(i -// + 1). +// last valid vertex. Thus, it is generally true that +// the vertices used by a particular primitive i are the +// set get_primitive_start(n) <= vi < +// get_primitive_start(n + 1) (although this range also +// includes the unused vertices between primitives). //////////////////////////////////////////////////////////////////// int qpGeomPrimitive:: -get_primitive_start(int i) const { +get_primitive_start(int n) const { + int num_vertices_per_primitive = get_num_vertices_per_primitive(); + int num_unused_vertices_per_primitive = get_num_unused_vertices_per_primitive(); + + if (num_vertices_per_primitive == 0) { + // This is a complex primitive type like a triangle strip: each + // primitive uses a different number of vertices. + CDReader cdata(_cycler); + nassertr(n >= 0 && n <= (int)cdata->_ends.size(), -1); + if (n == 0) { + return 0; + } else { + return cdata->_ends[n - 1] + num_unused_vertices_per_primitive; + } + + } else { + // This is a simple primitive type like a triangle: each primitive + // uses the same number of vertices. + return n * (num_vertices_per_primitive + num_unused_vertices_per_primitive); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomPrimitive::get_primitive_end +// Access: Published +// Description: Returns the element within the _vertices list at which +// the nth primitive ends. This is one past the last +// valid element for the nth primitive. +//////////////////////////////////////////////////////////////////// +int qpGeomPrimitive:: +get_primitive_end(int n) const { int num_vertices_per_primitive = get_num_vertices_per_primitive(); if (num_vertices_per_primitive == 0) { // This is a complex primitive type like a triangle strip: each // primitive uses a different number of vertices. CDReader cdata(_cycler); - nassertr(i >= 0 && i <= (int)cdata->_ends.size(), -1); - if (i == 0) { - return 0; - } else { - return cdata->_ends[i - 1]; - } + nassertr(n >= 0 && n < (int)cdata->_ends.size(), -1); + return cdata->_ends[n]; } else { // This is a simple primitive type like a triangle: each primitive // uses the same number of vertices. - return i * num_vertices_per_primitive; + int num_unused_vertices_per_primitive = get_num_unused_vertices_per_primitive(); + return n * (num_vertices_per_primitive + num_unused_vertices_per_primitive) + num_vertices_per_primitive; } } //////////////////////////////////////////////////////////////////// // Function: qpGeomPrimitive::get_primitive_num_vertices // Access: Published -// Description: Returns the number of vertices used by the ith -// primitive. +// Description: Returns the number of vertices used by the nth +// primitive. This is the same thing as +// get_primitive_end(n) - get_primitive_start(n). //////////////////////////////////////////////////////////////////// int qpGeomPrimitive:: -get_primitive_num_vertices(int i) const { +get_primitive_num_vertices(int n) const { int num_vertices_per_primitive = get_num_vertices_per_primitive(); if (num_vertices_per_primitive == 0) { // This is a complex primitive type like a triangle strip: each // primitive uses a different number of vertices. CDReader cdata(_cycler); - nassertr(i >= 0 && i < (int)cdata->_ends.size(), 0); - if (i == 0) { + nassertr(n >= 0 && n < (int)cdata->_ends.size(), 0); + if (n == 0) { return cdata->_ends[0]; } else { - return cdata->_ends[i] - cdata->_ends[i - 1]; + 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 { @@ -482,6 +420,19 @@ decompose() const { return result; } +//////////////////////////////////////////////////////////////////// +// Function: qpGeomPrimitive::get_num_bytes +// Access: Published +// Description: Returns the number of bytes consumed by the primitive +// and its index table(s). +//////////////////////////////////////////////////////////////////// +int qpGeomPrimitive:: +get_num_bytes() const { + CDReader cdata(_cycler); + return (cdata->_vertices.size() + cdata->_mins.size() + cdata->_maxs.size()) * sizeof(short) + + cdata->_ends.size() * sizeof(int) + sizeof(qpGeomPrimitive); +} + //////////////////////////////////////////////////////////////////// // Function: qpGeomPrimitive::output // Access: Published, Virtual @@ -503,21 +454,149 @@ write(ostream &out, int indent_level) const { indent(out, indent_level) << get_type() << ":\n"; int num_primitives = get_num_primitives(); - for (int i = 0; i < num_primitives; i++) { + int num_vertices = get_num_vertices(); + int num_unused_vertices_per_primitive = get_num_unused_vertices_per_primitive(); + for (int i = 0; i < num_primitives; ++i) { indent(out, indent_level + 2) << "["; int begin = get_primitive_start(i); - int end = get_primitive_start(i + 1); + int end = get_primitive_end(i); for (int vi = begin; vi < end; vi++) { out << " " << get_vertex(vi); } - out << " ]\n"; + out << " ]"; + if (end < num_vertices) { + for (int ui = 0; ui < num_unused_vertices_per_primitive; ++ui) { + if (end + ui < num_vertices) { + out << " " << get_vertex(end + ui); + } else { + out << " ?"; + } + } + } + out << "\n"; } } +//////////////////////////////////////////////////////////////////// +// Function: qpGeomPrimitive::modify_vertices +// Access: Public +// Description: Returns a modifiable pointer to the vertex index +// list, so application code can directly fiddle with +// this data. Use with caution, since there are no +// checks that the data will be left in a stable state. +//////////////////////////////////////////////////////////////////// +PTA_ushort qpGeomPrimitive:: +modify_vertices() { + clear_cache(); + CDWriter cdata(_cycler); + cdata->_rotated_vertices.clear(); + cdata->_got_minmax = false; + return cdata->_vertices; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomPrimitive::set_vertices +// Access: Public +// Description: Completely replaces the vertex index list with a new +// table. Chances are good that you should also replace +// the ends list with set_ends() at the same time. +//////////////////////////////////////////////////////////////////// +void qpGeomPrimitive:: +set_vertices(CPTA_ushort vertices) { + clear_cache(); + CDWriter cdata(_cycler); + cdata->_vertices = (PTA_ushort &)vertices; + cdata->_rotated_vertices.clear(); + cdata->_got_minmax = false; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomPrimitive::modify_ends +// Access: Public +// Description: Returns a modifiable pointer to the primitive ends +// array, so application code can directly fiddle with +// this data. Use with caution, since there are no +// checks that the data will be left in a stable state. +// +// Note that simple primitive types, like triangles, do +// not have a ends array: since all the primitives +// have the same number of vertices, it is not needed. +//////////////////////////////////////////////////////////////////// +PTA_int qpGeomPrimitive:: +modify_ends() { + clear_cache(); + CDWriter cdata(_cycler); + cdata->_rotated_vertices.clear(); + cdata->_got_minmax = false; + return cdata->_ends; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomPrimitive::set_ends +// Access: Public +// Description: Completely replaces the primitive ends array with +// a new table. Chances are good that you should also +// replace the vertices list with set_vertices() at the +// same time. +// +// Note that simple primitive types, like triangles, do +// not have a ends array: since all the primitives +// have the same number of vertices, it is not needed. +//////////////////////////////////////////////////////////////////// +void qpGeomPrimitive:: +set_ends(CPTA_int ends) { + clear_cache(); + CDWriter cdata(_cycler); + cdata->_ends = (PTA_int &)ends; + cdata->_rotated_vertices.clear(); + cdata->_got_minmax = false; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomPrimitive::get_num_vertices_per_primitive +// Access: Public, Virtual +// Description: If the primitive type is a simple type in which all +// primitives have the same number of vertices, like +// triangles, returns the number of vertices per +// primitive. If the primitive type is a more complex +// type in which different primitives might have +// different numbers of vertices, for instance a +// triangle strip, returns 0. +//////////////////////////////////////////////////////////////////// +int qpGeomPrimitive:: +get_num_vertices_per_primitive() const { + return 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomPrimitive::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 qpGeomPrimitive:: +get_min_num_vertices_per_primitive() const { + return 3; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomPrimitive::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 qpGeomPrimitive:: +get_num_unused_vertices_per_primitive() const { + return 0; +} + //////////////////////////////////////////////////////////////////// // Function: qpGeomPrimitive::clear_cache -// Access: Published +// Access: Public // Description: Removes all of the previously-cached results of // decompose(). //////////////////////////////////////////////////////////////////// @@ -539,7 +618,7 @@ clear_cache() { //////////////////////////////////////////////////////////////////// // Function: qpGeomPrimitive::prepare -// Access: Published +// Access: Public // Description: Indicates that the data should be enqueued to be // prepared in the indicated prepared_objects at the // beginning of the next frame. This will ensure the @@ -756,6 +835,19 @@ rotate_impl() const { return get_vertices(); } +//////////////////////////////////////////////////////////////////// +// Function: qpGeomPrimitive::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 qpGeomPrimitive:: +append_unused_vertices(PTA_ushort &, int) { +} + //////////////////////////////////////////////////////////////////// // Function: qpGeomPrimitive::do_rotate // Access: Private diff --git a/panda/src/gobj/qpgeomPrimitive.h b/panda/src/gobj/qpgeomPrimitive.h index ab65bffdee..ba80a41061 100644 --- a/panda/src/gobj/qpgeomPrimitive.h +++ b/panda/src/gobj/qpgeomPrimitive.h @@ -105,13 +105,53 @@ PUBLISHED: INLINE ShadeModel get_shade_model() const; INLINE void set_shade_model(ShadeModel shade_model); + // The following published methods are provided for safe, high-level + // iteration through the vertices and sub-primitives within the + // GeomPrimitive class. These work correctly regardless of the + // primitive type and without depending on knowledge about the way + // primitives' lengths are encoded. You can also safely build up a + // composite primitive using these methods. + INLINE int get_num_vertices() const; INLINE int get_vertex(int i) const; void add_vertex(int vertex); void add_consecutive_vertices(int start, int num_vertices); - void close_primitive(); + bool close_primitive(); void clear_vertices(); + int get_num_primitives() const; + int get_primitive_start(int n) const; + int get_primitive_end(int n) const; + int get_primitive_num_vertices(int n) const; + + INLINE int get_num_faces() const; + INLINE int get_primitive_num_faces(int n) const; + + INLINE int get_min_vertex() const; + INLINE int get_primitive_min_vertex(int n) const; + INLINE int get_max_vertex() const; + INLINE int get_primitive_max_vertex(int n) const; + + CPT(qpGeomPrimitive) decompose() const; + + int get_num_bytes() const; + INLINE int get_data_size_bytes() const; + INLINE UpdateSeq get_modified() const; + + virtual void output(ostream &out) const; + virtual void write(ostream &out, int indent_level) const; + +public: + // These public methods are not intended for high-level usage. They + // are public so that C++ code that absolutely needs fast access to + // the primitive data can get to it, but using them requires + // knowledge about how the component primitives are encoded within + // the GeomPrimitive class, and it's easy to screw something up. + // Also, if too many code samples depend on this internal knowledge, + // it may make it difficult to extend this class later. It is + // recommended that application-level code use the above interfaces + // instead. + INLINE CPTA_ushort get_vertices() const; INLINE CPTA_ushort get_flat_first_vertices() const; INLINE CPTA_ushort get_flat_last_vertices() const; @@ -125,29 +165,11 @@ PUBLISHED: INLINE CPTA_ushort get_mins() const; INLINE CPTA_ushort get_maxs() const; - int get_num_bytes() const; - INLINE int get_data_size_bytes() const; - INLINE UpdateSeq get_modified() const; - - INLINE int get_min_vertex() const; - INLINE int get_min_vertex(int i) const; - INLINE int get_max_vertex() const; - INLINE int get_max_vertex(int i) const; - virtual int get_num_vertices_per_primitive() const; virtual int get_min_num_vertices_per_primitive() const; - int get_num_primitives() const; - int get_primitive_start(int i) const; - INLINE int get_primitive_end(int i) const; - int get_primitive_num_vertices(int i) const; - - CPT(qpGeomPrimitive) decompose() const; - - virtual void output(ostream &out) const; - virtual void write(ostream &out, int indent_level) const; + virtual int get_num_unused_vertices_per_primitive() const; void clear_cache(); - void prepare(PreparedGraphicsObjects *prepared_objects); public: @@ -170,6 +192,7 @@ public: protected: virtual CPT(qpGeomPrimitive) decompose_impl() const; virtual CPTA_ushort rotate_impl() const; + virtual void append_unused_vertices(PTA_ushort &vertices, int vertex); protected: static PStatCollector _rotate_pcollector; @@ -195,7 +218,6 @@ private: CPT(qpGeomPrimitive) _decomposed; }; - // This is the data that must be cycled between pipeline stages. class EXPCL_PANDA CData : public CycleData { public: diff --git a/panda/src/gobj/qpgeomTriangles.cxx b/panda/src/gobj/qpgeomTriangles.cxx index 0ffdcfc42f..e27ac0e12a 100644 --- a/panda/src/gobj/qpgeomTriangles.cxx +++ b/panda/src/gobj/qpgeomTriangles.cxx @@ -56,7 +56,7 @@ qpGeomTriangles:: //////////////////////////////////////////////////////////////////// // Function: qpGeomTriangles::make_copy -// Access: Published, Virtual +// Access: Public, Virtual // Description: //////////////////////////////////////////////////////////////////// PT(qpGeomPrimitive) qpGeomTriangles:: @@ -66,7 +66,7 @@ make_copy() const { //////////////////////////////////////////////////////////////////// // Function: qpGeomTriangles::get_primitive_type -// Access: Published, Virtual +// Access: Public, Virtual // Description: Returns the fundamental rendering type of this // primitive: whether it is points, lines, or polygons. // This is used primarily to set up the appropriate @@ -80,7 +80,7 @@ get_primitive_type() const { //////////////////////////////////////////////////////////////////// // Function: qpGeomTriangles::get_num_vertices_per_primitive -// Access: Published, Virtual +// Access: Public, Virtual // Description: If the primitive type is a simple type in which all // primitives have the same number of vertices, like // triangles, returns the number of vertices per diff --git a/panda/src/gobj/qpgeomTriangles.h b/panda/src/gobj/qpgeomTriangles.h index 6c0b7219bf..7b71d40751 100644 --- a/panda/src/gobj/qpgeomTriangles.h +++ b/panda/src/gobj/qpgeomTriangles.h @@ -34,6 +34,7 @@ PUBLISHED: qpGeomTriangles(const qpGeomTriangles ©); virtual ~qpGeomTriangles(); +public: virtual PT(qpGeomPrimitive) make_copy() const; virtual PrimitiveType get_primitive_type() const; diff --git a/panda/src/gobj/qpgeomTrifans.cxx b/panda/src/gobj/qpgeomTrifans.cxx index 9433b0abc4..3686453f61 100644 --- a/panda/src/gobj/qpgeomTrifans.cxx +++ b/panda/src/gobj/qpgeomTrifans.cxx @@ -56,7 +56,7 @@ qpGeomTrifans:: //////////////////////////////////////////////////////////////////// // Function: qpGeomTrifans::make_copy -// Access: Published, Virtual +// Access: Public, Virtual // Description: //////////////////////////////////////////////////////////////////// PT(qpGeomPrimitive) qpGeomTrifans:: @@ -66,7 +66,7 @@ make_copy() const { //////////////////////////////////////////////////////////////////// // Function: qpGeomTrifans::get_primitive_type -// Access: Published, Virtual +// Access: Public, Virtual // Description: Returns the fundamental rendering type of this // primitive: whether it is points, lines, or polygons. // This is used primarily to set up the appropriate diff --git a/panda/src/gobj/qpgeomTrifans.h b/panda/src/gobj/qpgeomTrifans.h index 07d33f97e0..4e25d6729c 100644 --- a/panda/src/gobj/qpgeomTrifans.h +++ b/panda/src/gobj/qpgeomTrifans.h @@ -34,6 +34,7 @@ PUBLISHED: qpGeomTrifans(const qpGeomTrifans ©); virtual ~qpGeomTrifans(); +public: virtual PT(qpGeomPrimitive) make_copy() const; virtual PrimitiveType get_primitive_type() const; diff --git a/panda/src/gobj/qpgeomTristrips.cxx b/panda/src/gobj/qpgeomTristrips.cxx index fcb0674080..43f582b047 100644 --- a/panda/src/gobj/qpgeomTristrips.cxx +++ b/panda/src/gobj/qpgeomTristrips.cxx @@ -57,7 +57,7 @@ qpGeomTristrips:: //////////////////////////////////////////////////////////////////// // Function: qpGeomTristrips::make_copy -// Access: Published, Virtual +// Access: Public, Virtual // Description: //////////////////////////////////////////////////////////////////// PT(qpGeomPrimitive) qpGeomTristrips:: @@ -67,7 +67,7 @@ make_copy() const { //////////////////////////////////////////////////////////////////// // Function: qpGeomTristrips::get_primitive_type -// Access: Published, Virtual +// Access: Public, Virtual // Description: Returns the fundamental rendering type of this // primitive: whether it is points, lines, or polygons. // This is used primarily to set up the appropriate @@ -79,6 +79,20 @@ get_primitive_type() const { return PT_polygons; } +//////////////////////////////////////////////////////////////////// +// Function: qpGeomTristrips::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 qpGeomTristrips:: +get_num_unused_vertices_per_primitive() const { + return 2; +} + //////////////////////////////////////////////////////////////////// // Function: qpGeomTristrips::draw // Access: Public, Virtual @@ -118,9 +132,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 = 0; + int vi = -2; int li = 0; while (li < (int)ends.size()) { + // Skip unused vertices between tristrips. + vi += 2; int end = ends[li]; nassertr(vi + 2 <= end, triangles.p()); nassertr(vi < (int)vertices.size(), this); @@ -154,9 +170,11 @@ decompose_impl() const { } else { // Preserve the last vertex of each component triangle as the // last vertex of each generated triangle. - int vi = 0; + int vi = -2; int li = 0; while (li < (int)ends.size()) { + // Skip unused vertices between tristrips. + vi += 2; int end = ends[li]; nassertr(vi + 2 <= end, triangles.p()); nassertr(vi < (int)vertices.size(), this); @@ -216,6 +234,13 @@ rotate_impl() const { int end = (*ei); int num_vertices = end - begin; + if (begin != 0) { + // Copy in the unused vertices between tristrips. + new_vertices.push_back(new_vertices.back()); + new_vertices.push_back(vertices[end - 1]); + begin += 2; + } + if ((num_vertices & 1) == 0) { for (int vi = end - 1; vi >= begin; --vi) { new_vertices.push_back(vertices[vi]); @@ -235,6 +260,21 @@ rotate_impl() const { return new_vertices; } +//////////////////////////////////////////////////////////////////// +// Function: qpGeomTristrips::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 qpGeomTristrips:: +append_unused_vertices(PTA_ushort &vertices, int vertex) { + vertices.push_back(vertices.back()); + vertices.push_back(vertex); +} + //////////////////////////////////////////////////////////////////// // Function: qpGeomTristrips::register_with_read_factory // Access: Public, Static diff --git a/panda/src/gobj/qpgeomTristrips.h b/panda/src/gobj/qpgeomTristrips.h index c99555abcb..1b0469c9f5 100644 --- a/panda/src/gobj/qpgeomTristrips.h +++ b/panda/src/gobj/qpgeomTristrips.h @@ -34,8 +34,10 @@ PUBLISHED: qpGeomTristrips(const qpGeomTristrips ©); virtual ~qpGeomTristrips(); +public: virtual PT(qpGeomPrimitive) make_copy() const; virtual PrimitiveType get_primitive_type() const; + virtual int get_num_unused_vertices_per_primitive() const; public: virtual void draw(GraphicsStateGuardianBase *gsg) const; @@ -43,6 +45,7 @@ public: protected: virtual CPT(qpGeomPrimitive) decompose_impl() const; virtual CPTA_ushort rotate_impl() const; + virtual void append_unused_vertices(PTA_ushort &vertices, int vertex); public: static void register_with_read_factory();