瀏覽代碼

better GeomTransformer, flatten operations

David Rose 21 年之前
父節點
當前提交
c23be69d2b

+ 2 - 0
panda/src/pgraph/accumulatedAttribs.I

@@ -39,6 +39,7 @@ AccumulatedAttribs(const AccumulatedAttribs &copy) :
   _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 &copy) {
   _color = copy._color;
   _color_scale = copy._color_scale;
   _tex_matrix = copy._tex_matrix;
+  _texture = copy._texture;
   _other = copy._other;
 }

+ 95 - 1
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

+ 2 - 0
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;
 };
 

+ 29 - 0
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<NameCount::iterator, bool> 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;
+}

+ 81 - 21
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);
     }
   }
 }

+ 4 - 0
panda/src/pgraph/geomNode.h

@@ -92,6 +92,10 @@ public:
 
 private:
   typedef pvector<GeomEntry> Geoms;
+  typedef pmap<const TexCoordName *, int> 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 {

+ 9 - 10
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;
     }

+ 7 - 2
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);

+ 16 - 2
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 &copy) :
-  _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();
+  }
+}

+ 56 - 0
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

+ 10 - 0
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<TextureStage *> 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;

+ 1 - 0
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();