mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-03 10:22:45 -04:00
nonindexed primitives
This commit is contained in:
parent
81ba73e74b
commit
e0dca3b43b
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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),
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 << ")";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user