diff --git a/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx b/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx index 3e65b405c3..664eb78d4b 100644 --- a/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx +++ b/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx @@ -2739,29 +2739,51 @@ void DXGraphicsStateGuardian8:: draw_triangles(const qpGeomTriangles *primitive) { _vertices_tri_pcollector.add_level(primitive->get_num_vertices()); _primitive_batches_tri_pcollector.add_level(1); - if (_vbuffer_active) { - IndexBufferContext *ibc = ((qpGeomPrimitive *)primitive)->prepare_now(get_prepared_objects(), this); - nassertv(ibc != (IndexBufferContext *)NULL); - apply_index_buffer(ibc); - - _pD3DDevice->DrawIndexedPrimitive - (D3DPT_TRIANGLELIST, - primitive->get_min_vertex(), - primitive->get_max_vertex() - primitive->get_min_vertex() + 1, - 0, primitive->get_num_primitives()); - + if (primitive->is_indexed()) { + if (_vbuffer_active) { + // Indexed, vbuffers. + IndexBufferContext *ibc = ((qpGeomPrimitive *)primitive)->prepare_now(get_prepared_objects(), this); + nassertv(ibc != (IndexBufferContext *)NULL); + apply_index_buffer(ibc); + + _pD3DDevice->DrawIndexedPrimitive + (D3DPT_TRIANGLELIST, + primitive->get_min_vertex(), + primitive->get_max_vertex() - primitive->get_min_vertex() + 1, + 0, primitive->get_num_primitives()); + + } else { + // Indexed, client arrays. + D3DFORMAT index_type = get_index_type(primitive->get_index_type()); + + _pD3DDevice->DrawIndexedPrimitiveUP + (D3DPT_TRIANGLELIST, + primitive->get_min_vertex(), + primitive->get_max_vertex() - primitive->get_min_vertex() + 1, + primitive->get_num_primitives(), + primitive->get_data(), + index_type, + _vertex_data->get_array(0)->get_data(), + _vertex_data->get_format()->get_array(0)->get_stride()); + } } else { - D3DFORMAT index_type = get_index_type(primitive->get_index_type()); - - _pD3DDevice->DrawIndexedPrimitiveUP - (D3DPT_TRIANGLELIST, - primitive->get_min_vertex(), - primitive->get_max_vertex() - primitive->get_min_vertex() + 1, - primitive->get_num_primitives(), - primitive->get_data(), - index_type, - _vertex_data->get_array(0)->get_data(), - _vertex_data->get_format()->get_array(0)->get_stride()); + if (_vbuffer_active) { + // Nonindexed, vbuffers. + _pD3DDevice->DrawPrimitive + (D3DPT_TRIANGLELIST, + primitive->get_first_vertex(), + primitive->get_num_primitives()); + + } else { + // Nonindexed, client arrays. + int stride = _vertex_data->get_format()->get_array(0)->get_stride(); + unsigned int first_vertex = primitive->get_first_vertex(); + _pD3DDevice->DrawPrimitiveUP + (D3DPT_TRIANGLELIST, + primitive->get_num_primitives(), + _vertex_data->get_array(0)->get_data() + stride * first_vertex, + stride); + } } } @@ -2781,74 +2803,134 @@ draw_tristrips(const qpGeomTristrips *primitive) { // that have already been set up within the primitive. _vertices_tristrip_pcollector.add_level(primitive->get_num_vertices()); _primitive_batches_tristrip_pcollector.add_level(1); - if (_vbuffer_active) { - IndexBufferContext *ibc = ((qpGeomPrimitive *)primitive)->prepare_now(get_prepared_objects(), this); - nassertv(ibc != (IndexBufferContext *)NULL); - apply_index_buffer(ibc); - - _pD3DDevice->DrawIndexedPrimitive - (D3DPT_TRIANGLESTRIP, - min_vertex, max_vertex - min_vertex + 1, - 0, primitive->get_num_vertices() - 2); - + if (primitive->is_indexed()) { + if (_vbuffer_active) { + // Indexed, vbuffers, one line triangle strip. + IndexBufferContext *ibc = ((qpGeomPrimitive *)primitive)->prepare_now(get_prepared_objects(), this); + nassertv(ibc != (IndexBufferContext *)NULL); + apply_index_buffer(ibc); + + _pD3DDevice->DrawIndexedPrimitive + (D3DPT_TRIANGLESTRIP, + min_vertex, max_vertex - min_vertex + 1, + 0, primitive->get_num_vertices() - 2); + + } else { + // Indexed, client arrays, one long triangle strip. + _pD3DDevice->DrawIndexedPrimitiveUP + (D3DPT_TRIANGLESTRIP, + min_vertex, max_vertex - min_vertex + 1, + primitive->get_num_vertices() - 2, + primitive->get_data(), index_type, + _vertex_data->get_array(0)->get_data(), + _vertex_data->get_format()->get_array(0)->get_stride()); + } } else { - _pD3DDevice->DrawIndexedPrimitiveUP - (D3DPT_TRIANGLESTRIP, - min_vertex, max_vertex - min_vertex + 1, - primitive->get_num_vertices() - 2, - primitive->get_data(), index_type, - _vertex_data->get_array(0)->get_data(), - _vertex_data->get_format()->get_array(0)->get_stride()); + if (_vbuffer_active) { + // Nonindexed, vbuffers, one long triangle strip. + _pD3DDevice->DrawPrimitive + (D3DPT_TRIANGLESTRIP, + primitive->get_first_vertex(), + primitive->get_num_vertices() - 2); + + } else { + // Indexed, client arrays, one long triangle strip. + int stride = _vertex_data->get_format()->get_array(0)->get_stride(); + unsigned int first_vertex = primitive->get_first_vertex(); + _pD3DDevice->DrawPrimitiveUP + (D3DPT_TRIANGLESTRIP, + primitive->get_num_vertices() - 2, + _vertex_data->get_array(0)->get_data() + stride * first_vertex, + stride); + } } } else { // Send the individual triangle strips, stepping over the // degenerate vertices. CPTA_int ends = primitive->get_ends(); - int index_stride = primitive->get_index_stride(); _primitive_batches_tristrip_pcollector.add_level(ends.size()); - qpGeomVertexReader mins(primitive->get_mins(), 0); - qpGeomVertexReader maxs(primitive->get_maxs(), 0); - nassertv(primitive->get_mins()->get_num_rows() == (int)ends.size() && - primitive->get_maxs()->get_num_rows() == (int)ends.size()); - - if (_vbuffer_active) { - IndexBufferContext *ibc = ((qpGeomPrimitive *)primitive)->prepare_now(get_prepared_objects(), this); - nassertv(ibc != (IndexBufferContext *)NULL); - apply_index_buffer(ibc); + if (primitive->is_indexed()) { + CPTA_int ends = primitive->get_ends(); + int index_stride = primitive->get_index_stride(); + _primitive_batches_tristrip_pcollector.add_level(ends.size()); - unsigned int start = 0; - for (size_t i = 0; i < ends.size(); i++) { - _vertices_tristrip_pcollector.add_level(ends[i] - start); - unsigned int min = mins.get_data1i(); - unsigned int max = maxs.get_data1i(); - _pD3DDevice->DrawIndexedPrimitive - (D3DPT_TRIANGLESTRIP, - min, max - min + 1, - start, ends[i] - start - 2); + qpGeomVertexReader mins(primitive->get_mins(), 0); + qpGeomVertexReader maxs(primitive->get_maxs(), 0); + nassertv(primitive->get_mins()->get_num_rows() == (int)ends.size() && + primitive->get_maxs()->get_num_rows() == (int)ends.size()); + + if (_vbuffer_active) { + // Indexed, client arrays, individual triangle strips. + IndexBufferContext *ibc = ((qpGeomPrimitive *)primitive)->prepare_now(get_prepared_objects(), this); + nassertv(ibc != (IndexBufferContext *)NULL); + apply_index_buffer(ibc); - start = ends[i] + 2; + unsigned int start = 0; + for (size_t i = 0; i < ends.size(); i++) { + _vertices_tristrip_pcollector.add_level(ends[i] - start); + unsigned int min = mins.get_data1i(); + unsigned int max = maxs.get_data1i(); + _pD3DDevice->DrawIndexedPrimitive + (D3DPT_TRIANGLESTRIP, + min, max - min + 1, + start, ends[i] - start - 2); + + start = ends[i] + 2; + } + + } else { + // Indexed, client arrays, individual triangle strips. + CPTA_uchar array_data = _vertex_data->get_array(0)->get_data(); + int stride = _vertex_data->get_format()->get_array(0)->get_stride(); + CPTA_uchar vertices = primitive->get_data(); + + unsigned int start = 0; + for (size_t i = 0; i < ends.size(); i++) { + _vertices_tristrip_pcollector.add_level(ends[i] - start); + unsigned int min = mins.get_data1i(); + unsigned int max = maxs.get_data1i(); + _pD3DDevice->DrawIndexedPrimitiveUP + (D3DPT_TRIANGLESTRIP, + min, max - min + 1, + ends[i] - start - 2, + vertices + start * index_stride, index_type, + array_data, stride); + + 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(); - CPTA_uchar vertices = primitive->get_data(); - - unsigned int start = 0; - for (size_t i = 0; i < ends.size(); i++) { - _vertices_tristrip_pcollector.add_level(ends[i] - start); - unsigned int min = mins.get_data1i(); - unsigned int max = maxs.get_data1i(); - _pD3DDevice->DrawIndexedPrimitiveUP - (D3DPT_TRIANGLESTRIP, - min, max - min + 1, - ends[i] - start - 2, - vertices + start * index_stride, index_type, - array_data, stride); + if (_vbuffer_active) { + // Nonindexed, client arrays, individual triangle strips. + unsigned int first_vertex = primitive->get_first_vertex(); + unsigned int start = 0; + for (size_t i = 0; i < ends.size(); i++) { + _vertices_tristrip_pcollector.add_level(ends[i] - start); + _pD3DDevice->DrawPrimitive + (D3DPT_TRIANGLESTRIP, + first_vertex + start, ends[i] - start - 2); + + start = ends[i] + 2; + } - start = ends[i] + 2; + } else { + // Nonindexed, client arrays, individual triangle strips. + CPTA_uchar array_data = _vertex_data->get_array(0)->get_data(); + int stride = _vertex_data->get_format()->get_array(0)->get_stride(); + unsigned int first_vertex = primitive->get_first_vertex(); + + unsigned int start = 0; + for (size_t i = 0; i < ends.size(); i++) { + _vertices_tristrip_pcollector.add_level(ends[i] - start); + _pD3DDevice->DrawPrimitiveUP + (D3DPT_TRIANGLESTRIP, + ends[i] - start - 2, + array_data + (first_vertex + start) * stride, stride); + + start = ends[i] + 2; + } } } } @@ -2861,57 +2943,92 @@ draw_tristrips(const qpGeomTristrips *primitive) { //////////////////////////////////////////////////////////////////// void DXGraphicsStateGuardian8:: draw_trifans(const qpGeomTrifans *primitive) { - int min_vertex = primitive->get_min_vertex(); - int max_vertex = primitive->get_max_vertex(); - D3DFORMAT index_type = get_index_type(primitive->get_index_type()); - - // Send the individual triangle fans. There's no connecting fans - // with degenerate vertices, so no worries about that. CPTA_int ends = primitive->get_ends(); - int index_stride = primitive->get_index_stride(); _primitive_batches_trifan_pcollector.add_level(ends.size()); - qpGeomVertexReader mins(primitive->get_mins(), 0); - qpGeomVertexReader maxs(primitive->get_maxs(), 0); - nassertv(primitive->get_mins()->get_num_rows() == (int)ends.size() && - primitive->get_maxs()->get_num_rows() == (int)ends.size()); - - if (_vbuffer_active) { - IndexBufferContext *ibc = ((qpGeomPrimitive *)primitive)->prepare_now(get_prepared_objects(), this); - nassertv(ibc != (IndexBufferContext *)NULL); - apply_index_buffer(ibc); + if (primitive->is_indexed()) { + int min_vertex = primitive->get_min_vertex(); + int max_vertex = primitive->get_max_vertex(); + D3DFORMAT index_type = get_index_type(primitive->get_index_type()); - unsigned int start = 0; - for (size_t i = 0; i < ends.size(); i++) { - _vertices_trifan_pcollector.add_level(ends[i] - start); - unsigned int min = mins.get_data1i(); - unsigned int max = maxs.get_data1i(); - _pD3DDevice->DrawIndexedPrimitive - (D3DPT_TRIANGLEFAN, - min, max - min + 1, - start, ends[i] - start - 2); + // Send the individual triangle fans. There's no connecting fans + // with degenerate vertices, so no worries about that. + int index_stride = primitive->get_index_stride(); + + qpGeomVertexReader mins(primitive->get_mins(), 0); + qpGeomVertexReader maxs(primitive->get_maxs(), 0); + nassertv(primitive->get_mins()->get_num_rows() == (int)ends.size() && + primitive->get_maxs()->get_num_rows() == (int)ends.size()); + + if (_vbuffer_active) { + // Indexed, vbuffers. + 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_trifan_pcollector.add_level(ends[i] - start); + unsigned int min = mins.get_data1i(); + unsigned int max = maxs.get_data1i(); + _pD3DDevice->DrawIndexedPrimitive + (D3DPT_TRIANGLEFAN, + min, max - min + 1, + start, ends[i] - start - 2); + + start = ends[i]; + } + + } else { + // Indexed, client arrays. + CPTA_uchar array_data = _vertex_data->get_array(0)->get_data(); + int stride = _vertex_data->get_format()->get_array(0)->get_stride(); + CPTA_uchar vertices = primitive->get_data(); + + unsigned int start = 0; + for (size_t i = 0; i < ends.size(); i++) { + _vertices_trifan_pcollector.add_level(ends[i] - start); + unsigned int min = mins.get_data1i(); + unsigned int max = maxs.get_data1i(); + _pD3DDevice->DrawIndexedPrimitiveUP + (D3DPT_TRIANGLEFAN, + min, max - min + 1, + ends[i] - start - 2, + vertices + start * index_stride, index_type, + array_data, stride); + + start = ends[i]; + } } - } else { - CPTA_uchar array_data = _vertex_data->get_array(0)->get_data(); - int stride = _vertex_data->get_format()->get_array(0)->get_stride(); - CPTA_uchar vertices = primitive->get_data(); - - unsigned int start = 0; - for (size_t i = 0; i < ends.size(); i++) { - _vertices_trifan_pcollector.add_level(ends[i] - start); - unsigned int min = mins.get_data1i(); - unsigned int max = maxs.get_data1i(); - _pD3DDevice->DrawIndexedPrimitiveUP - (D3DPT_TRIANGLEFAN, - min, max - min + 1, - ends[i] - start - 2, - vertices + start * index_stride, index_type, - array_data, stride); + if (_vbuffer_active) { + // Nonindexed, vbuffers. + unsigned int start = 0; + for (size_t i = 0; i < ends.size(); i++) { + _vertices_trifan_pcollector.add_level(ends[i] - start); + _pD3DDevice->DrawPrimitive + (D3DPT_TRIANGLEFAN, + start, ends[i] - start - 2); + + start = ends[i]; + } - start = ends[i]; + } else { + // Nonindexed, client arrays. + CPTA_uchar array_data = _vertex_data->get_array(0)->get_data(); + int stride = _vertex_data->get_format()->get_array(0)->get_stride(); + unsigned int first_vertex = primitive->get_first_vertex(); + + unsigned int start = 0; + for (size_t i = 0; i < ends.size(); i++) { + _vertices_trifan_pcollector.add_level(ends[i] - start); + _pD3DDevice->DrawPrimitiveUP + (D3DPT_TRIANGLEFAN, + ends[i] - start - 2, + array_data + (first_vertex + start) * stride, stride); + + start = ends[i]; + } } } } @@ -2925,29 +3042,51 @@ void DXGraphicsStateGuardian8:: draw_lines(const qpGeomLines *primitive) { _vertices_other_pcollector.add_level(primitive->get_num_vertices()); _primitive_batches_other_pcollector.add_level(1); - if (_vbuffer_active) { - IndexBufferContext *ibc = ((qpGeomPrimitive *)primitive)->prepare_now(get_prepared_objects(), this); - nassertv(ibc != (IndexBufferContext *)NULL); - apply_index_buffer(ibc); - _pD3DDevice->DrawIndexedPrimitive - (D3DPT_LINELIST, - primitive->get_min_vertex(), - primitive->get_max_vertex() - primitive->get_min_vertex() + 1, - 0, primitive->get_num_primitives()); + if (primitive->is_indexed()) { + if (_vbuffer_active) { + // Indexed, vbuffers. + IndexBufferContext *ibc = ((qpGeomPrimitive *)primitive)->prepare_now(get_prepared_objects(), this); + nassertv(ibc != (IndexBufferContext *)NULL); + apply_index_buffer(ibc); + + _pD3DDevice->DrawIndexedPrimitive + (D3DPT_LINELIST, + primitive->get_min_vertex(), + primitive->get_max_vertex() - primitive->get_min_vertex() + 1, + 0, primitive->get_num_primitives()); + + } else { + // Indexed, client arrays. + D3DFORMAT index_type = get_index_type(primitive->get_index_type()); + _pD3DDevice->DrawIndexedPrimitiveUP + (D3DPT_LINELIST, + primitive->get_min_vertex(), + primitive->get_max_vertex() - primitive->get_min_vertex() + 1, + primitive->get_num_primitives(), + primitive->get_data(), + index_type, + _vertex_data->get_array(0)->get_data(), + _vertex_data->get_format()->get_array(0)->get_stride()); + } } else { - D3DFORMAT index_type = get_index_type(primitive->get_index_type()); - - _pD3DDevice->DrawIndexedPrimitiveUP - (D3DPT_LINELIST, - primitive->get_min_vertex(), - primitive->get_max_vertex() - primitive->get_min_vertex() + 1, - primitive->get_num_primitives(), - primitive->get_data(), - index_type, - _vertex_data->get_array(0)->get_data(), - _vertex_data->get_format()->get_array(0)->get_stride()); + if (_vbuffer_active) { + // Nonindexed, vbuffers. + _pD3DDevice->DrawPrimitive + (D3DPT_LINELIST, primitive->get_first_vertex(), + primitive->get_num_primitives()); + + } else { + // Nonindexed, client arrays. + int stride = _vertex_data->get_format()->get_array(0)->get_stride(); + unsigned int first_vertex = primitive->get_first_vertex(); + _pD3DDevice->DrawPrimitiveUP + (D3DPT_LINELIST, + primitive->get_num_primitives(), + _vertex_data->get_array(0)->get_data() + stride * first_vertex, + stride); + } } } diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index ace0bace34..a0a123c2d8 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -2489,14 +2489,21 @@ void CLP(GraphicsStateGuardian):: draw_triangles(const qpGeomTriangles *primitive) { _vertices_tri_pcollector.add_level(primitive->get_num_vertices()); _primitive_batches_tri_pcollector.add_level(1); - const unsigned char *client_pointer = setup_primitive(primitive); - _glDrawRangeElements(GL_TRIANGLES, - primitive->get_min_vertex(), - primitive->get_max_vertex(), - primitive->get_num_vertices(), - get_numeric_type(primitive->get_index_type()), - client_pointer); + if (primitive->is_indexed()) { + const unsigned char *client_pointer = setup_primitive(primitive); + + _glDrawRangeElements(GL_TRIANGLES, + primitive->get_min_vertex(), + primitive->get_max_vertex(), + primitive->get_num_vertices(), + get_numeric_type(primitive->get_index_type()), + client_pointer); + } else { + GLP(DrawArrays)(GL_TRIANGLES, + primitive->get_first_vertex(), + primitive->get_num_vertices()); + } report_my_gl_errors(); } @@ -2508,41 +2515,58 @@ draw_triangles(const qpGeomTriangles *primitive) { //////////////////////////////////////////////////////////////////// void CLP(GraphicsStateGuardian):: draw_tristrips(const qpGeomTristrips *primitive) { - const unsigned char *client_pointer = setup_primitive(primitive); - 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()); _primitive_batches_tristrip_pcollector.add_level(1); - _glDrawRangeElements(GL_TRIANGLE_STRIP, - primitive->get_min_vertex(), - primitive->get_max_vertex(), - primitive->get_num_vertices(), - get_numeric_type(primitive->get_index_type()), - client_pointer); + if (primitive->is_indexed()) { + const unsigned char *client_pointer = setup_primitive(primitive); + _glDrawRangeElements(GL_TRIANGLE_STRIP, + primitive->get_min_vertex(), + primitive->get_max_vertex(), + primitive->get_num_vertices(), + get_numeric_type(primitive->get_index_type()), + client_pointer); + } else { + GLP(DrawArrays)(GL_TRIANGLE_STRIP, + primitive->get_first_vertex(), + primitive->get_num_vertices()); + } } else { // Send the individual triangle strips, stepping over the // degenerate vertices. CPTA_int ends = primitive->get_ends(); - int index_stride = primitive->get_index_stride(); - - qpGeomVertexReader mins(primitive->get_mins(), 0); - qpGeomVertexReader maxs(primitive->get_maxs(), 0); - nassertv(primitive->get_mins()->get_num_rows() == (int)ends.size() && - primitive->get_maxs()->get_num_rows() == (int)ends.size()); _primitive_batches_tristrip_pcollector.add_level(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.get_data1i(), maxs.get_data1i(), - ends[i] - start, - get_numeric_type(primitive->get_index_type()), - client_pointer + start * index_stride); - start = ends[i] + 2; + if (primitive->is_indexed()) { + const unsigned char *client_pointer = setup_primitive(primitive); + int index_stride = primitive->get_index_stride(); + qpGeomVertexReader mins(primitive->get_mins(), 0); + qpGeomVertexReader maxs(primitive->get_maxs(), 0); + nassertv(primitive->get_mins()->get_num_rows() == (int)ends.size() && + primitive->get_maxs()->get_num_rows() == (int)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.get_data1i(), maxs.get_data1i(), + ends[i] - start, + get_numeric_type(primitive->get_index_type()), + client_pointer + start * index_stride); + start = ends[i] + 2; + } + } else { + unsigned int start = 0; + int first_vertex = primitive->get_first_vertex(); + for (size_t i = 0; i < ends.size(); i++) { + _vertices_tristrip_pcollector.add_level(ends[i] - start); + GLP(DrawArrays)(GL_TRIANGLE_STRIP, first_vertex + start, + ends[i] - start); + start = ends[i] + 2; + } } } @@ -2556,27 +2580,37 @@ draw_tristrips(const qpGeomTristrips *primitive) { //////////////////////////////////////////////////////////////////// void CLP(GraphicsStateGuardian):: draw_trifans(const qpGeomTrifans *primitive) { - const unsigned char *client_pointer = setup_primitive(primitive); - // Send the individual triangle fans. There's no connecting fans // with degenerate vertices, so no worries about that. CPTA_int ends = primitive->get_ends(); - int index_stride = primitive->get_index_stride(); - - qpGeomVertexReader mins(primitive->get_mins(), 0); - qpGeomVertexReader maxs(primitive->get_maxs(), 0); - nassertv(primitive->get_mins()->get_num_rows() == (int)ends.size() && - primitive->get_maxs()->get_num_rows() == (int)ends.size()); _primitive_batches_trifan_pcollector.add_level(ends.size()); - unsigned int start = 0; - for (size_t i = 0; i < ends.size(); i++) { - _vertices_trifan_pcollector.add_level(ends[i] - start); - _glDrawRangeElements(GL_TRIANGLE_FAN, - mins.get_data1i(), maxs.get_data1i(), ends[i] - start, - get_numeric_type(primitive->get_index_type()), - client_pointer + start * index_stride); - start = ends[i]; + if (primitive->is_indexed()) { + const unsigned char *client_pointer = setup_primitive(primitive); + int index_stride = primitive->get_index_stride(); + qpGeomVertexReader mins(primitive->get_mins(), 0); + qpGeomVertexReader maxs(primitive->get_maxs(), 0); + nassertv(primitive->get_mins()->get_num_rows() == (int)ends.size() && + primitive->get_maxs()->get_num_rows() == (int)ends.size()); + + unsigned int start = 0; + for (size_t i = 0; i < ends.size(); i++) { + _vertices_trifan_pcollector.add_level(ends[i] - start); + _glDrawRangeElements(GL_TRIANGLE_FAN, + mins.get_data1i(), maxs.get_data1i(), ends[i] - start, + get_numeric_type(primitive->get_index_type()), + client_pointer + start * index_stride); + start = ends[i]; + } + } else { + unsigned int start = 0; + int first_vertex = primitive->get_first_vertex(); + for (size_t i = 0; i < ends.size(); i++) { + _vertices_trifan_pcollector.add_level(ends[i] - start); + GLP(DrawArrays)(GL_TRIANGLE_FAN, first_vertex + start, + ends[i] - start); + start = ends[i]; + } } report_my_gl_errors(); @@ -2591,14 +2625,20 @@ void CLP(GraphicsStateGuardian):: draw_lines(const qpGeomLines *primitive) { _vertices_other_pcollector.add_level(primitive->get_num_vertices()); _primitive_batches_other_pcollector.add_level(1); - const unsigned char *client_pointer = setup_primitive(primitive); - _glDrawRangeElements(GL_LINES, - primitive->get_min_vertex(), - primitive->get_max_vertex(), - primitive->get_num_vertices(), - get_numeric_type(primitive->get_index_type()), - client_pointer); + if (primitive->is_indexed()) { + const unsigned char *client_pointer = setup_primitive(primitive); + _glDrawRangeElements(GL_LINES, + primitive->get_min_vertex(), + primitive->get_max_vertex(), + primitive->get_num_vertices(), + get_numeric_type(primitive->get_index_type()), + client_pointer); + } else { + GLP(DrawArrays)(GL_LINES, + primitive->get_first_vertex(), + primitive->get_num_vertices()); + } report_my_gl_errors(); } @@ -2621,14 +2661,20 @@ void CLP(GraphicsStateGuardian):: draw_points(const qpGeomPoints *primitive) { _vertices_other_pcollector.add_level(primitive->get_num_vertices()); _primitive_batches_other_pcollector.add_level(1); - const unsigned char *client_pointer = setup_primitive(primitive); - _glDrawRangeElements(GL_POINTS, - primitive->get_min_vertex(), - primitive->get_max_vertex(), - primitive->get_num_vertices(), - get_numeric_type(primitive->get_index_type()), - client_pointer); + if (primitive->is_indexed()) { + const unsigned char *client_pointer = setup_primitive(primitive); + _glDrawRangeElements(GL_POINTS, + primitive->get_min_vertex(), + primitive->get_max_vertex(), + primitive->get_num_vertices(), + get_numeric_type(primitive->get_index_type()), + client_pointer); + } else { + GLP(DrawArrays)(GL_POINTS, + primitive->get_first_vertex(), + primitive->get_num_vertices()); + } report_my_gl_errors(); } diff --git a/panda/src/gobj/qpgeom.I b/panda/src/gobj/qpgeom.I index 91439937bf..6fc44fddef 100644 --- a/panda/src/gobj/qpgeom.I +++ b/panda/src/gobj/qpgeom.I @@ -70,6 +70,7 @@ get_usage_hint() const { if (!cdata->_got_usage_hint) { CDWriter cdataw(((qpGeom *)this)->_cycler, cdata); ((qpGeom *)this)->reset_usage_hint(cdataw); + return cdataw->_usage_hint; } return cdata->_usage_hint; } diff --git a/panda/src/gobj/qpgeom.cxx b/panda/src/gobj/qpgeom.cxx index a5306f523e..3a8fd5f22f 100644 --- a/panda/src/gobj/qpgeom.cxx +++ b/panda/src/gobj/qpgeom.cxx @@ -200,12 +200,69 @@ offset_vertices(const qpGeomVertexData *data, int offset) { } cdata->_modified = qpGeom::get_next_modified(); - mark_bound_stale(); - reset_geom_rendering(cdata); - nassertv(all_is_valid); } +//////////////////////////////////////////////////////////////////// +// Function: qpGeom::make_nonindexed +// Access: Published +// Description: Converts the geom from indexed to nonindexed by +// duplicating vertices as necessary. If composite_only +// is true, then only composite primitives such as +// trifans and tristrips are converted. Returns the +// number of GeomPrimitive objects converted. +//////////////////////////////////////////////////////////////////// +int qpGeom:: +make_nonindexed(bool composite_only) { + int num_changed = 0; + + clear_cache(); + CDWriter cdata(_cycler); + CPT(qpGeomVertexData) orig_data = cdata->_data; + PT(qpGeomVertexData) new_data = new qpGeomVertexData(*cdata->_data); + new_data->clear_rows(); + +#ifndef NDEBUG + bool all_is_valid = true; +#endif + Primitives::iterator pi; + Primitives new_prims; + new_prims.reserve(cdata->_primitives.size()); + for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) { + PT(qpGeomPrimitive) primitive = (*pi)->make_copy(); + new_prims.push_back(primitive); + + if (primitive->is_indexed() && + (primitive->is_composite() || !composite_only)) { + primitive->make_nonindexed(new_data, orig_data); + ++num_changed; + } else { + // If it's a simple primitive, pack it anyway, so it can share + // the same GeomVertexData. + primitive->pack_vertices(new_data, orig_data); + } + +#ifndef NDEBUG + if (!primitive->check_valid(new_data)) { + all_is_valid = false; + } +#endif + } + + nassertr(all_is_valid, 0); + + if (num_changed != 0) { + // If any at all were changed, then keep the result (otherwise, + // discard it, since we might have de-optimized the indexed + // geometry a bit). + cdata->_data = new_data; + cdata->_primitives.swap(new_prims); + cdata->_modified = qpGeom::get_next_modified(); + } + + return num_changed; +} + //////////////////////////////////////////////////////////////////// // Function: qpGeom::set_primitive // Access: Published diff --git a/panda/src/gobj/qpgeom.h b/panda/src/gobj/qpgeom.h index 458d5871e5..ea503ec99e 100644 --- a/panda/src/gobj/qpgeom.h +++ b/panda/src/gobj/qpgeom.h @@ -78,6 +78,7 @@ PUBLISHED: PT(qpGeomVertexData) modify_vertex_data(); void set_vertex_data(const qpGeomVertexData *data); void offset_vertices(const qpGeomVertexData *data, int offset); + int make_nonindexed(bool composite_only); INLINE int get_num_primitives() const; INLINE const qpGeomPrimitive *get_primitive(int i) const; diff --git a/panda/src/gobj/qpgeomLines.cxx b/panda/src/gobj/qpgeomLines.cxx index 0fbe41ab07..17ba50c15a 100644 --- a/panda/src/gobj/qpgeomLines.cxx +++ b/panda/src/gobj/qpgeomLines.cxx @@ -124,23 +124,38 @@ draw(GraphicsStateGuardianBase *gsg) const { CPT(qpGeomVertexArrayData) qpGeomLines:: rotate_impl() const { // To rotate lines, we just move reverse the pairs of vertices. - CPT(qpGeomVertexArrayData) vertices = get_vertices(); + int num_vertices = get_num_vertices(); + + PT(qpGeomVertexArrayData) new_vertices = make_index_data(); + new_vertices->set_num_rows(num_vertices); - PT(qpGeomVertexArrayData) new_vertices = - new qpGeomVertexArrayData(*vertices); - qpGeomVertexReader from(vertices, 0); - qpGeomVertexWriter to(new_vertices, 0); + if (is_indexed()) { + CPT(qpGeomVertexArrayData) vertices = get_vertices(); + qpGeomVertexReader from(vertices, 0); + qpGeomVertexWriter to(new_vertices, 0); - int num_vertices = vertices->get_num_rows(); - - for (int begin = 0; begin < num_vertices; begin += 2) { - from.set_row(begin + 1); - to.set_data1i(from.get_data1i()); - from.set_row(begin); - to.set_data1i(from.get_data1i()); - } + for (int begin = 0; begin < num_vertices; begin += 2) { + from.set_row(begin + 1); + to.set_data1i(from.get_data1i()); + from.set_row(begin); + to.set_data1i(from.get_data1i()); + } - nassertr(to.is_at_end(), NULL); + nassertr(to.is_at_end(), NULL); + + } else { + // Nonindexed case. + int first_vertex = get_first_vertex(); + qpGeomVertexWriter to(new_vertices, 0); + + for (int begin = 0; begin < num_vertices; begin += 2) { + to.set_data1i(begin + 1 + first_vertex); + to.set_data1i(begin + first_vertex); + } + + nassertr(to.is_at_end(), NULL); + } + return new_vertices; } diff --git a/panda/src/gobj/qpgeomLinestrips.cxx b/panda/src/gobj/qpgeomLinestrips.cxx index f3a9726391..d519d49858 100644 --- a/panda/src/gobj/qpgeomLinestrips.cxx +++ b/panda/src/gobj/qpgeomLinestrips.cxx @@ -166,25 +166,45 @@ decompose_impl() const { CPT(qpGeomVertexArrayData) qpGeomLinestrips:: rotate_impl() const { // To rotate a line strip, we just reverse the vertices. - CPT(qpGeomVertexArrayData) vertices = get_vertices(); CPTA_int ends = get_ends(); - PT(qpGeomVertexArrayData) new_vertices = - new qpGeomVertexArrayData(*vertices); - qpGeomVertexReader from(vertices, 0); - qpGeomVertexWriter to(new_vertices, 0); + PT(qpGeomVertexArrayData) new_vertices = make_index_data(); + new_vertices->set_num_rows(get_num_vertices()); - int begin = 0; - CPTA_int::const_iterator ei; - for (ei = ends.begin(); ei != ends.end(); ++ei) { - int end = (*ei); - for (int vi = end - 1; vi >= begin; --vi) { - from.set_row(vi); - to.set_data1i(from.get_data1i()); + if (is_indexed()) { + CPT(qpGeomVertexArrayData) vertices = get_vertices(); + qpGeomVertexReader from(vertices, 0); + qpGeomVertexWriter to(new_vertices, 0); + + int begin = 0; + CPTA_int::const_iterator ei; + for (ei = ends.begin(); ei != ends.end(); ++ei) { + int end = (*ei); + for (int vi = end - 1; vi >= begin; --vi) { + from.set_row(vi); + to.set_data1i(from.get_data1i()); + } + begin = end; } - begin = end; - } + + nassertr(to.is_at_end(), NULL); - nassertr(to.is_at_end(), NULL); + } else { + // Nonindexed case. + int first_vertex = get_first_vertex(); + qpGeomVertexWriter to(new_vertices, 0); + + int begin = 0; + CPTA_int::const_iterator ei; + for (ei = ends.begin(); ei != ends.end(); ++ei) { + int end = (*ei); + for (int vi = end - 1; vi >= begin; --vi) { + to.set_data1i(vi + first_vertex); + } + begin = end; + } + + nassertr(to.is_at_end(), NULL); + } return new_vertices; } diff --git a/panda/src/gobj/qpgeomPrimitive.I b/panda/src/gobj/qpgeomPrimitive.I index 0556ec6c1b..281d77b959 100644 --- a/panda/src/gobj/qpgeomPrimitive.I +++ b/panda/src/gobj/qpgeomPrimitive.I @@ -65,18 +65,8 @@ set_shade_model(qpGeomPrimitive::ShadeModel shade_model) { //////////////////////////////////////////////////////////////////// INLINE qpGeomPrimitive::UsageHint qpGeomPrimitive:: get_usage_hint() const { - return get_vertices()->get_usage_hint(); -} - -//////////////////////////////////////////////////////////////////// -// Function: qpGeomPrimitive::set_usage_hint -// Access: Published -// Description: Changes the UsageHint hint for this primitive. See -// get_usage_hint(). -//////////////////////////////////////////////////////////////////// -INLINE void qpGeomPrimitive:: -set_usage_hint(qpGeomPrimitive::UsageHint usage_hint) { - modify_vertices()->set_usage_hint(usage_hint); + CDReader cdata(_cycler); + return cdata->_usage_hint; } //////////////////////////////////////////////////////////////////// @@ -91,6 +81,36 @@ get_index_type() const { return cdata->_index_type; } +//////////////////////////////////////////////////////////////////// +// Function: qpGeomPrimitive::is_composite +// Access: Published +// Description: Returns true if the primitive is a composite +// primitive such as a tristrip or trifan, or false if +// it is a fundamental primitive such as a collection of +// triangles. +//////////////////////////////////////////////////////////////////// +INLINE bool qpGeomPrimitive:: +is_composite() const { + return (get_num_vertices_per_primitive() == 0); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomPrimitive::is_indexed +// Access: Published +// Description: Returns true if the primitive is indexed, false +// otherwise. An indexed primitive stores a table of +// index numbers into its GeomVertexData, so that it can +// reference the vertices in any order. A nonindexed +// primitive, on the other hand, stores only the first +// vertex number and number of vertices used, so that it +// can only reference the vertices consecutively. +//////////////////////////////////////////////////////////////////// +INLINE bool qpGeomPrimitive:: +is_indexed() const { + CDReader cdata(_cycler); + return (cdata->_vertices != (qpGeomVertexArrayData *)NULL); +} + //////////////////////////////////////////////////////////////////// // Function: qpGeomPrimitive::get_num_vertices // Access: Published @@ -100,7 +120,11 @@ get_index_type() const { INLINE int qpGeomPrimitive:: get_num_vertices() const { CDReader cdata(_cycler); - return cdata->_vertices->get_num_rows(); + if (cdata->_vertices == (qpGeomVertexArrayData *)NULL) { + return cdata->_num_vertices; + } else { + return cdata->_vertices->get_num_rows(); + } } //////////////////////////////////////////////////////////////////// @@ -157,6 +181,7 @@ get_min_vertex() const { ((qpGeomPrimitive *)this)->recompute_minmax(cdataw); return cdataw->_min_vertex; } + return cdata->_min_vertex; } @@ -206,7 +231,8 @@ get_modified() const { // 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 +// application code can read it directly. This might +// return NULL if the primitive is nonindexed. Do not // attempt to modify the returned array; use // modify_vertices() or set_vertices() for this. //////////////////////////////////////////////////////////////////// @@ -225,6 +251,7 @@ get_vertices() const { //////////////////////////////////////////////////////////////////// INLINE int qpGeomPrimitive:: get_index_stride() const { + nassertr(is_indexed(), 0); return get_vertices()->get_array_format()->get_stride(); } @@ -236,6 +263,7 @@ get_index_stride() const { //////////////////////////////////////////////////////////////////// INLINE CPTA_uchar qpGeomPrimitive:: get_data() const { + nassertr(is_indexed(), CPTA_uchar()); return get_vertices()->get_data(); } @@ -270,6 +298,7 @@ get_ends() const { //////////////////////////////////////////////////////////////////// INLINE const qpGeomVertexArrayData *qpGeomPrimitive:: get_mins() const { + nassertr(is_indexed(), NULL); CDReader cdata(_cycler); if (!cdata->_got_minmax) { CDWriter cdataw(((qpGeomPrimitive *)this)->_cycler, cdata); @@ -292,6 +321,7 @@ get_mins() const { //////////////////////////////////////////////////////////////////// INLINE const qpGeomVertexArrayData *qpGeomPrimitive:: get_maxs() const { + nassertr(is_indexed(), NULL); CDReader cdata(_cycler); if (!cdata->_got_minmax) { CDWriter cdataw(((qpGeomPrimitive *)this)->_cycler, cdata); @@ -301,6 +331,29 @@ get_maxs() const { return cdata->_maxs; } +//////////////////////////////////////////////////////////////////// +// Function: qpGeomPrimitive::get_index_format +// Access: Protected +// Description: Returns a registered format appropriate for using to +// store the index table. +//////////////////////////////////////////////////////////////////// +INLINE CPT(qpGeomVertexArrayFormat) qpGeomPrimitive:: +get_index_format() const { + return qpGeomVertexArrayFormat::register_format + (new qpGeomVertexArrayFormat(InternalName::get_index(), 1, + get_index_type(), C_index)); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomPrimitive::make_index_data +// Access: Protected +// Description: Creates and returns a new, empty index table. +//////////////////////////////////////////////////////////////////// +INLINE PT(qpGeomVertexArrayData) qpGeomPrimitive:: +make_index_data() const { + return new qpGeomVertexArrayData(get_index_format(), get_usage_hint()); +} + //////////////////////////////////////////////////////////////////// // Function: qpGeomPrimitive::CData::Constructor // Access: Public @@ -309,7 +362,10 @@ get_maxs() const { INLINE qpGeomPrimitive::CData:: CData() : _shade_model(SM_smooth), + _first_vertex(0), + _num_vertices(0), _index_type(NT_uint16), + _usage_hint(UH_unspecified), _got_minmax(true), _min_vertex(0), _max_vertex(0) @@ -324,7 +380,10 @@ CData() : INLINE qpGeomPrimitive::CData:: CData(const qpGeomPrimitive::CData ©) : _shade_model(copy._shade_model), + _first_vertex(copy._first_vertex), + _num_vertices(copy._num_vertices), _index_type(copy._index_type), + _usage_hint(copy._usage_hint), _vertices(copy._vertices), _ends(copy._ends), _mins(copy._mins), diff --git a/panda/src/gobj/qpgeomPrimitive.cxx b/panda/src/gobj/qpgeomPrimitive.cxx index 27f54d19bc..76c5ca0563 100644 --- a/panda/src/gobj/qpgeomPrimitive.cxx +++ b/panda/src/gobj/qpgeomPrimitive.cxx @@ -53,13 +53,7 @@ qpGeomPrimitive() { qpGeomPrimitive:: qpGeomPrimitive(qpGeomPrimitive::UsageHint usage_hint) { CDWriter cdata(_cycler); - - CPT(qpGeomVertexArrayFormat) new_format = - qpGeomVertexArrayFormat::register_format - (new qpGeomVertexArrayFormat(InternalName::get_index(), 1, - cdata->_index_type, C_index)); - - cdata->_vertices = new qpGeomVertexArrayData(new_format, usage_hint); + cdata->_usage_hint = usage_hint; } //////////////////////////////////////////////////////////////////// @@ -97,6 +91,27 @@ get_geom_rendering() const { return 0; } +//////////////////////////////////////////////////////////////////// +// Function: qpGeomPrimitive::set_usage_hint +// Access: Published +// Description: Changes the UsageHint hint for this primitive. See +// get_usage_hint(). +//////////////////////////////////////////////////////////////////// +void qpGeomPrimitive:: +set_usage_hint(qpGeomPrimitive::UsageHint usage_hint) { + CDWriter cdata(_cycler); + cdata->_usage_hint = usage_hint; + + if (cdata->_vertices != (qpGeomVertexArrayData *)NULL) { + if (cdata->_vertices->get_ref_count() > 1) { + cdata->_vertices = new qpGeomVertexArrayData(*cdata->_vertices); + } + + cdata->_modified = qpGeom::get_next_modified(); + cdata->_usage_hint = usage_hint; + } +} + //////////////////////////////////////////////////////////////////// // Function: qpGeomPrimitive::set_index_type // Access: Published @@ -108,23 +123,45 @@ void qpGeomPrimitive:: set_index_type(qpGeomPrimitive::NumericType index_type) { CDWriter cdata(_cycler); cdata->_index_type = index_type; - - CPT(qpGeomVertexArrayFormat) new_format = - qpGeomVertexArrayFormat::register_format - (new qpGeomVertexArrayFormat(InternalName::get_index(), 1, index_type, - C_index)); - if (cdata->_vertices->get_array_format() != new_format) { - PT(qpGeomVertexArrayData) new_vertices = - new qpGeomVertexArrayData(new_format, cdata->_vertices->get_usage_hint()); - qpGeomVertexReader from(cdata->_vertices, 0); - qpGeomVertexWriter to(new_vertices, 0); + if (cdata->_vertices != (qpGeomVertexArrayData *)NULL) { + CPT(qpGeomVertexArrayFormat) new_format = get_index_format(); + + if (cdata->_vertices->get_array_format() != new_format) { + PT(qpGeomVertexArrayData) new_vertices = make_index_data(); + new_vertices->set_num_rows(cdata->_vertices->get_num_rows()); - while (!from.is_at_end()) { - to.add_data1i(from.get_data1i()); + qpGeomVertexReader from(cdata->_vertices, 0); + qpGeomVertexWriter to(new_vertices, 0); + + while (!from.is_at_end()) { + to.set_data1i(from.get_data1i()); + } + cdata->_vertices = new_vertices; + cdata->_got_minmax = false; } - cdata->_vertices = new_vertices; - cdata->_got_minmax = false; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomPrimitive::get_first_vertex +// Access: Published +// Description: Returns the first vertex number referenced by the +// primitive. This is particularly important in the +// case of a nonindexed primitive, in which case +// get_first_vertex() and get_num_vertices() completely +// define the extent of the vertex range. +//////////////////////////////////////////////////////////////////// +int qpGeomPrimitive:: +get_first_vertex() const { + CDReader cdata(_cycler); + if (cdata->_vertices == (qpGeomVertexArrayData *)NULL) { + return cdata->_first_vertex; + } else if (cdata->_vertices->get_num_rows() == 0) { + return 0; + } else { + qpGeomVertexReader index(cdata->_vertices, 0); + return index.get_data1i(); } } @@ -136,11 +173,19 @@ set_index_type(qpGeomPrimitive::NumericType index_type) { int qpGeomPrimitive:: get_vertex(int i) const { CDReader cdata(_cycler); - nassertr(i >= 0 && i < (int)cdata->_vertices->get_num_rows(), -1); - qpGeomVertexReader index(cdata->_vertices, 0); - index.set_row(i); - return index.get_data1i(); + if (cdata->_vertices != (qpGeomVertexArrayData *)NULL) { + // The indexed case. + nassertr(i >= 0 && i < (int)cdata->_vertices->get_num_rows(), -1); + + qpGeomVertexReader index(cdata->_vertices, 0); + index.set_row(i); + return index.get_data1i(); + + } else { + // The nonindexed case. + return cdata->_first_vertex + i; + } } //////////////////////////////////////////////////////////////////// @@ -159,12 +204,33 @@ add_vertex(int vertex) { int num_primitives = get_num_primitives(); if (num_primitives > 0 && - (int)cdata->_vertices->get_num_rows() == get_primitive_end(num_primitives - 1)) { + requires_unused_vertices() && + get_num_vertices() == get_primitive_end(num_primitives - 1)) { // If we are beginning a new primitive, give the derived class a // chance to insert some degenerate vertices. + if (cdata->_vertices == (qpGeomVertexArrayData *)NULL) { + do_make_indexed(cdata); + } append_unused_vertices(cdata->_vertices, vertex); } + if (cdata->_vertices == (qpGeomVertexArrayData *)NULL) { + // The nonindexed case. We can keep the primitive nonindexed only + // if the vertex number happens to be the next available vertex. + if (cdata->_num_vertices == 0) { + cdata->_first_vertex = vertex; + cdata->_num_vertices = 1; + return; + + } else if (vertex == cdata->_first_vertex + cdata->_num_vertices) { + ++cdata->_num_vertices; + return; + } + + // Otherwise, we need to suddenly become an indexed primitive. + do_make_indexed(cdata); + } + qpGeomVertexWriter index(cdata->_vertices, 0); index.set_row(cdata->_vertices->get_num_rows()); @@ -191,12 +257,32 @@ add_consecutive_vertices(int start, int num_vertices) { int num_primitives = get_num_primitives(); if (num_primitives > 0 && - (int)cdata->_vertices->get_num_rows() == 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 // chance to insert some degenerate vertices. + if (cdata->_vertices == (qpGeomVertexArrayData *)NULL) { + do_make_indexed(cdata); + } append_unused_vertices(cdata->_vertices, start); } + if (cdata->_vertices == (qpGeomVertexArrayData *)NULL) { + // The nonindexed case. We can keep the primitive nonindexed only + // if the vertex number happens to be the next available vertex. + if (cdata->_num_vertices == 0) { + cdata->_first_vertex = start; + cdata->_num_vertices = num_vertices; + return; + + } else if (start == cdata->_first_vertex + cdata->_num_vertices) { + cdata->_num_vertices += num_vertices; + return; + } + + // Otherwise, we need to suddenly become an indexed primitive. + do_make_indexed(cdata); + } + qpGeomVertexWriter index(cdata->_vertices, 0); index.set_row(cdata->_vertices->get_num_rows()); @@ -247,14 +333,14 @@ close_primitive() { #ifndef NDEBUG int num_added; if (cdata->_ends.empty()) { - num_added = (int)cdata->_vertices->get_num_rows(); + num_added = get_num_vertices(); } else { - num_added = (int)cdata->_vertices->get_num_rows() - cdata->_ends.back(); + num_added = get_num_vertices() - cdata->_ends.back(); num_added -= get_num_unused_vertices_per_primitive(); } nassertr(num_added >= get_min_num_vertices_per_primitive(), false); #endif - cdata->_ends.push_back((int)cdata->_vertices->get_num_rows()); + cdata->_ends.push_back(get_num_vertices()); } else { #ifndef NDEBUG @@ -264,7 +350,7 @@ close_primitive() { 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->get_num_rows(); + int num_vertices = get_num_vertices(); nassertr((num_vertices + num_unused_vertices_per_primitive) % (num_vertices_per_primitive + num_unused_vertices_per_primitive) == 0, false) #endif } @@ -283,8 +369,9 @@ close_primitive() { void qpGeomPrimitive:: clear_vertices() { CDWriter cdata(_cycler); - cdata->_vertices = new qpGeomVertexArrayData - (cdata->_vertices->get_array_format(), cdata->_vertices->get_usage_hint()); + cdata->_first_vertex = 0; + cdata->_num_vertices = 0; + cdata->_vertices.clear(); cdata->_ends.clear(); cdata->_mins.clear(); cdata->_maxs.clear(); @@ -300,12 +387,103 @@ clear_vertices() { //////////////////////////////////////////////////////////////////// void qpGeomPrimitive:: offset_vertices(int offset) { - qpGeomVertexRewriter index(modify_vertices(), 0); - while (!index.is_at_end()) { - index.set_data1i(index.get_data1i() + offset); + if (is_indexed()) { + qpGeomVertexRewriter index(modify_vertices(), 0); + while (!index.is_at_end()) { + index.set_data1i(index.get_data1i() + offset); + } + + } else { + CDWriter cdata(_cycler); + cdata->_first_vertex += offset; + cdata->_modified = qpGeom::get_next_modified(); } } +//////////////////////////////////////////////////////////////////// +// Function: qpGeomPrimitive::make_nonindexed +// Access: Published +// Description: Converts the primitive from indexed to nonindexed by +// duplicating vertices as necessary into the indicated +// dest GeomVertexData. +//////////////////////////////////////////////////////////////////// +void qpGeomPrimitive:: +make_nonindexed(qpGeomVertexData *dest, const qpGeomVertexData *source) { + int num_vertices = get_num_vertices(); + int dest_start = dest->get_num_rows(); + + dest->set_num_rows(dest_start + num_vertices); + for (int i = 0; i < num_vertices; ++i) { + int v = get_vertex(i); + dest->copy_row_from(dest_start + i, source, v); + } + + set_nonindexed_vertices(dest_start, num_vertices); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomPrimitive::pack_vertices +// Access: Published +// Description: Packs the vertices used by the primitive from the +// indicated source array onto the end of the indicated +// destination array. +//////////////////////////////////////////////////////////////////// +void qpGeomPrimitive:: +pack_vertices(qpGeomVertexData *dest, const qpGeomVertexData *source) { + if (!is_indexed()) { + // If the primitive is nonindexed, packing is the same as + // converting (again) to nonindexed. + make_nonindexed(dest, source); + + } else { + // The indexed case: build up a new index as we go. + CPT(qpGeomVertexArrayData) orig_vertices = get_vertices(); + PT(qpGeomVertexArrayData) new_vertices = make_index_data(); + qpGeomVertexWriter index(new_vertices, 0); + typedef pmap CopiedIndices; + CopiedIndices copied_indices; + + int num_vertices = get_num_vertices(); + int dest_start = dest->get_num_rows(); + + for (int i = 0; i < num_vertices; ++i) { + int v = get_vertex(i); + + // Try to add the relation { v : size() }. If that succeeds, + // great; if it doesn't, look up whatever we previously added + // for v. + pair result = + copied_indices.insert(CopiedIndices::value_type(v, (int)copied_indices.size())); + int v2 = (*result.first).second + dest_start; + index.add_data1i(v2); + + if (result.second) { + // This is the first time we've seen vertex v. + dest->copy_row_from(v2, source, v); + } + } + + set_vertices(new_vertices); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomPrimitive::make_indexed +// Access: Published +// Description: Converts the primitive from nonindexed form to +// indexed form. This will simply create an index table +// that is numbered consecutively from +// get_first_vertex(); it does not automatically +// collapse together identical vertices that may have +// been split apart by a previous call to +// make_nonindexed(). +//////////////////////////////////////////////////////////////////// +void qpGeomPrimitive:: +make_indexed() { + CDWriter cdata(_cycler); + do_make_indexed(cdata); +} + //////////////////////////////////////////////////////////////////// // Function: qpGeomPrimitive::get_num_primitives // Access: Published @@ -326,7 +504,7 @@ get_num_primitives() const { } else { // This is a simple primitive type like a triangle: each primitive // uses the same number of vertices. - return ((int)cdata->_vertices->get_num_rows() / num_vertices_per_primitive); + return (get_num_vertices() / num_vertices_per_primitive); } } @@ -431,12 +609,16 @@ get_primitive_num_vertices(int n) const { //////////////////////////////////////////////////////////////////// int qpGeomPrimitive:: get_primitive_min_vertex(int n) const { - CDReader cdata(_cycler); - nassertr(n >= 0 && n < (int)cdata->_mins->get_num_rows(), -1); + if (is_indexed()) { + CPT(qpGeomVertexArrayData) mins = get_mins(); + nassertr(n >= 0 && n < mins->get_num_rows(), -1); - qpGeomVertexReader index(cdata->_mins, 0); - index.set_row(n); - return index.get_data1i(); + qpGeomVertexReader index(mins, 0); + index.set_row(n); + return index.get_data1i(); + } else { + return get_primitive_start(n); + } } //////////////////////////////////////////////////////////////////// @@ -447,12 +629,16 @@ get_primitive_min_vertex(int n) const { //////////////////////////////////////////////////////////////////// int qpGeomPrimitive:: get_primitive_max_vertex(int n) const { - CDReader cdata(_cycler); - nassertr(n >= 0 && n < (int)cdata->_maxs->get_num_rows(), -1); + if (is_indexed()) { + CPT(qpGeomVertexArrayData) maxs = get_maxs(); + nassertr(n >= 0 && n < maxs->get_num_rows(), -1); - qpGeomVertexReader index(cdata->_maxs, 0); - index.set_row(n); - return index.get_data1i(); + qpGeomVertexReader index(maxs, 0); + index.set_row(n); + return index.get_data1i(); + } else { + return get_primitive_end(n) - 1; + } } //////////////////////////////////////////////////////////////////// @@ -520,8 +706,12 @@ rotate() const { int qpGeomPrimitive:: get_num_bytes() const { CDReader cdata(_cycler); - return (cdata->_vertices->get_data_size_bytes() + - cdata->_ends.size() * sizeof(int) + sizeof(qpGeomPrimitive)); + int num_bytes = cdata->_ends.size() * sizeof(int) + sizeof(qpGeomPrimitive); + if (cdata->_vertices != (qpGeomVertexArrayData *)NULL) { + num_bytes += cdata->_vertices->get_data_size_bytes(); + } + + return num_bytes; } //////////////////////////////////////////////////////////////////// @@ -557,7 +747,13 @@ output(ostream &out) const { void qpGeomPrimitive:: write(ostream &out, int indent_level) const { indent(out, indent_level) - << get_type() << ":\n"; + << get_type(); + if (is_indexed()) { + out << " (indexed)"; + } else { + out << " (nonindexed)"; + } + out << ":\n"; int num_primitives = get_num_primitives(); int num_vertices = get_num_vertices(); int num_unused_vertices_per_primitive = get_num_unused_vertices_per_primitive(); @@ -590,10 +786,18 @@ write(ostream &out, int indent_level) const { // 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. +// +// If this is called on a nonindexed primitive, it will +// implicitly be converted to an indexed primitive. //////////////////////////////////////////////////////////////////// qpGeomVertexArrayData *qpGeomPrimitive:: modify_vertices() { CDWriter cdata(_cycler); + + if (cdata->_vertices == (qpGeomVertexArrayData *)NULL) { + do_make_indexed(cdata); + } + if (cdata->_vertices->get_ref_count() > 1) { cdata->_vertices = new qpGeomVertexArrayData(*cdata->_vertices); } @@ -619,6 +823,24 @@ set_vertices(const qpGeomVertexArrayData *vertices) { cdata->_got_minmax = false; } +//////////////////////////////////////////////////////////////////// +// Function: qpGeomPrimitive::set_nonindexed_vertices +// Access: Public +// Description: Sets the primitive up as a nonindexed primitive, +// using the indicated vertex range. +//////////////////////////////////////////////////////////////////// +void qpGeomPrimitive:: +set_nonindexed_vertices(int first_vertex, int num_vertices) { + CDWriter cdata(_cycler); + cdata->_vertices = (qpGeomVertexArrayData *)NULL; + cdata->_first_vertex = first_vertex; + cdata->_num_vertices = num_vertices; + + cdata->_modified = qpGeom::get_next_modified(); + cdata->_got_minmax = false; + recompute_minmax(cdata); +} + //////////////////////////////////////////////////////////////////// // Function: qpGeomPrimitive::modify_ends // Access: Public @@ -847,42 +1069,85 @@ calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point, CDReader cdata(_cycler); - qpGeomVertexReader index(cdata->_vertices, 0); - - if (got_mat) { - while (!index.is_at_end()) { - reader.set_row(index.get_data1i()); - const LVecBase3f &vertex = reader.get_data3f(); - - if (found_any) { - min_point.set(min(min_point[0], vertex[0]), - min(min_point[1], vertex[1]), - min(min_point[2], vertex[2])); - max_point.set(max(max_point[0], vertex[0]), - max(max_point[1], vertex[1]), - max(max_point[2], vertex[2])); - } else { - min_point = vertex; - max_point = vertex; - found_any = true; + if (cdata->_vertices == (qpGeomVertexArrayData *)NULL) { + // Nonindexed case. + if (got_mat) { + for (int i = 0; i < cdata->_num_vertices; i++) { + reader.set_row(cdata->_first_vertex + i); + const LVecBase3f &vertex = reader.get_data3f(); + + if (found_any) { + min_point.set(min(min_point[0], vertex[0]), + min(min_point[1], vertex[1]), + min(min_point[2], vertex[2])); + max_point.set(max(max_point[0], vertex[0]), + max(max_point[1], vertex[1]), + max(max_point[2], vertex[2])); + } else { + min_point = vertex; + max_point = vertex; + found_any = true; + } + } + } else { + for (int i = 0; i < cdata->_num_vertices; i++) { + reader.set_row(cdata->_first_vertex + i); + LPoint3f vertex = mat.xform_point(reader.get_data3f()); + + if (found_any) { + min_point.set(min(min_point[0], vertex[0]), + min(min_point[1], vertex[1]), + min(min_point[2], vertex[2])); + max_point.set(max(max_point[0], vertex[0]), + max(max_point[1], vertex[1]), + max(max_point[2], vertex[2])); + } else { + min_point = vertex; + max_point = vertex; + found_any = true; + } } } + } else { - while (!index.is_at_end()) { - reader.set_row(index.get_data1i()); - LPoint3f vertex = mat.xform_point(reader.get_data3f()); - - if (found_any) { - min_point.set(min(min_point[0], vertex[0]), - min(min_point[1], vertex[1]), - min(min_point[2], vertex[2])); - max_point.set(max(max_point[0], vertex[0]), - max(max_point[1], vertex[1]), - max(max_point[2], vertex[2])); - } else { - min_point = vertex; - max_point = vertex; - found_any = true; + // Indexed case. + qpGeomVertexReader index(cdata->_vertices, 0); + + if (got_mat) { + while (!index.is_at_end()) { + reader.set_row(index.get_data1i()); + const LVecBase3f &vertex = reader.get_data3f(); + + if (found_any) { + min_point.set(min(min_point[0], vertex[0]), + min(min_point[1], vertex[1]), + min(min_point[2], vertex[2])); + max_point.set(max(max_point[0], vertex[0]), + max(max_point[1], vertex[1]), + max(max_point[2], vertex[2])); + } else { + min_point = vertex; + max_point = vertex; + found_any = true; + } + } + } else { + while (!index.is_at_end()) { + reader.set_row(index.get_data1i()); + LPoint3f vertex = mat.xform_point(reader.get_data3f()); + + if (found_any) { + min_point.set(min(min_point[0], vertex[0]), + min(min_point[1], vertex[1]), + min(min_point[2], vertex[2])); + max_point.set(max(max_point[0], vertex[0]), + max(max_point[1], vertex[1]), + max(max_point[2], vertex[2])); + } else { + min_point = vertex; + max_point = vertex; + found_any = true; + } } } } @@ -919,6 +1184,17 @@ rotate_impl() const { return NULL; } +//////////////////////////////////////////////////////////////////// +// Function: qpGeomPrimitive::requires_unused_vertices +// Access: Protected, Virtual +// Description: Should be redefined to return true in any primitive +// that implements append_unused_vertices(). +//////////////////////////////////////////////////////////////////// +bool qpGeomPrimitive:: +requires_unused_vertices() const { + return false; +} + //////////////////////////////////////////////////////////////////// // Function: qpGeomPrimitive::append_unused_vertices // Access: Protected, Virtual @@ -927,6 +1203,9 @@ rotate_impl() const { // vertices between primitives, if the primitive type // requires that. The second parameter is the first // vertex that begins the new primitive. +// +// This method is only called if +// requires_unused_vertices(), above, returns true. //////////////////////////////////////////////////////////////////// void qpGeomPrimitive:: append_unused_vertices(qpGeomVertexArrayData *, int) { @@ -940,7 +1219,16 @@ append_unused_vertices(qpGeomVertexArrayData *, int) { //////////////////////////////////////////////////////////////////// void qpGeomPrimitive:: recompute_minmax(qpGeomPrimitive::CDWriter &cdata) { - if (cdata->_vertices->get_num_rows() == 0) { + if (cdata->_vertices == (qpGeomVertexArrayData *)NULL) { + // In the nonindexed case, we don't need to do much (the + // minmax is trivial). + cdata->_min_vertex = cdata->_first_vertex; + cdata->_max_vertex = cdata->_first_vertex + cdata->_num_vertices - 1; + cdata->_mins.clear(); + cdata->_maxs.clear(); + + } else if (get_num_vertices() == 0) { + // Or if we don't have any vertices, the minmax is also trivial. cdata->_min_vertex = 0; cdata->_max_vertex = 0; cdata->_mins.clear(); @@ -951,10 +1239,8 @@ recompute_minmax(qpGeomPrimitive::CDWriter &cdata) { // the minmax of each primitive (as well as the overall minmax). qpGeomVertexReader index(cdata->_vertices, 0); - cdata->_mins = new qpGeomVertexArrayData - (cdata->_vertices->get_array_format(), UH_unspecified); - cdata->_maxs = new qpGeomVertexArrayData - (cdata->_vertices->get_array_format(), UH_unspecified); + cdata->_mins = make_index_data(); + cdata->_maxs = make_index_data(); qpGeomVertexWriter mins(cdata->_mins, 0); qpGeomVertexWriter maxs(cdata->_maxs, 0); @@ -1014,6 +1300,22 @@ recompute_minmax(qpGeomPrimitive::CDWriter &cdata) { cdata->_got_minmax = true; } +//////////////////////////////////////////////////////////////////// +// Function: qpGeomPrimitive::do_make_indexed +// Access: Private +// Description: The private implementation of make_indexed(). +//////////////////////////////////////////////////////////////////// +void qpGeomPrimitive:: +do_make_indexed(qpGeomPrimitive::CDWriter &cdata) { + if (cdata->_vertices == (qpGeomVertexArrayData *)NULL) { + cdata->_vertices = make_index_data(); + qpGeomVertexWriter index(cdata->_vertices, 0); + for (int i = 0; i < cdata->_num_vertices; ++i) { + index.add_data1i(i + cdata->_first_vertex); + } + } +} + //////////////////////////////////////////////////////////////////// // Function: qpGeomPrimitive::write_datagram // Access: Public, Virtual @@ -1027,6 +1329,23 @@ write_datagram(BamWriter *manager, Datagram &dg) { manager->write_cdata(dg, _cycler); } +//////////////////////////////////////////////////////////////////// +// Function: qpGeomPrimitive::finalize +// Access: Public, Virtual +// Description: Called by the BamReader to perform any final actions +// needed for setting up the object after all objects +// have been read and all pointers have been completed. +//////////////////////////////////////////////////////////////////// +void qpGeomPrimitive:: +finalize(BamReader *manager) { + if (manager->get_file_minor_ver() < 19) { + const qpGeomVertexArrayData *vertices = get_vertices(); + if (vertices != (qpGeomVertexArrayData *)NULL) { + set_usage_hint(vertices->get_usage_hint()); + } + } +} + //////////////////////////////////////////////////////////////////// // Function: qpGeomPrimitive::fillin // Access: Protected @@ -1039,6 +1358,7 @@ fillin(DatagramIterator &scan, BamReader *manager) { TypedWritable::fillin(scan, manager); manager->read_cdata(scan, _cycler); + manager->register_finalize(this); } //////////////////////////////////////////////////////////////////// @@ -1060,7 +1380,10 @@ make_copy() const { void qpGeomPrimitive::CData:: write_datagram(BamWriter *manager, Datagram &dg) const { dg.add_uint8(_shade_model); + dg.add_uint32(_first_vertex); + dg.add_uint32(_num_vertices); dg.add_uint8(_index_type); + dg.add_uint8(_usage_hint); manager->write_pointer(dg, _vertices); WRITE_PTA(manager, dg, IPD_int::write_datagram, _ends); @@ -1092,7 +1415,14 @@ complete_pointers(TypedWritable **p_list, BamReader *manager) { void qpGeomPrimitive::CData:: fillin(DatagramIterator &scan, BamReader *manager) { _shade_model = (ShadeModel)scan.get_uint8(); + if (manager->get_file_minor_ver() >= 19) { + _first_vertex = scan.get_uint32(); + _num_vertices = scan.get_uint32(); + } _index_type = (NumericType)scan.get_uint8(); + if (manager->get_file_minor_ver() >= 19) { + _usage_hint = (UsageHint)scan.get_uint8(); + } manager->read_pointer(scan); READ_PTA(manager, scan, IPD_int::read_datagram, _ends); diff --git a/panda/src/gobj/qpgeomPrimitive.h b/panda/src/gobj/qpgeomPrimitive.h index 3ece82d0f7..222cadff3c 100644 --- a/panda/src/gobj/qpgeomPrimitive.h +++ b/panda/src/gobj/qpgeomPrimitive.h @@ -80,7 +80,7 @@ PUBLISHED: INLINE void set_shade_model(ShadeModel shade_model); INLINE UsageHint get_usage_hint() const; - INLINE void set_usage_hint(UsageHint usage_hint); + void set_usage_hint(UsageHint usage_hint); INLINE NumericType get_index_type() const; void set_index_type(NumericType index_type); @@ -92,6 +92,9 @@ PUBLISHED: // primitives' lengths are encoded. You can also safely build up a // composite primitive using these methods. + INLINE bool is_composite() const; + INLINE bool is_indexed() const; + int get_first_vertex() const; INLINE int get_num_vertices() const; int get_vertex(int i) const; void add_vertex(int vertex); @@ -100,6 +103,9 @@ PUBLISHED: bool close_primitive(); void clear_vertices(); void offset_vertices(int offset); + void make_nonindexed(qpGeomVertexData *dest, const qpGeomVertexData *source); + void pack_vertices(qpGeomVertexData *dest, const qpGeomVertexData *source); + void make_indexed(); int get_num_primitives() const; int get_primitive_start(int n) const; @@ -140,6 +146,7 @@ public: INLINE const qpGeomVertexArrayData *get_vertices() const; qpGeomVertexArrayData *modify_vertices(); void set_vertices(const qpGeomVertexArrayData *vertices); + void set_nonindexed_vertices(int first_vertex, int num_vertices); INLINE int get_index_stride() const; INLINE CPTA_uchar get_data() const; @@ -163,6 +170,10 @@ public: bool release(PreparedGraphicsObjects *prepared_objects); int release_all(); +protected: + INLINE CPT(qpGeomVertexArrayFormat) get_index_format() const; + INLINE PT(qpGeomVertexArrayData) make_index_data() const; + private: void clear_prepared(PreparedGraphicsObjects *prepared_objects); @@ -177,6 +188,7 @@ public: protected: virtual CPT(qpGeomPrimitive) decompose_impl() const; virtual CPT(qpGeomVertexArrayData) rotate_impl() const; + virtual bool requires_unused_vertices() const; virtual void append_unused_vertices(qpGeomVertexArrayData *vertices, int vertex); @@ -200,7 +212,10 @@ private: virtual void fillin(DatagramIterator &scan, BamReader *manager); ShadeModel _shade_model; + int _first_vertex; + int _num_vertices; NumericType _index_type; + UsageHint _usage_hint; PT(qpGeomVertexArrayData) _vertices; PTA_int _ends; PT(qpGeomVertexArrayData) _mins; @@ -217,6 +232,7 @@ private: typedef CycleDataWriter CDWriter; void recompute_minmax(CDWriter &cdata); + void do_make_indexed(CDWriter &cdata); static PStatCollector _decompose_pcollector; static PStatCollector _rotate_pcollector; @@ -224,6 +240,8 @@ private: public: virtual void write_datagram(BamWriter *manager, Datagram &dg); + virtual void finalize(BamReader *manager); + protected: void fillin(DatagramIterator &scan, BamReader *manager); diff --git a/panda/src/gobj/qpgeomTriangles.cxx b/panda/src/gobj/qpgeomTriangles.cxx index 3282eef71f..45fb05a8bf 100644 --- a/panda/src/gobj/qpgeomTriangles.cxx +++ b/panda/src/gobj/qpgeomTriangles.cxx @@ -116,49 +116,87 @@ rotate_impl() const { // To rotate triangles, we just move one vertex from the front to // the back, or vice-versa; but we have to know what direction we're // going. - CPT(qpGeomVertexArrayData) vertices = get_vertices(); ShadeModel shade_model = get_shade_model(); - - PT(qpGeomVertexArrayData) new_vertices = - new qpGeomVertexArrayData(*vertices); - qpGeomVertexReader from(vertices, 0); - qpGeomVertexWriter to(new_vertices, 0); - - int num_vertices = vertices->get_num_rows(); - - switch (shade_model) { - case SM_flat_first_vertex: - // Move the first vertex to the end. - { - for (int begin = 0; begin < num_vertices; begin += 3) { - from.set_row(begin + 1); - to.set_data1i(from.get_data1i()); - to.set_data1i(from.get_data1i()); - from.set_row(begin); - to.set_data1i(from.get_data1i()); - } - } - break; + int num_vertices = get_num_vertices(); - case SM_flat_last_vertex: - // Move the last vertex to the front. - { - for (int begin = 0; begin < num_vertices; begin += 3) { - from.set_row(begin + 2); - to.set_data1i(from.get_data1i()); - from.set_row(begin); - to.set_data1i(from.get_data1i()); - to.set_data1i(from.get_data1i()); + PT(qpGeomVertexArrayData) new_vertices = make_index_data(); + new_vertices->set_num_rows(num_vertices); + + if (is_indexed()) { + CPT(qpGeomVertexArrayData) vertices = get_vertices(); + qpGeomVertexReader from(vertices, 0); + qpGeomVertexWriter to(new_vertices, 0); + + switch (shade_model) { + case SM_flat_first_vertex: + // Move the first vertex to the end. + { + for (int begin = 0; begin < num_vertices; begin += 3) { + from.set_row(begin + 1); + to.set_data1i(from.get_data1i()); + to.set_data1i(from.get_data1i()); + from.set_row(begin); + to.set_data1i(from.get_data1i()); + } } - } - break; + break; - default: - // This shouldn't get called with any other shade model. - nassertr(false, vertices); + case SM_flat_last_vertex: + // Move the last vertex to the front. + { + for (int begin = 0; begin < num_vertices; begin += 3) { + from.set_row(begin + 2); + to.set_data1i(from.get_data1i()); + from.set_row(begin); + to.set_data1i(from.get_data1i()); + to.set_data1i(from.get_data1i()); + } + } + break; + + default: + // This shouldn't get called with any other shade model. + nassertr(false, vertices); + } + + nassertr(to.is_at_end(), NULL); + + } else { + // Nonindexed case. + int first_vertex = get_first_vertex(); + qpGeomVertexWriter to(new_vertices, 0); + + switch (shade_model) { + case SM_flat_first_vertex: + // Move the first vertex to the end. + { + for (int begin = 0; begin < num_vertices; begin += 3) { + to.set_data1i(begin + 1 + first_vertex); + to.set_data1i(begin + 2 + first_vertex); + to.set_data1i(begin + first_vertex); + } + } + break; + + case SM_flat_last_vertex: + // Move the last vertex to the front. + { + for (int begin = 0; begin < num_vertices; begin += 3) { + to.set_data1i(begin + 2 + first_vertex); + to.set_data1i(begin + first_vertex); + to.set_data1i(begin + 1 + first_vertex); + } + } + break; + + default: + // This shouldn't get called with any other shade model. + nassertr(false, NULL); + } + + nassertr(to.is_at_end(), NULL); } - - nassertr(to.is_at_end(), NULL); + return new_vertices; } diff --git a/panda/src/gobj/qpgeomTristrips.cxx b/panda/src/gobj/qpgeomTristrips.cxx index 7394db9a1a..c269dfec18 100644 --- a/panda/src/gobj/qpgeomTristrips.cxx +++ b/panda/src/gobj/qpgeomTristrips.cxx @@ -235,44 +235,91 @@ rotate_impl() const { // vertices, that doesn't work--in fact, nothing works (without also // changing the winding order), so we don't allow an odd number of // vertices in a flat-shaded tristrip. - CPT(qpGeomVertexArrayData) vertices = get_vertices(); CPTA_int ends = get_ends(); - PT(qpGeomVertexArrayData) new_vertices = - new qpGeomVertexArrayData(*vertices); - qpGeomVertexReader from(vertices, 0); - qpGeomVertexWriter to(new_vertices, 0); - int begin = 0; - int last_added = 0; - CPTA_int::const_iterator ei; - for (ei = ends.begin(); ei != ends.end(); ++ei) { - int end = (*ei); - int num_vertices = end - begin; + PT(qpGeomVertexArrayData) new_vertices = make_index_data(); + new_vertices->set_num_rows(get_num_vertices()); - if (begin != 0) { - // Copy in the unused vertices between tristrips. - to.set_data1i(last_added); - from.set_row(end - 1); - to.set_data1i(from.get_data1i()); - begin += 2; + if (is_indexed()) { + CPT(qpGeomVertexArrayData) vertices = get_vertices(); + qpGeomVertexReader from(vertices, 0); + qpGeomVertexWriter to(new_vertices, 0); + + int begin = 0; + int last_added = 0; + CPTA_int::const_iterator ei; + for (ei = ends.begin(); ei != ends.end(); ++ei) { + int end = (*ei); + int num_vertices = end - begin; + + if (begin != 0) { + // Copy in the unused vertices between tristrips. + to.set_data1i(last_added); + from.set_row(end - 1); + to.set_data1i(from.get_data1i()); + begin += 2; + } + + // If this assertion is triggered, there was a triangle strip with + // an odd number of vertices, which is not allowed. + nassertr((num_vertices & 1) == 0, NULL); + for (int vi = end - 1; vi >= begin; --vi) { + from.set_row(vi); + last_added = from.get_data1i(); + to.set_data1i(last_added); + } + + begin = end; } - // If this assertion is triggered, there was a triangle strip with - // an odd number of vertices, which is not allowed. - nassertr((num_vertices & 1) == 0, NULL); - for (int vi = end - 1; vi >= begin; --vi) { - from.set_row(vi); - last_added = from.get_data1i(); - to.set_data1i(last_added); + nassertr(to.is_at_end(), NULL); + + } else { + // Nonindexed case. + int first_vertex = get_first_vertex(); + qpGeomVertexWriter to(new_vertices, 0); + + int begin = 0; + int last_added = 0; + CPTA_int::const_iterator ei; + for (ei = ends.begin(); ei != ends.end(); ++ei) { + int end = (*ei); + int num_vertices = end - begin; + + if (begin != 0) { + // Copy in the unused vertices between tristrips. + to.set_data1i(last_added); + to.set_data1i(end - 1 + first_vertex); + begin += 2; + } + + // If this assertion is triggered, there was a triangle strip with + // an odd number of vertices, which is not allowed. + nassertr((num_vertices & 1) == 0, NULL); + for (int vi = end - 1; vi >= begin; --vi) { + last_added = vi + first_vertex; + to.set_data1i(last_added); + } + + begin = end; } - begin = end; + nassertr(to.is_at_end(), NULL); } - - nassertr(to.is_at_end(), NULL); return new_vertices; } +//////////////////////////////////////////////////////////////////// +// Function: qpGeomTristrips::requires_unused_vertices +// Access: Protected, Virtual +// Description: Should be redefined to return true in any primitive +// that implements append_unused_vertices(). +//////////////////////////////////////////////////////////////////// +bool qpGeomTristrips:: +requires_unused_vertices() const { + return true; +} + //////////////////////////////////////////////////////////////////// // Function: qpGeomTristrips::append_unused_vertices // Access: Protected, Virtual diff --git a/panda/src/gobj/qpgeomTristrips.h b/panda/src/gobj/qpgeomTristrips.h index 456ba58a37..e3026608b5 100644 --- a/panda/src/gobj/qpgeomTristrips.h +++ b/panda/src/gobj/qpgeomTristrips.h @@ -46,6 +46,7 @@ public: protected: virtual CPT(qpGeomPrimitive) decompose_impl() const; virtual CPT(qpGeomVertexArrayData) rotate_impl() const; + virtual bool requires_unused_vertices() const; virtual void append_unused_vertices(qpGeomVertexArrayData *vertices, int vertex); diff --git a/panda/src/gobj/qpgeomVertexColumn.cxx b/panda/src/gobj/qpgeomVertexColumn.cxx index 17f9b668f8..952b7c5b75 100644 --- a/panda/src/gobj/qpgeomVertexColumn.cxx +++ b/panda/src/gobj/qpgeomVertexColumn.cxx @@ -46,7 +46,33 @@ operator = (const qpGeomVertexColumn ©) { //////////////////////////////////////////////////////////////////// void qpGeomVertexColumn:: output(ostream &out) const { - out << *get_name() << "(" << get_num_components() << ")"; + out << *get_name() << "(" << get_num_components(); + switch (get_numeric_type()) { + case NT_uint8: + out << "b"; + break; + + case NT_uint16: + out << "s"; + break; + + case NT_uint32: + out << "l"; + break; + + case NT_packed_dcba: + out << "p-"; + break; + + case NT_packed_dabc: + out << "p"; + break; + + case NT_float32: + out << "f"; + } + + out << ")"; } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/gobj/qpgeomVertexData.cxx b/panda/src/gobj/qpgeomVertexData.cxx index 030cde6401..48dd242879 100644 --- a/panda/src/gobj/qpgeomVertexData.cxx +++ b/panda/src/gobj/qpgeomVertexData.cxx @@ -379,11 +379,11 @@ get_num_bytes() const { // pointerwise from the source. //////////////////////////////////////////////////////////////////// void qpGeomVertexData:: -copy_from(const qpGeomVertexData &source, bool keep_data_objects) { - const qpGeomVertexFormat *source_format = source.get_format(); +copy_from(const qpGeomVertexData *source, bool keep_data_objects) { + const qpGeomVertexFormat *source_format = source->get_format(); const qpGeomVertexFormat *dest_format = get_format(); - int num_rows = source.get_num_rows(); + int num_rows = source->get_num_rows(); int num_arrays = source_format->get_num_arrays(); int source_i; @@ -410,14 +410,14 @@ copy_from(const qpGeomVertexData &source, bool keep_data_objects) { // Maybe it even has the same data pointer already. If so, // avoid flipping the modified flag. - CPTA_uchar source_data = source.get_array(source_i)->get_data(); + CPTA_uchar source_data = source->get_array(source_i)->get_data(); if (get_array(dest_i)->get_data() != source_data) { modify_array(dest_i)->set_data(source_data); } } else { // Copy the GeomVertexArrayData object. - if (get_array(dest_i) != source.get_array(source_i)) { - set_array(dest_i, source.get_array(source_i)); + if (get_array(dest_i) != source->get_array(source_i)) { + set_array(dest_i, source->get_array(source_i)); } } @@ -432,7 +432,7 @@ copy_from(const qpGeomVertexData &source, bool keep_data_objects) { // Now go back through and copy any data that's left over. for (source_i = 0; source_i < num_arrays; ++source_i) { - CPTA_uchar array_data = source.get_array(source_i)->get_data(); + CPTA_uchar array_data = source->get_array(source_i)->get_data(); const qpGeomVertexArrayFormat *source_array_format = source_format->get_array(source_i); int num_columns = source_array_format->get_num_columns(); for (int di = 0; di < num_columns; ++di) { @@ -487,7 +487,7 @@ copy_from(const qpGeomVertexData &source, bool keep_data_objects) { } qpGeomVertexWriter to(this); to.set_column(dest_i, dest_column); - qpGeomVertexReader from(&source); + qpGeomVertexReader from(source); from.set_column(source_i, source_column); while (!from.is_at_end()) { @@ -505,7 +505,7 @@ copy_from(const qpGeomVertexData &source, bool keep_data_objects) { if (dest_animation.get_animation_type() == AT_hardware) { // Convert Panda-style animation tables to hardware-style // animation tables. - CPT(TransformBlendPalette) blend_palette = source.get_transform_blend_palette(); + CPT(TransformBlendPalette) blend_palette = source->get_transform_blend_palette(); if (blend_palette != (TransformBlendPalette *)NULL) { PT(TransformPalette) transform_palette = new TransformPalette; TransformMap already_added; @@ -515,7 +515,7 @@ copy_from(const qpGeomVertexData &source, bool keep_data_objects) { // means we can put the blends in any order. qpGeomVertexWriter weight(this, InternalName::get_transform_weight()); qpGeomVertexWriter index(this, InternalName::get_transform_index()); - qpGeomVertexReader from(&source, InternalName::get_transform_blend()); + qpGeomVertexReader from(source, InternalName::get_transform_blend()); while (!from.is_at_end()) { const TransformBlend &blend = blend_palette->get_blend(from.get_data1i()); @@ -537,7 +537,7 @@ copy_from(const qpGeomVertexData &source, bool keep_data_objects) { // Build a nonindexed transform array. This means we have to // use the same n transforms, in the same order, for each vertex. qpGeomVertexWriter weight(this, InternalName::get_transform_weight()); - qpGeomVertexReader from(&source, InternalName::get_transform_blend()); + qpGeomVertexReader from(source, InternalName::get_transform_blend()); while (!from.is_at_end()) { const TransformBlend &blend = blend_palette->get_blend(from.get_data1i()); @@ -562,6 +562,41 @@ copy_from(const qpGeomVertexData &source, bool keep_data_objects) { } } +//////////////////////////////////////////////////////////////////// +// Function: qpGeomVertexData::copy_row_from +// Access: Published +// Description: Copies a single row of the data from the other array +// into the indicated row of this array. In this case, +// the source format must exactly match the destination +// format. +//////////////////////////////////////////////////////////////////// +void qpGeomVertexData:: +copy_row_from(int dest_row, const qpGeomVertexData *source, + int source_row) { + const qpGeomVertexFormat *source_format = source->get_format(); + const qpGeomVertexFormat *dest_format = get_format(); + nassertv(source_format == dest_format); + nassertv(source_row >= 0 && source_row < source->get_num_rows()); + + if (dest_row >= get_num_rows()) { + // Implicitly add enough rows to get to the indicated row. + set_num_rows(dest_row + 1); + } + + int num_arrays = source_format->get_num_arrays(); + + for (int i = 0; i < num_arrays; ++i) { + PTA_uchar dest_array_data = modify_array(i)->modify_data(); + CPTA_uchar source_array_data = source->get_array(i)->get_data(); + const qpGeomVertexArrayFormat *array_format = source_format->get_array(i); + int stride = array_format->get_stride(); + + memcpy(dest_array_data + stride * dest_row, + source_array_data + stride * source_row, + stride); + } +} + //////////////////////////////////////////////////////////////////// // Function: qpGeomVertexData::convert_to // Access: Published @@ -605,7 +640,7 @@ convert_to(const qpGeomVertexFormat *new_format) const { new_data->set_transform_blend_palette(get_transform_blend_palette()); new_data->set_slider_table(get_slider_table()); - new_data->copy_from(*this, false); + new_data->copy_from(this, false); { // Record the new result in the cache. @@ -1269,7 +1304,7 @@ update_animated_vertices(qpGeomVertexData::CDWriter &cdata, bool from_app) { // of the data that might have changed since last frame, but that's // too much trouble (and isn't obviously faster than just copying // the whole thing). - new_data->copy_from(*this, true); + new_data->copy_from(this, true); // First, apply all of the morphs. CPT(SliderTable) table = cdata->_slider_table; diff --git a/panda/src/gobj/qpgeomVertexData.h b/panda/src/gobj/qpgeomVertexData.h index 4a5fdb1739..83e7ff8c1f 100644 --- a/panda/src/gobj/qpgeomVertexData.h +++ b/panda/src/gobj/qpgeomVertexData.h @@ -118,7 +118,9 @@ PUBLISHED: int get_num_bytes() const; INLINE UpdateSeq get_modified() const; - void copy_from(const qpGeomVertexData &source, bool keep_data_objects); + void copy_from(const qpGeomVertexData *source, bool keep_data_objects); + void copy_row_from(int dest_row, const qpGeomVertexData *source, + int source_row); CPT(qpGeomVertexData) convert_to(const qpGeomVertexFormat *new_format) const; CPT(qpGeomVertexData) scale_color(const LVecBase4f &color_scale) const; diff --git a/panda/src/gobj/qpgeomVertexFormat.cxx b/panda/src/gobj/qpgeomVertexFormat.cxx index ee8070252a..ddd4a45918 100644 --- a/panda/src/gobj/qpgeomVertexFormat.cxx +++ b/panda/src/gobj/qpgeomVertexFormat.cxx @@ -417,7 +417,8 @@ write_with_data(ostream &out, int indent_level, for (size_t i = 0; i < _arrays.size(); i++) { CPTA_uchar array_data = data->get_array(i)->get_data(); indent(out, indent_level) - << "Array " << i << " (" << (void *)array_data.p() << "):\n"; + << "Array " << i << " (" << (void *)array_data.p() << ", " + << *_arrays[i] << "):\n"; _arrays[i]->write_with_data(out, indent_level + 2, data->get_array(i)); } } diff --git a/panda/src/pgraph/geomNode.I b/panda/src/pgraph/geomNode.I index eb4e609120..a33138ee54 100644 --- a/panda/src/pgraph/geomNode.I +++ b/panda/src/pgraph/geomNode.I @@ -67,6 +67,17 @@ get_geom(int n) const { //////////////////////////////////////////////////////////////////// // Function: GeomNode::get_unique_geom // Access: Public +// Description: This method is deprecated; you should call +// modify_geom() instead. +//////////////////////////////////////////////////////////////////// +INLINE Geom *GeomNode:: +get_unique_geom(int n) { + return modify_geom(n); +} + +//////////////////////////////////////////////////////////////////// +// Function: GeomNode::modify_geom +// Access: Public // Description: Returns the nth geom of the node, suitable for // modifying it. If the nth Geom has multiple reference // counts to it, reassigns it to an identical copy @@ -76,7 +87,7 @@ get_geom(int n) const { // with any other GeomNodes. //////////////////////////////////////////////////////////////////// INLINE Geom *GeomNode:: -get_unique_geom(int n) { +modify_geom(int n) { CDWriter cdata(_cycler); nassertr(n >= 0 && n < (int)cdata->_geoms.size(), NULL); Geom *geom = cdata->_geoms[n]._geom; diff --git a/panda/src/pgraph/geomNode.h b/panda/src/pgraph/geomNode.h index be3cc9d8a0..8457c2e25e 100644 --- a/panda/src/pgraph/geomNode.h +++ b/panda/src/pgraph/geomNode.h @@ -59,6 +59,7 @@ PUBLISHED: INLINE int get_num_geoms() const; INLINE const Geom *get_geom(int n) const; INLINE Geom *get_unique_geom(int n); + INLINE Geom *modify_geom(int n); INLINE const RenderState *get_geom_state(int n) const; INLINE void set_geom_state(int n, const RenderState *state); diff --git a/panda/src/pgraph/sceneGraphReducer.I b/panda/src/pgraph/sceneGraphReducer.I index 4da934433f..0b1bfc96cd 100644 --- a/panda/src/pgraph/sceneGraphReducer.I +++ b/panda/src/pgraph/sceneGraphReducer.I @@ -118,3 +118,18 @@ INLINE int SceneGraphReducer:: collect_vertex_data(PandaNode *root, int collect_bits) { return r_collect_vertex_data(root, collect_bits, _transformer); } + +//////////////////////////////////////////////////////////////////// +// Function: SceneGraphReducer::make_nonindexed +// Access: Published +// Description: Converts indexed geometry to nonindexed geometry at +// the indicated node and below, by duplicating vertices +// where necessary. The parameter nonindexed_bits is a +// union of bits defined in +// SceneGraphReducer::MakeNonindexed, which specifes +// which types of geometry to avoid making nonindexed. +//////////////////////////////////////////////////////////////////// +INLINE int SceneGraphReducer:: +make_nonindexed(PandaNode *root, int nonindexed_bits) { + return r_make_nonindexed(root, nonindexed_bits); +} diff --git a/panda/src/pgraph/sceneGraphReducer.cxx b/panda/src/pgraph/sceneGraphReducer.cxx index b8b3edc31f..dd0a66dbfa 100644 --- a/panda/src/pgraph/sceneGraphReducer.cxx +++ b/panda/src/pgraph/sceneGraphReducer.cxx @@ -583,6 +583,9 @@ r_collect_vertex_data(PandaNode *node, int collect_bits, if (!node->get_transform()->is_identity()) { this_node_bits |= CVD_transform; } + if (node->is_geom_node()) { + this_node_bits |= CVD_one_node_only; + } if ((collect_bits & this_node_bits) != 0) { // We need to start a unique collection here. @@ -621,3 +624,53 @@ r_collect_vertex_data(PandaNode *node, int collect_bits, return num_created; } + +//////////////////////////////////////////////////////////////////// +// Function: SceneGraphReducer::r_make_nonindexed +// Access: Private +// Description: The recursive implementation of +// make_nonindexed(). +//////////////////////////////////////////////////////////////////// +int SceneGraphReducer:: +r_make_nonindexed(PandaNode *node, int nonindexed_bits) { + int num_changed = 0; + + if (node->is_geom_node()) { + GeomNode *geom_node = DCAST(GeomNode, node); + int num_geoms = geom_node->get_num_geoms(); + for (int i = 0; i < num_geoms; ++i) { + if (geom_node->get_geom(i)->is_of_type(qpGeom::get_class_type())) { + const qpGeom *geom = DCAST(qpGeom, geom_node->get_geom(i)); + + // Check whether the geom is animated or dynamic, and skip it + // if the user specified so. + const qpGeomVertexData *data = geom->get_vertex_data(); + int this_geom_bits = 0; + if (data->get_format()->get_animation().get_animation_type() != + qpGeom::AT_none) { + this_geom_bits |= MN_avoid_animated; + } + if (data->get_usage_hint() != qpGeom::UH_static || + geom->get_usage_hint() != qpGeom::UH_static) { + this_geom_bits |= MN_avoid_dynamic; + } + + if ((nonindexed_bits & this_geom_bits) == 0) { + // The geom meets the user's qualifications for making + // nonindexed, so do it. + qpGeom *mgeom = DCAST(qpGeom, geom_node->modify_geom(i)); + num_changed += mgeom->make_nonindexed((nonindexed_bits & MN_composite_only) != 0); + } + } + } + } + + PandaNode::Children children = node->get_children(); + int num_children = children.get_num_children(); + for (int i = 0; i < num_children; ++i) { + num_changed += + r_make_nonindexed(children.get_child(i), nonindexed_bits); + } + + return num_changed; +} diff --git a/panda/src/pgraph/sceneGraphReducer.h b/panda/src/pgraph/sceneGraphReducer.h index a030aa8cad..37281ae19e 100644 --- a/panda/src/pgraph/sceneGraphReducer.h +++ b/panda/src/pgraph/sceneGraphReducer.h @@ -78,9 +78,29 @@ PUBLISHED: // If set, GeomVertexDatas with any usage_hint other than // UH_static will not be collected with any other Geoms in a - // different GeomNode. However, two different Geoms within the - // same node might still be collected together. + // different GeomNode. However, two different dynamic Geoms + // within the same node might still be collected together. CVD_avoid_dynamic = 0x008, + + // If set, only those GeomVertexDatas within the same node might + // be collected together. + CVD_one_node_only = 0x010, + }; + + enum MakeNonindexed { + // If set, only composite primitives such as tristrips and trifans + // will be made nonindexed; simple primitives such as triangles + // will be left indexed. + MN_composite_only = 0x001, + + // If set any GeomVertexData with any animation indication will + // not be adjusted, whether the animation is to be performed on + // the CPU or on the graphics pipe. + MN_avoid_animated = 0x002, + + // If set, any GeomVertexData or Geom with a usage_hint other than + // UH_static will not be made nonindexed. + MN_avoid_dynamic = 0x004, }; INLINE void set_usage_hint(qpGeom::UsageHint usage_hint); @@ -93,6 +113,7 @@ PUBLISHED: int flatten(PandaNode *root, int combine_siblings_bits); INLINE int collect_vertex_data(PandaNode *root, int collect_bits = ~0); + INLINE int make_nonindexed(PandaNode *root, int nonindexed_bits = ~0); protected: void r_apply_attribs(PandaNode *node, const AccumulatedAttribs &attribs, @@ -121,6 +142,7 @@ protected: int r_collect_vertex_data(PandaNode *node, int collect_bits, GeomTransformer &transformer); + int r_make_nonindexed(PandaNode *node, int collect_bits); private: GeomTransformer _transformer; diff --git a/panda/src/putil/bam.h b/panda/src/putil/bam.h index dbd9c7657d..0268e7933e 100644 --- a/panda/src/putil/bam.h +++ b/panda/src/putil/bam.h @@ -34,7 +34,7 @@ static const unsigned short _bam_major_ver = 4; // Bumped to major version 3 on 12/8/00 to change float64's to float32's. // Bumped to major version 4 on 4/10/02 to store new scene graph. -static const unsigned short _bam_minor_ver = 18; +static const unsigned short _bam_minor_ver = 19; // Bumped to minor version 1 on 4/10/03 to add CullFaceAttrib::reverse. // Bumped to minor version 2 on 4/12/03 to add num_components to texture. // Bumped to minor version 3 on 4/15/03 to add ImageBuffer::_alpha_file_channel @@ -53,6 +53,7 @@ static const unsigned short _bam_minor_ver = 18; // Bumped to minor version 16 on 2/24/05 to add TextureStage::rgb_scale, etc. // Bumped to minor version 17 on 3/03/05 to add 3-d textures, etc. // Bumped to minor version 18 on 4/05/05 to add RenderModeAttrib::perspective. +// Bumped to minor version 19 on 4/19/05 to add nonindexed qpgeom primitives. #endif diff --git a/panda/src/testbed/pview.cxx b/panda/src/testbed/pview.cxx index c3aab50463..12b8e62c86 100644 --- a/panda/src/testbed/pview.cxx +++ b/panda/src/testbed/pview.cxx @@ -18,9 +18,10 @@ #include "pandaFramework.h" #include "textNode.h" -#include "multitexReducer.h" #include "configVariableBool.h" #include "texturePool.h" +#include "multitexReducer.h" +#include "sceneGraphReducer.h" // By including checkPandaVersion.h, we guarantee that runtime // attempts to run pview will fail if it inadvertently links with the @@ -130,6 +131,12 @@ event_2(CPT_Event event, void *) { void event_0(CPT_Event event, void *) { // 0: run hacky test. + + SceneGraphReducer gr; + gr.make_nonindexed(framework.get_models().node()); + gr.collect_vertex_data(framework.get_models().node()); + + /* static int count = 0; static PT(TextureStage) ts; @@ -175,6 +182,7 @@ event_0(CPT_Event event, void *) { } } count++; + */ } void