collect_vertex_data

This commit is contained in:
David Rose 2005-04-13 23:56:15 +00:00
parent 62305f25bd
commit d36604ab05
17 changed files with 394 additions and 3 deletions

View File

@ -2494,6 +2494,10 @@ draw_tristrips(const qpGeomTristrips *primitive) {
const unsigned short *client_pointer = setup_primitive(primitive);
if (connect_triangle_strips && _render_mode != RenderModeAttrib::M_wireframe) {
GLCAT.debug()
<< "Connected triangle strips\n";
primitive->write(GLCAT.debug(), 2);
// 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());
@ -2504,6 +2508,10 @@ draw_tristrips(const qpGeomTristrips *primitive) {
GL_UNSIGNED_SHORT, client_pointer);
} else {
GLCAT.debug()
<< "Separate triangle strips\n";
primitive->write(GLCAT.debug(), 2);
// Send the individual triangle strips, stepping over the
// degenerate vertices.
CPTA_int ends = primitive->get_ends();

View File

@ -141,6 +141,45 @@ set_vertex_data(const qpGeomVertexData *data) {
reset_point_rendering(cdata);
}
////////////////////////////////////////////////////////////////////
// Function: qpGeom::offset_vertices
// Access: Published
// Description: Replaces a Geom's vertex table with a new table, and
// simultaneously adds the indicated offset to all
// vertex references within the Geom's primitives. This
// is intended to be used to combine multiple
// GeomVertexDatas from different Geoms into a single
// big buffer, with each Geom referencing a subset of
// the vertices in the buffer.
////////////////////////////////////////////////////////////////////
void qpGeom::
offset_vertices(const qpGeomVertexData *data, int offset) {
clear_cache();
CDWriter cdata(_cycler);
cdata->_data = (qpGeomVertexData *)data;
#ifndef NDEBUG
bool all_is_valid = true;
#endif
Primitives::iterator pi;
for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) {
(*pi)->offset_vertices(offset);
#ifndef NDEBUG
if (!(*pi)->check_valid(data)) {
all_is_valid = false;
}
#endif
}
cdata->_got_usage_hint = false;
cdata->_modified = qpGeom::get_next_modified();
mark_bound_stale();
reset_point_rendering(cdata);
nassertv(all_is_valid);
}
////////////////////////////////////////////////////////////////////
// Function: qpGeom::set_primitive
// Access: Published

View File

@ -98,6 +98,7 @@ PUBLISHED:
INLINE CPT(qpGeomVertexData) get_vertex_data() const;
PT(qpGeomVertexData) modify_vertex_data();
void set_vertex_data(const qpGeomVertexData *data);
void offset_vertices(const qpGeomVertexData *data, int offset);
INLINE int get_num_primitives() const;
INLINE const qpGeomPrimitive *get_primitive(int i) const;

View File

@ -274,6 +274,28 @@ clear_vertices() {
cdata->_got_minmax = false;
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomPrimitive::offset_vertices
// Access: Published
// Description: Adds the indicated offset to all vertices used by the
// primitive.
////////////////////////////////////////////////////////////////////
void qpGeomPrimitive::
offset_vertices(int offset) {
clear_cache();
CDWriter cdata(_cycler);
cdata->_rotated_vertices.clear();
cdata->_mins.clear();
cdata->_maxs.clear();
cdata->_got_minmax = false;
PTA_ushort::iterator vi;
for (vi = cdata->_vertices.begin(); vi != cdata->_vertices.end(); ++vi) {
(*vi) += offset;
}
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomPrimitive::get_num_primitives
// Access: Published

View File

@ -119,6 +119,7 @@ PUBLISHED:
void add_next_vertices(int num_vertices);
bool close_primitive();
void clear_vertices();
void offset_vertices(int offset);
int get_num_primitives() const;
int get_primitive_start(int n) const;

View File

@ -197,6 +197,37 @@ get_vector(int n) const {
return _vectors[n];
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexFormat::get_num_texcoords
// Access: Published
// Description: Returns the number of columns within the format
// that represent texture coordinates.
//
// This may only be called after the format has been
// registered.
////////////////////////////////////////////////////////////////////
INLINE int qpGeomVertexFormat::
get_num_texcoords() const {
nassertr(_is_registered, 0);
return _texcoords.size();
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexFormat::get_texcoord
// Access: Published
// Description: Returns the name of the nth texcoord column. This
// represents a texture coordinate.
//
// This may only be called after the format has been
// registered.
////////////////////////////////////////////////////////////////////
INLINE const InternalName *qpGeomVertexFormat::
get_texcoord(int n) const {
nassertr(_is_registered, NULL);
nassertr(n >= 0 && n < (int)_texcoords.size(), NULL);
return _texcoords[n];
}
////////////////////////////////////////////////////////////////////
// Function: qpGeomVertexFormat::get_num_morphs
// Access: Published

View File

@ -546,6 +546,11 @@ do_register() {
_vectors.push_back(column->get_name());
break;
case qpGeomVertexColumn::C_texcoord:
// It's a texcoord.
_texcoords.push_back(column->get_name());
break;
case qpGeomVertexColumn::C_morph_delta:
{
// It's a morph description.
@ -604,6 +609,7 @@ do_unregister() {
_columns_by_name.clear();
_points.clear();
_vectors.clear();
_texcoords.clear();
_morphs.clear();
}

View File

@ -104,6 +104,9 @@ PUBLISHED:
INLINE int get_num_vectors() const;
INLINE const InternalName *get_vector(int n) const;
INLINE int get_num_texcoords() const;
INLINE const InternalName *get_texcoord(int n) const;
INLINE int get_num_morphs() const;
INLINE const InternalName *get_morph_slider(int n) const;
INLINE const InternalName *get_morph_base(int n) const;
@ -190,6 +193,7 @@ private:
typedef pvector< CPT(InternalName) > Columns;
Columns _points;
Columns _vectors;
Columns _texcoords;
class MorphRecord {
public:

View File

@ -159,7 +159,7 @@ set_column(const InternalName *name) {
// The return value is true if the data type is valid,
// false otherwise.
////////////////////////////////////////////////////////////////////
bool qpGeomVertexRewriter::
INLINE bool qpGeomVertexRewriter::
set_column(int array, const qpGeomVertexColumn *column) {
// It's important to invoke the writer first, then the reader. See
// set_vertex().

View File

@ -154,6 +154,14 @@ ConfigVariableBool auto_break_cycles
"is false, you must explicitly call TransformState.clear_cache() "
"from time to time to prevent gradual memory bloat."));
ConfigVariableInt max_collect_vertices
("max-collect-vertices", 4096,
PRC_DESC("Specifies the maximum number of vertices that are allowed to be "
"accumulated into any one GeomVertexData structure as a result "
"of collecting objects together during a flatten operation. This "
"does not impose a limit on the original size of any one "
"GeomVertexData structure."));
ConfigVariableBool polylight_info
("polylight-info", false,
PRC_DESC("Set this true to view some info statements regarding the polylight. "

View File

@ -23,6 +23,7 @@
#include "notifyCategoryProxy.h"
#include "dconfig.h"
#include "configVariableBool.h"
#include "configVariableInt.h"
#include "configVariableDouble.h"
#include "configVariableList.h"
@ -40,6 +41,7 @@ extern ConfigVariableBool paranoid_compose;
extern ConfigVariableBool compose_componentwise;
extern ConfigVariableBool paranoid_const;
extern ConfigVariableBool auto_break_cycles;
extern ConfigVariableInt max_collect_vertices;
extern ConfigVariableBool polylight_info;
extern ConfigVariableDouble lod_fade_time;

View File

@ -17,6 +17,30 @@
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: GeomTransformer::get_max_collect_vertices
// Access: Public
// Description: Returns the maximum number of vertices that may be
// put into a single GeomVertexData as a result of
// collecting multiple objects in collect_vertex_data().
////////////////////////////////////////////////////////////////////
INLINE int GeomTransformer::
get_max_collect_vertices() const {
return _max_collect_vertices;
}
////////////////////////////////////////////////////////////////////
// Function: GeomTransformer::set_max_collect_vertices
// Access: Public
// Description: Specifies the maximum number of vertices that may be
// put into a single GeomVertexData as a result of
// collecting multiple objects in collect_vertex_data().
////////////////////////////////////////////////////////////////////
INLINE void GeomTransformer::
set_max_collect_vertices(int max_collect_vertices) {
_max_collect_vertices = max_collect_vertices;
}
////////////////////////////////////////////////////////////////////
// Function: GeomTransformer::qpSourceVertices::Ordering Operator
// Access: Public
@ -113,3 +137,19 @@ operator < (const GeomTransformer::SourceColors &other) const {
}
return (_scale.compare_to(other._scale) < 0);
}
////////////////////////////////////////////////////////////////////
// Function: GeomTransformer::NewCollectedKey::Ordering Operator
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE bool GeomTransformer::NewCollectedKey::
operator < (const GeomTransformer::NewCollectedKey &other) const {
if (_format != other._format) {
return _format < other._format;
}
if (_usage_hint != other._usage_hint) {
return (int)_usage_hint < (int)other._usage_hint;
}
return _name < other._name;
}

View File

@ -28,7 +28,21 @@
// Description:
////////////////////////////////////////////////////////////////////
GeomTransformer::
GeomTransformer() {
GeomTransformer() :
// The default value here comes from the Config file.
_max_collect_vertices(max_collect_vertices)
{
}
////////////////////////////////////////////////////////////////////
// Function: GeomTransformer::Copy Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
GeomTransformer::
GeomTransformer(const GeomTransformer &copy) :
_max_collect_vertices(copy._max_collect_vertices)
{
}
////////////////////////////////////////////////////////////////////
@ -510,3 +524,117 @@ apply_state(GeomNode *node, const RenderState *state) {
return any_changed;
}
////////////////////////////////////////////////////////////////////
// Function: GeomTransformer::collect_vertex_data
// Access: Public
// Description: Transforms the vertices and the normals in the
// indicated Geom by the indicated matrix. Returns true
// if the Geom was changed, false otherwise.
////////////////////////////////////////////////////////////////////
bool GeomTransformer::
collect_vertex_data(Geom *geom, bool keep_names) {
if (!geom->is_of_type(qpGeom::get_class_type())) {
return false;
}
qpGeom *qpgeom = DCAST(qpGeom, geom);
const qpGeomVertexData *vdata = qpgeom->get_vertex_data();
if (vdata->get_num_vertices() > _max_collect_vertices) {
// Don't even bother.
return false;
}
const qpGeomVertexFormat *format = vdata->get_format();
NewCollectedKey key;
if (keep_names) {
key._name = vdata->get_name();
}
key._format = format;
key._usage_hint = vdata->get_usage_hint();
AlreadyCollected::const_iterator ai;
ai = _already_collected.find(vdata);
if (ai != _already_collected.end()) {
// We've previously collected this vertex data; reuse it.
const AlreadyCollectedData &acd = (*ai).second;
qpgeom->offset_vertices(acd._data, acd._offset);
return true;
}
// We haven't collected this vertex data yet; append the vertices
// onto the new data.
NewCollectedData::iterator ni = _new_collected_data.find(key);
PT(qpGeomVertexData) new_data;
if (ni != _new_collected_data.end()) {
new_data = (*ni).second;
} else {
new_data = new qpGeomVertexData(vdata->get_name(), format,
vdata->get_usage_hint());
_new_collected_data[key] = new_data;
}
int offset = new_data->get_num_vertices();
int new_num_vertices = offset + vdata->get_num_vertices();
if (new_num_vertices > _max_collect_vertices) {
// Whoa, hold the phone! Too many vertices going into this one
// GeomVertexData object; we'd better start over.
new_data = new qpGeomVertexData(vdata->get_name(), format,
vdata->get_usage_hint());
_new_collected_data[key] = new_data;
offset = 0;
new_num_vertices = vdata->get_num_vertices();
}
new_data->set_num_vertices(new_num_vertices);
for (int i = 0; i < vdata->get_num_arrays(); ++i) {
qpGeomVertexArrayData *new_array = new_data->modify_array(i);
const qpGeomVertexArrayData *old_array = vdata->get_array(i);
int stride = format->get_array(i)->get_stride();
int start_byte = offset * stride;
int copy_bytes = old_array->get_data_size_bytes();
nassertr(start_byte + copy_bytes == new_array->get_data_size_bytes(), false);
memcpy(new_array->modify_data() + start_byte,
old_array->get_data(), copy_bytes);
}
qpgeom->offset_vertices(new_data, offset);
AlreadyCollectedData &acd = _already_collected[vdata];
acd._data = new_data;
acd._offset = offset;
return true;
}
////////////////////////////////////////////////////////////////////
// Function: GeomTransformer::collect_vertex_data
// Access: Public
// Description: Collects together individual GeomVertexData
// structures that share the same format into one big
// GeomVertexData structure. This is designed to
// minimize context switches on the graphics card.
////////////////////////////////////////////////////////////////////
bool GeomTransformer::
collect_vertex_data(GeomNode *node, bool keep_names) {
bool any_changed = false;
GeomNode::CDWriter cdata(node->_cycler);
GeomNode::Geoms::iterator gi;
for (gi = cdata->_geoms.begin(); gi != cdata->_geoms.end(); ++gi) {
GeomNode::GeomEntry &entry = (*gi);
PT(Geom) new_geom = entry._geom->make_copy();
if (collect_vertex_data(new_geom, keep_names)) {
entry._geom = new_geom;
any_changed = true;
}
}
return any_changed;
}

View File

@ -48,8 +48,12 @@ class InternalName;
class EXPCL_PANDA GeomTransformer {
public:
GeomTransformer();
GeomTransformer(const GeomTransformer &copy);
~GeomTransformer();
INLINE int get_max_collect_vertices() const;
INLINE void set_max_collect_vertices(int max_collect_vertices);
bool transform_vertices(Geom *geom, const LMatrix4f &mat);
bool transform_vertices(GeomNode *node, const LMatrix4f &mat);
@ -68,7 +72,12 @@ public:
bool apply_state(GeomNode *node, const RenderState *state);
bool collect_vertex_data(Geom *geom, bool keep_names);
bool collect_vertex_data(GeomNode *node, bool keep_names);
private:
int _max_collect_vertices;
class qpSourceVertices {
public:
INLINE bool operator < (const qpSourceVertices &other) const;
@ -153,6 +162,25 @@ private:
};
typedef pmap<SourceColors, PTA_Colorf> TColors;
TColors _tcolors;
class AlreadyCollectedData {
public:
CPT(qpGeomVertexData) _data;
int _offset;
};
typedef pmap< CPT(qpGeomVertexData), AlreadyCollectedData> AlreadyCollected;
AlreadyCollected _already_collected;
class NewCollectedKey {
public:
INLINE bool operator < (const NewCollectedKey &other) const;
string _name;
CPT(qpGeomVertexFormat) _format;
qpGeomUsageHint::UsageHint _usage_hint;
};
typedef pmap< NewCollectedKey, PT(qpGeomVertexData) > NewCollectedData;
NewCollectedData _new_collected_data;
};
#include "geomTransformer.I"

View File

@ -73,3 +73,22 @@ apply_attribs(PandaNode *node, const AccumulatedAttribs &attribs,
int attrib_types, GeomTransformer &transformer) {
r_apply_attribs(node, attribs, attrib_types, transformer);
}
////////////////////////////////////////////////////////////////////
// Function: SceneGraphReducer::collect_vertex_data
// Access: Published
// Description: Collects all different GeomVertexData blocks that
// have compatible formats at this node and below into a
// single, unified block (or at least multiple larger
// blocks). This is intended to reduce rendering
// overhead incurred by switching vertex buffers.
//
// The set of bits passed in collect_bits indicates
// which properties are used to differentiate
// GeomVertexData blocks. If it is 0, then more blocks
// will be combined together than if it is nonzero.
////////////////////////////////////////////////////////////////////
INLINE int SceneGraphReducer::
collect_vertex_data(PandaNode *root, int collect_bits) {
return r_collect_vertex_data(root, collect_bits, _transformer);
}

View File

@ -19,7 +19,7 @@
#include "sceneGraphReducer.h"
#include "config_pgraph.h"
#include "accumulatedAttribs.h"
#include "modelNode.h"
#include "pointerTo.h"
#include "plist.h"
#include "pmap.h"
@ -564,3 +564,47 @@ choose_name(PandaNode *preserve, PandaNode *source1, PandaNode *source2) {
preserve->set_name(name);
}
}
////////////////////////////////////////////////////////////////////
// Function: SceneGraphReducer::r_collect_vertex_data
// Access: Private
// Description: The recursive implementation of
// collect_vertex_data().
////////////////////////////////////////////////////////////////////
int SceneGraphReducer::
r_collect_vertex_data(PandaNode *node, int collect_bits,
GeomTransformer &transformer) {
int num_collected = 0;
if ((collect_bits & CVD_model) != 0 &&
node->is_of_type(ModelNode::get_class_type())) {
// When we come to a model node, start a new collection.
GeomTransformer new_transformer(transformer);
PandaNode::Children children = node->get_children();
int num_children = children.get_num_children();
for (int i = 0; i < num_children; ++i) {
num_collected +=
r_collect_vertex_data(children.get_child(i), collect_bits, new_transformer);
}
return num_collected;
}
if (node->is_geom_node()) {
// When we come to geom node, collect.
bool keep_names = ((collect_bits & SceneGraphReducer::CVD_name) != 0);
if (transformer.collect_vertex_data(DCAST(GeomNode, node), keep_names)) {
++num_collected;
}
}
// Then recurse.
PandaNode::Children children = node->get_children();
int num_children = children.get_num_children();
for (int i = 0; i < num_children; ++i) {
num_collected +=
r_collect_vertex_data(children.get_child(i), collect_bits, transformer);
}
return num_collected;
}

View File

@ -61,12 +61,19 @@ PUBLISHED:
CS_recurse = 0x004,
};
enum CollectVertexData {
CVD_name = 0x001,
CVD_model = 0x002,
};
INLINE void apply_attribs(PandaNode *node, int attrib_types = ~0);
INLINE void apply_attribs(PandaNode *node, const AccumulatedAttribs &attribs,
int attrib_types, GeomTransformer &transformer);
int flatten(PandaNode *root, int combine_siblings_bits);
INLINE int collect_vertex_data(PandaNode *root, int collect_bits = ~0);
protected:
void r_apply_attribs(PandaNode *node, const AccumulatedAttribs &attribs,
int attrib_types, GeomTransformer &transformer);
@ -92,6 +99,9 @@ protected:
void choose_name(PandaNode *preserve, PandaNode *source1,
PandaNode *source2);
int r_collect_vertex_data(PandaNode *node, int collect_bits,
GeomTransformer &transformer);
private:
GeomTransformer _transformer;
};