nonindexed primitives

This commit is contained in:
David Rose 2005-04-20 00:28:37 +00:00
parent 81ba73e74b
commit e0dca3b43b
24 changed files with 1367 additions and 420 deletions

View File

@ -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);
}
}
}

View File

@ -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();
}

View File

@ -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;
}

View File

@ -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

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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 &copy) :
_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),

View File

@ -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<int, int> 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<CopiedIndices::iterator, bool> result =
copied_indices.insert(CopiedIndices::value_type(v, (int)copied_indices.size()));
int v2 = (*result.first).second + dest_start;
index.add_data1i(v2);
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);

View File

@ -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<CData> 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);

View File

@ -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;
}

View File

@ -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

View File

@ -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);

View File

@ -46,7 +46,33 @@ operator = (const qpGeomVertexColumn &copy) {
////////////////////////////////////////////////////////////////////
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 << ")";
}
////////////////////////////////////////////////////////////////////

View File

@ -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;

View File

@ -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;

View File

@ -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));
}
}

View File

@ -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;

View File

@ -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);

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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

View File

@ -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