From c23be69d2bbf55cfeb6a5f8ed55e18644650d5c3 Mon Sep 17 00:00:00 2001 From: David Rose Date: Tue, 21 Dec 2004 00:12:09 +0000 Subject: [PATCH] better GeomTransformer, flatten operations --- panda/src/pgraph/accumulatedAttribs.I | 2 + panda/src/pgraph/accumulatedAttribs.cxx | 96 +++++++++++++++++++++- panda/src/pgraph/accumulatedAttribs.h | 2 + panda/src/pgraph/geomNode.I | 29 +++++++ panda/src/pgraph/geomNode.cxx | 102 +++++++++++++++++++----- panda/src/pgraph/geomNode.h | 4 + panda/src/pgraph/geomTransformer.cxx | 19 +++-- panda/src/pgraph/geomTransformer.h | 9 ++- panda/src/pgraph/texMatrixAttrib.I | 18 ++++- panda/src/pgraph/texMatrixAttrib.cxx | 56 +++++++++++++ panda/src/pgraph/texMatrixAttrib.h | 10 +++ panda/src/testbed/pview.cxx | 1 + 12 files changed, 312 insertions(+), 36 deletions(-) diff --git a/panda/src/pgraph/accumulatedAttribs.I b/panda/src/pgraph/accumulatedAttribs.I index 6f57593787..bddea8acc2 100644 --- a/panda/src/pgraph/accumulatedAttribs.I +++ b/panda/src/pgraph/accumulatedAttribs.I @@ -39,6 +39,7 @@ AccumulatedAttribs(const AccumulatedAttribs ©) : _color(copy._color), _color_scale(copy._color_scale), _tex_matrix(copy._tex_matrix), + _texture(copy._texture), _other(copy._other) { } @@ -54,5 +55,6 @@ operator = (const AccumulatedAttribs ©) { _color = copy._color; _color_scale = copy._color_scale; _tex_matrix = copy._tex_matrix; + _texture = copy._texture; _other = copy._other; } diff --git a/panda/src/pgraph/accumulatedAttribs.cxx b/panda/src/pgraph/accumulatedAttribs.cxx index fcc718e76e..80f709dcfa 100644 --- a/panda/src/pgraph/accumulatedAttribs.cxx +++ b/panda/src/pgraph/accumulatedAttribs.cxx @@ -23,6 +23,7 @@ #include "colorAttrib.h" #include "colorScaleAttrib.h" #include "texMatrixAttrib.h" +#include "textureAttrib.h" #include "config_pgraph.h" @@ -119,9 +120,25 @@ collect(PandaNode *node, int attrib_types) { } node->clear_attrib(TexMatrixAttrib::get_class_type()); } + + // We also need to accumulate the texture state if we are + // accumulating texture matrix. + const RenderAttrib *tex_attrib = + node->get_attrib(TextureAttrib::get_class_type()); + if (tex_attrib != (const RenderAttrib *)NULL) { + if (_texture == (const RenderAttrib *)NULL) { + _texture = tex_attrib; + } else { + _texture = _texture->compose(tex_attrib); + } + + // However, we don't remove the texture state from the node. + // We're just accumulating it so we can tell which texture + // coordinates are safe to flatten. + } } - if ((attrib_types & SceneGraphReducer::TT_transform) != 0) { + if ((attrib_types & SceneGraphReducer::TT_other) != 0) { // Collect everything else. nassertv(_other != (RenderState *)NULL); _other = _other->compose(node->get_state()); @@ -129,6 +146,83 @@ collect(PandaNode *node, int attrib_types) { } } +//////////////////////////////////////////////////////////////////// +// Function: AccumulatedAttribs::collect +// Access: Public +// Description: Collects the state and transform from the indicated +// node and adds it to the accumulator, removing it from +// the state (and returning a new state). +//////////////////////////////////////////////////////////////////// +CPT(RenderState) AccumulatedAttribs:: +collect(const RenderState *state, int attrib_types) { + CPT(RenderState) new_state = state; + + if ((attrib_types & SceneGraphReducer::TT_color) != 0) { + const RenderAttrib *node_attrib = + new_state->get_attrib(ColorAttrib::get_class_type()); + if (node_attrib != (const RenderAttrib *)NULL) { + // The node has a color attribute; apply it. + if (_color == (const RenderAttrib *)NULL) { + _color = node_attrib; + } else { + _color = _color->compose(node_attrib); + } + new_state = new_state->remove_attrib(ColorAttrib::get_class_type()); + } + } + + if ((attrib_types & SceneGraphReducer::TT_color_scale) != 0) { + const RenderAttrib *node_attrib = + new_state->get_attrib(ColorScaleAttrib::get_class_type()); + if (node_attrib != (const RenderAttrib *)NULL) { + if (_color_scale == (const RenderAttrib *)NULL) { + _color_scale = node_attrib; + } else { + _color_scale = _color_scale->compose(node_attrib); + } + new_state = new_state->remove_attrib(ColorScaleAttrib::get_class_type()); + } + } + + if ((attrib_types & SceneGraphReducer::TT_tex_matrix) != 0) { + const RenderAttrib *node_attrib = + new_state->get_attrib(TexMatrixAttrib::get_class_type()); + if (node_attrib != (const RenderAttrib *)NULL) { + if (_tex_matrix == (const RenderAttrib *)NULL) { + _tex_matrix = node_attrib; + } else { + _tex_matrix = _tex_matrix->compose(node_attrib); + } + new_state = new_state->remove_attrib(TexMatrixAttrib::get_class_type()); + } + + // We also need to accumulate the texture state if we are + // accumulating texture matrix. + const RenderAttrib *tex_attrib = + new_state->get_attrib(TextureAttrib::get_class_type()); + if (tex_attrib != (const RenderAttrib *)NULL) { + if (_texture == (const RenderAttrib *)NULL) { + _texture = tex_attrib; + } else { + _texture = _texture->compose(tex_attrib); + } + + // However, we don't remove the texture state from the node. + // We're just accumulating it so we can tell which texture + // coordinates are safe to flatten. + } + } + + if ((attrib_types & SceneGraphReducer::TT_other) != 0) { + // Collect everything else. + nassertr(_other != (RenderState *)NULL, new_state); + _other = _other->compose(new_state); + new_state = RenderState::make_empty(); + } + + return new_state; +} + //////////////////////////////////////////////////////////////////// // Function: AccumulatedAttribs::apply_to_node // Access: Public diff --git a/panda/src/pgraph/accumulatedAttribs.h b/panda/src/pgraph/accumulatedAttribs.h index 516b4ab9d2..03716e9ebe 100644 --- a/panda/src/pgraph/accumulatedAttribs.h +++ b/panda/src/pgraph/accumulatedAttribs.h @@ -43,12 +43,14 @@ public: void write(ostream &out, int attrib_types, int indent_level) const; void collect(PandaNode *node, int attrib_types); + CPT(RenderState) collect(const RenderState *state, int attrib_types); void apply_to_node(PandaNode *node, int attrib_types); CPT(TransformState) _transform; CPT(RenderAttrib) _color; CPT(RenderAttrib) _color_scale; CPT(RenderAttrib) _tex_matrix; + CPT(RenderAttrib) _texture; CPT(RenderState) _other; }; diff --git a/panda/src/pgraph/geomNode.I b/panda/src/pgraph/geomNode.I index 99d16c775e..9fafbaad1c 100644 --- a/panda/src/pgraph/geomNode.I +++ b/panda/src/pgraph/geomNode.I @@ -178,3 +178,32 @@ INLINE CollideMask GeomNode:: get_default_collide_mask() { return default_geom_node_collide_mask; } + +//////////////////////////////////////////////////////////////////// +// Function: GeomNode::count_name +// Access: Private +// Description: Increments the count for the indicated TexCoordName. +//////////////////////////////////////////////////////////////////// +INLINE void GeomNode:: +count_name(GeomNode::NameCount &name_count, const TexCoordName *name) { + pair result = + name_count.insert(NameCount::value_type(name, 1)); + if (!result.second) { + (*result.first).second++; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: GeomNode::get_name_count +// Access: Private +// Description: Returns the count for the indicated TexCoordName. +//////////////////////////////////////////////////////////////////// +INLINE int GeomNode:: +get_name_count(const GeomNode::NameCount &name_count, const TexCoordName *name) { + NameCount::const_iterator ni; + ni = name_count.find(name); + if (ni != name_count.end()) { + return (*ni).second; + } + return 0; +} diff --git a/panda/src/pgraph/geomNode.cxx b/panda/src/pgraph/geomNode.cxx index 25da833c2a..8644f49c96 100644 --- a/panda/src/pgraph/geomNode.cxx +++ b/panda/src/pgraph/geomNode.cxx @@ -188,33 +188,93 @@ apply_attribs_to_vertices(const AccumulatedAttribs &attribs, int attrib_types, transformer.transform_vertices(this, attribs._transform->get_mat()); } } - if ((attrib_types & SceneGraphReducer::TT_color) != 0) { - if (attribs._color != (const RenderAttrib *)NULL) { - const ColorAttrib *ca = DCAST(ColorAttrib, attribs._color); - if (ca->get_color_type() == ColorAttrib::T_flat) { - transformer.set_color(this, ca->get_color()); + + GeomNode::CDWriter cdata(_cycler); + GeomNode::Geoms::iterator gi; + for (gi = cdata->_geoms.begin(); gi != cdata->_geoms.end(); ++gi) { + GeomEntry &entry = (*gi); + PT(Geom) new_geom = entry._geom->make_copy(); + + AccumulatedAttribs geom_attribs = attribs; + entry._state = geom_attribs.collect(entry._state, attrib_types); + + bool any_changed = false; + + if ((attrib_types & SceneGraphReducer::TT_color) != 0) { + if (geom_attribs._color != (const RenderAttrib *)NULL) { + const ColorAttrib *ca = DCAST(ColorAttrib, geom_attribs._color); + if (ca->get_color_type() == ColorAttrib::T_flat) { + if (transformer.set_color(new_geom, ca->get_color())) { + any_changed = true; + } + } } } - } - if ((attrib_types & SceneGraphReducer::TT_color_scale) != 0) { - if (attribs._color_scale != (const RenderAttrib *)NULL) { - const ColorScaleAttrib *csa = DCAST(ColorScaleAttrib, attribs._color_scale); - if (csa->get_scale() != LVecBase4f(1.0f, 1.0f, 1.0f, 1.0f)) { - transformer.transform_colors(this, csa->get_scale()); + if ((attrib_types & SceneGraphReducer::TT_color_scale) != 0) { + if (geom_attribs._color_scale != (const RenderAttrib *)NULL) { + const ColorScaleAttrib *csa = DCAST(ColorScaleAttrib, geom_attribs._color_scale); + if (csa->get_scale() != LVecBase4f(1.0f, 1.0f, 1.0f, 1.0f)) { + if (transformer.transform_colors(new_geom, csa->get_scale())) { + any_changed = true; + } + } } } - } - if ((attrib_types & SceneGraphReducer::TT_tex_matrix) != 0) { - if (attribs._tex_matrix != (const RenderAttrib *)NULL) { - const TexMatrixAttrib *tma = DCAST(TexMatrixAttrib, attribs._tex_matrix); - if (tma->get_mat() != LMatrix4f::ident_mat()) { - transformer.transform_texcoords(this, tma->get_mat()); + if ((attrib_types & SceneGraphReducer::TT_tex_matrix) != 0) { + if (geom_attribs._tex_matrix != (const RenderAttrib *)NULL) { + // Determine which texture coordinate names are used more than + // once. This assumes we have discovered all of the textures + // that are in effect on the geomNode; this may not be true if + // there is a texture that has been applied at a node above + // that from which we started the flatten operation, but + // caveat programmer. + NameCount name_count; + + if (geom_attribs._texture != (RenderAttrib *)NULL) { + const TextureAttrib *ta = DCAST(TextureAttrib, geom_attribs._texture); + int num_on_stages = ta->get_num_on_stages(); + for (int si = 0; si < num_on_stages; si++) { + TextureStage *stage = ta->get_on_stage(si); + const TexCoordName *name = stage->get_texcoord_name(); + count_name(name_count, name); + } + } + + const TexMatrixAttrib *tma = + DCAST(TexMatrixAttrib, geom_attribs._tex_matrix); + + CPT(TexMatrixAttrib) new_tma = DCAST(TexMatrixAttrib, TexMatrixAttrib::make()); + + int num_stages = tma->get_num_stages(); + for (int i = 0; i < num_stages; i++) { + TextureStage *stage = tma->get_stage(i); + const TexCoordName *name = stage->get_texcoord_name(); + if (get_name_count(name_count, name) > 1) { + // We can't transform these texcoords, since the name is + // used by more than one active stage. + new_tma = DCAST(TexMatrixAttrib, new_tma->add_stage(stage, tma->get_transform(stage))); + + } else { + // It's safe to transform these texcoords; the name is + // used by no more than one active stage. + if (transformer.transform_texcoords(new_geom, name, name, tma->get_mat(stage))) { + any_changed = true; + } + } + } + + if (!new_tma->is_empty()) { + entry._state = entry._state->add_attrib(new_tma); + } } } - } - if ((attrib_types & SceneGraphReducer::TT_other) != 0) { - if (!attribs._other->is_empty()) { - transformer.apply_state(this, attribs._other); + + if (any_changed) { + entry._geom = new_geom; + } + + if ((attrib_types & SceneGraphReducer::TT_other) != 0) { + entry._state = geom_attribs._other->compose(entry._state); } } } diff --git a/panda/src/pgraph/geomNode.h b/panda/src/pgraph/geomNode.h index 35260997ea..c6f8138e74 100644 --- a/panda/src/pgraph/geomNode.h +++ b/panda/src/pgraph/geomNode.h @@ -92,6 +92,10 @@ public: private: typedef pvector Geoms; + typedef pmap NameCount; + + INLINE void count_name(NameCount &name_count, const TexCoordName *name); + INLINE int get_name_count(const NameCount &name_count, const TexCoordName *name); // This is the data that must be cycled between pipeline stages. class EXPCL_PANDA CData : public CycleData { diff --git a/panda/src/pgraph/geomTransformer.cxx b/panda/src/pgraph/geomTransformer.cxx index 13ecc831ab..d5bfb0be66 100644 --- a/panda/src/pgraph/geomTransformer.cxx +++ b/panda/src/pgraph/geomTransformer.cxx @@ -150,18 +150,16 @@ transform_vertices(GeomNode *node, const LMatrix4f &mat) { // Geom was changed, false otherwise. //////////////////////////////////////////////////////////////////// bool GeomTransformer:: -transform_texcoords(Geom *geom, const LMatrix4f &mat) { +transform_texcoords(Geom *geom, const TexCoordName *from_name, + const TexCoordName *to_name, const LMatrix4f &mat) { bool transformed = false; nassertr(geom != (Geom *)NULL, false); - PTA_TexCoordf texcoords; - GeomBindType bind; - PTA_ushort index; + PTA_TexCoordf texcoords = geom->get_texcoords_array(from_name); + PTA_ushort index = geom->get_texcoords_index(from_name); - geom->get_texcoords(texcoords, bind, index); - - if (bind != G_OFF) { + if (!texcoords.is_null()) { // Look up the Geom's texcoords in our table--have we already // transformed this array? SourceTexCoords stc; @@ -183,7 +181,7 @@ transform_texcoords(Geom *geom, const LMatrix4f &mat) { nassertr(new_texcoords.size() == texcoords.size(), false); } - geom->set_texcoords(new_texcoords, bind, index); + geom->set_texcoords(to_name, new_texcoords, index); transformed = true; } @@ -203,7 +201,8 @@ transform_texcoords(Geom *geom, const LMatrix4f &mat) { // false otherwise. //////////////////////////////////////////////////////////////////// bool GeomTransformer:: -transform_texcoords(GeomNode *node, const LMatrix4f &mat) { +transform_texcoords(GeomNode *node, const TexCoordName *from_name, + const TexCoordName *to_name, const LMatrix4f &mat) { bool any_changed = false; GeomNode::CDWriter cdata(node->_cycler); @@ -211,7 +210,7 @@ transform_texcoords(GeomNode *node, const LMatrix4f &mat) { for (gi = cdata->_geoms.begin(); gi != cdata->_geoms.end(); ++gi) { GeomNode::GeomEntry &entry = (*gi); PT(Geom) new_geom = entry._geom->make_copy(); - if (transform_texcoords(new_geom, mat)) { + if (transform_texcoords(new_geom, from_name, to_name, mat)) { entry._geom = new_geom; any_changed = true; } diff --git a/panda/src/pgraph/geomTransformer.h b/panda/src/pgraph/geomTransformer.h index 3356beeb29..a25b9f3353 100644 --- a/panda/src/pgraph/geomTransformer.h +++ b/panda/src/pgraph/geomTransformer.h @@ -26,6 +26,7 @@ class GeomNode; class RenderState; +class TexCoordName; /////////////////////////////////////////////////////////////////// // Class : GeomTransformer @@ -51,8 +52,12 @@ public: bool transform_vertices(Geom *geom, const LMatrix4f &mat); bool transform_vertices(GeomNode *node, const LMatrix4f &mat); - bool transform_texcoords(Geom *geom, const LMatrix4f &mat); - bool transform_texcoords(GeomNode *node, const LMatrix4f &mat); + bool transform_texcoords(Geom *geom, const TexCoordName *from_name, + const TexCoordName *to_name, + const LMatrix4f &mat); + bool transform_texcoords(GeomNode *node, const TexCoordName *from_name, + const TexCoordName *to_name, + const LMatrix4f &mat); bool set_color(Geom *geom, const Colorf &color); bool set_color(GeomNode *node, const Colorf &color); diff --git a/panda/src/pgraph/texMatrixAttrib.I b/panda/src/pgraph/texMatrixAttrib.I index b63a460251..cc1da4acfb 100644 --- a/panda/src/pgraph/texMatrixAttrib.I +++ b/panda/src/pgraph/texMatrixAttrib.I @@ -24,7 +24,7 @@ // TexMatrixAttrib object. //////////////////////////////////////////////////////////////////// INLINE TexMatrixAttrib:: -TexMatrixAttrib() { +TexMatrixAttrib() : _stage_list_stale(true) { } //////////////////////////////////////////////////////////////////// @@ -35,6 +35,20 @@ TexMatrixAttrib() { //////////////////////////////////////////////////////////////////// INLINE TexMatrixAttrib:: TexMatrixAttrib(const TexMatrixAttrib ©) : - _stages(copy._stages) + _stages(copy._stages), + _stage_list_stale(true) { } + +//////////////////////////////////////////////////////////////////// +// Function: TexMatrixAttrib::check_stage_list +// Access: Private +// Description: Builds the linear list of TextureStages if it needs +// to be built. +//////////////////////////////////////////////////////////////////// +void TexMatrixAttrib:: +check_stage_list() const { + if (_stage_list_stale) { + ((TexMatrixAttrib *)this)->rebuild_stage_list(); + } +} diff --git a/panda/src/pgraph/texMatrixAttrib.cxx b/panda/src/pgraph/texMatrixAttrib.cxx index 799024fc14..39d3f0805d 100644 --- a/panda/src/pgraph/texMatrixAttrib.cxx +++ b/panda/src/pgraph/texMatrixAttrib.cxx @@ -61,6 +61,9 @@ make() { //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) TexMatrixAttrib:: make(const LMatrix4f &mat) { + if (mat == LMatrix4f::ident_mat()) { + return make(); + } CPT(TransformState) transform = TransformState::make_mat(mat); return make(TextureStage::get_default(), transform); } @@ -73,6 +76,9 @@ make(const LMatrix4f &mat) { //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) TexMatrixAttrib:: make(const TransformState *transform) { + if (transform->is_identity()) { + return make(); + } return make(TextureStage::get_default(), transform); } @@ -84,6 +90,9 @@ make(const TransformState *transform) { //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) TexMatrixAttrib:: make(TextureStage *stage, const TransformState *transform) { + if (transform->is_identity()) { + return make(); + } TexMatrixAttrib *attrib = new TexMatrixAttrib; attrib->_stages.insert(Stages::value_type(stage, transform)); return return_new(attrib); @@ -98,6 +107,9 @@ make(TextureStage *stage, const TransformState *transform) { //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) TexMatrixAttrib:: add_stage(TextureStage *stage, const TransformState *transform) const { + if (transform->is_identity()) { + return remove_stage(stage); + } TexMatrixAttrib *attrib = new TexMatrixAttrib(*this); attrib->_stages[stage] = transform; return return_new(attrib); @@ -152,6 +164,31 @@ has_stage(TextureStage *stage) const { return (mi != _stages.end()); } +//////////////////////////////////////////////////////////////////// +// Function: TexMatrixAttrib::get_num_stages +// Access: Published +// Description: Returns the number of stages that are represented by +// this attrib. +//////////////////////////////////////////////////////////////////// +int TexMatrixAttrib:: +get_num_stages() const { + return _stages.size(); +} + +//////////////////////////////////////////////////////////////////// +// Function: TexMatrixAttrib::get_stage +// Access: Published +// Description: Returns the nth stage that is represented by this +// attrib. The TextureStages are in no particular +// order. +//////////////////////////////////////////////////////////////////// +TextureStage *TexMatrixAttrib:: +get_stage(int n) const { + nassertr(n >= 0 && n < (int)_stages.size(), NULL); + check_stage_list(); + return _stage_list[n]; +} + //////////////////////////////////////////////////////////////////// // Function: TexMatrixAttrib::get_mat // Access: Published @@ -427,6 +464,25 @@ make_default_impl() const { return new TexMatrixAttrib; } +//////////////////////////////////////////////////////////////////// +// Function: TexMatrixAttrib::rebuild_stage_list +// Access: Private +// Description: Builds the linear list of TextureStages, the first +// time someone asks for it. +//////////////////////////////////////////////////////////////////// +void TexMatrixAttrib:: +rebuild_stage_list() { + _stage_list.clear(); + _stage_list.reserve(_stages.size()); + + Stages::const_iterator si; + for (si = _stages.begin(); si != _stages.end(); ++si) { + _stage_list.push_back((*si).first); + } + + _stage_list_stale = false; +} + //////////////////////////////////////////////////////////////////// // Function: TexMatrixAttrib::register_with_read_factory // Access: Public, Static diff --git a/panda/src/pgraph/texMatrixAttrib.h b/panda/src/pgraph/texMatrixAttrib.h index b2fd5e093d..48058ef185 100644 --- a/panda/src/pgraph/texMatrixAttrib.h +++ b/panda/src/pgraph/texMatrixAttrib.h @@ -53,6 +53,9 @@ PUBLISHED: bool is_empty() const; bool has_stage(TextureStage *stage) const; + int get_num_stages() const; + TextureStage *get_stage(int n) const; + const LMatrix4f &get_mat() const; const LMatrix4f &get_mat(TextureStage *stage) const; @@ -69,9 +72,16 @@ protected: virtual RenderAttrib *make_default_impl() const; private: + INLINE void check_stage_list() const; + void rebuild_stage_list(); + typedef pmap< PT(TextureStage), CPT(TransformState) > Stages; Stages _stages; + typedef pvector StageList; + StageList _stage_list; + bool _stage_list_stale; + // This element is only used during reading from a bam file. It has // no meaningful value any other time. size_t _num_stages; diff --git a/panda/src/testbed/pview.cxx b/panda/src/testbed/pview.cxx index d898f09bb3..1a2197332a 100644 --- a/panda/src/testbed/pview.cxx +++ b/panda/src/testbed/pview.cxx @@ -114,6 +114,7 @@ event_0(CPT_Event event, void *) { static PT(TextureStage) ts; if (ts == (TextureStage *)NULL) { ts = new TextureStage("ts"); + ts->set_sort(50); } NodePath models = framework.get_models();