Parcourir la source

apply texture coords after flattening

David Rose il y a 21 ans
Parent
commit
338b93d6cf

+ 12 - 0
panda/src/grutil/multitexReducer.I

@@ -99,3 +99,15 @@ GeomInfo(const RenderState *state, const RenderState *geom_net_state,
   _index(index)
   _index(index)
 {
 {
 }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: MultitexReducer::GeomNodeInfo::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE MultitexReducer::GeomNodeInfo::
+GeomNodeInfo(const RenderState *state, GeomNode *geom_node) :
+  _state(state),
+  _geom_node(geom_node)
+{
+}

+ 166 - 12
panda/src/grutil/multitexReducer.cxx

@@ -20,6 +20,9 @@
 #include "pandaNode.h"
 #include "pandaNode.h"
 #include "geomNode.h"
 #include "geomNode.h"
 #include "geom.h"
 #include "geom.h"
+#include "geomTransformer.h"
+#include "accumulatedAttribs.h"
+#include "sceneGraphReducer.h"
 #include "renderState.h"
 #include "renderState.h"
 #include "transformState.h"
 #include "transformState.h"
 #include "graphicsOutput.h"
 #include "graphicsOutput.h"
@@ -65,6 +68,7 @@ MultitexReducer::
 void MultitexReducer::
 void MultitexReducer::
 clear() {
 clear() {
   _stages.clear();
   _stages.clear();
+  _geom_node_list.clear();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -288,17 +292,45 @@ flatten(GraphicsOutput *window) {
     NodePath cam = render.attach_new_node(cam_node);
     NodePath cam = render.attach_new_node(cam_node);
     dr->set_camera(cam);
     dr->set_camera(cam);
 
 
-    if (!_use_geom) {
-      // Put one plain white card in the background for the first
-      // texture layer to apply onto.
+    // If the geometry has vertex color and M_decal is in use, we must
+    // render with use_geom in effect.  Otherwise we need not (and we
+    // might prefer not to).
+    bool force_use_geom = _use_geom;
+    bool bake_in_color = _use_geom;
+
+    Colorf geom_color(1.0f, 1.0f, 1.0f, 1.0f);
+    if (!force_use_geom) {
+      bool uses_decal = scan_decal(stage_list);
+      if (uses_decal) {
+        // If we have M_decal, we need to bake in the flat color
+        // even if there is no vertex color.
+        bake_in_color = true;
+
+        int num_colors = 0;
+        scan_color(geom_list, geom_color, num_colors);
+        if (num_colors > 1) {
+          // But if there is also vertex color, then we need to render
+          // with the geometry.
+          force_use_geom = true;
+        }
+      }
+    }
+    
+    if (!force_use_geom) {
+      // Put one plain white (or flat-colored) card in the background
+      // for the first texture layer to apply onto.
       
       
       CardMaker cm("background");
       CardMaker cm("background");
       cm.set_frame(0.0f, 1.0f, 0.0f, 1.0f);
       cm.set_frame(0.0f, 1.0f, 0.0f, 1.0f);
+      if (bake_in_color) {
+        cm.set_color(geom_color);
+      }
       render.attach_new_node(cm.generate());
       render.attach_new_node(cm.generate());
 
 
     } else {
     } else {
-      // Put a colored model of the geometry in the background for the
-      // first texture layer to apply only.
+      // Put a vertex-colored model of the geometry in the background
+      // for the first texture layer to apply only.
+      nassertv(bake_in_color);
       PT(GeomNode) geom_node = new GeomNode("background");
       PT(GeomNode) geom_node = new GeomNode("background");
       transfer_geom(geom_node, NULL, geom_list, true);
       transfer_geom(geom_node, NULL, geom_list, true);
       
       
@@ -309,7 +341,7 @@ flatten(GraphicsOutput *window) {
     for (si = stage_list.begin(); si != stage_list.end(); ++si) {
     for (si = stage_list.begin(); si != stage_list.end(); ++si) {
       const StageInfo &stage_info = (*si);
       const StageInfo &stage_info = (*si);
 
 
-      make_texture_layer(render, stage_info, geom_list);
+      make_texture_layer(render, stage_info, geom_list, force_use_geom);
     }
     }
 
 
     // Now modify the geometry to apply the new texture, instead of
     // Now modify the geometry to apply the new texture, instead of
@@ -325,10 +357,9 @@ flatten(GraphicsOutput *window) {
         geom_info._geom_node->get_geom_state(geom_info._index);
         geom_info._geom_node->get_geom_state(geom_info._index);
       geom_state = geom_state->add_attrib(new_ta);
       geom_state = geom_state->add_attrib(new_ta);
 
 
-      if (_use_geom) {
-        // If we have use_geom in effect, we have to be sure to
-        // disable coloring on the new fragment (the color has been
-        // baked into the texture).
+      if (bake_in_color) {
+        // If we have baked the color into the texture, we have to be
+        // sure to disable coloring on the new fragment.
         geom_state = geom_state->add_attrib(ColorAttrib::make_flat(Colorf(1.0f, 1.0f, 1.0f, 1.0f)));
         geom_state = geom_state->add_attrib(ColorAttrib::make_flat(Colorf(1.0f, 1.0f, 1.0f, 1.0f)));
 
 
         // And we invent a ColorScaleAttrib to undo the effect of any
         // And we invent a ColorScaleAttrib to undo the effect of any
@@ -374,6 +405,20 @@ flatten(GraphicsOutput *window) {
       geom_info._geom_node->set_geom_state(geom_info._index, geom_state);
       geom_info._geom_node->set_geom_state(geom_info._index, geom_state);
     }
     }
   }
   }
+
+  // Now that we've copied all of the geometry and applied texture
+  // matrices, flatten out those texture matrices where possible.
+  GeomTransformer transformer;
+
+  GeomNodeList::const_iterator gni;
+  for (gni = _geom_node_list.begin(); gni != _geom_node_list.end(); ++gni) {
+    const GeomNodeInfo &geom_node_info = (*gni);
+    AccumulatedAttribs attribs;
+    attribs._texture = 
+      geom_node_info._state->get_attrib(TextureAttrib::get_class_type());
+    geom_node_info._geom_node->apply_attribs_to_vertices
+      (attribs, SceneGraphReducer::TT_tex_matrix, transformer);
+  }
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -391,6 +436,8 @@ scan_geom_node(GeomNode *node, const RenderState *state,
       << *transform << ")\n";
       << *transform << ")\n";
   }
   }
 
 
+  _geom_node_list.push_back(GeomNodeInfo(state, node));
+
   int num_geoms = node->get_num_geoms();
   int num_geoms = node->get_num_geoms();
   for (int gi = 0; gi < num_geoms; gi++) {
   for (int gi = 0; gi < num_geoms; gi++) {
     CPT(RenderState) geom_net_state = 
     CPT(RenderState) geom_net_state = 
@@ -653,7 +700,8 @@ choose_texture_size(int &x_size, int &y_size,
 void MultitexReducer::
 void MultitexReducer::
 make_texture_layer(const NodePath &render, 
 make_texture_layer(const NodePath &render, 
                    const MultitexReducer::StageInfo &stage_info, 
                    const MultitexReducer::StageInfo &stage_info, 
-                   const MultitexReducer::GeomList &geom_list) {
+                   const MultitexReducer::GeomList &geom_list,
+                   bool force_use_geom) {
   CPT(RenderAttrib) cba;
   CPT(RenderAttrib) cba;
 
 
   switch (stage_info._stage->get_mode()) {
   switch (stage_info._stage->get_mode()) {
@@ -697,7 +745,7 @@ make_texture_layer(const NodePath &render,
 
 
   NodePath geom;
   NodePath geom;
 
 
-  if (!_use_geom && stage_info._stage->get_texcoord_name() == _target_stage->get_texcoord_name()) {
+  if (!force_use_geom && stage_info._stage->get_texcoord_name() == _target_stage->get_texcoord_name()) {
     // If this TextureStage uses the target texcoords, we can just
     // If this TextureStage uses the target texcoords, we can just
     // generate a simple card the fills the entire buffer.
     // generate a simple card the fills the entire buffer.
     CardMaker cm(stage_info._tex->get_name());
     CardMaker cm(stage_info._tex->get_name());
@@ -787,6 +835,111 @@ transfer_geom(GeomNode *geom_node, const TexCoordName *texcoord_name,
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: MultitexReducer::scan_color
+//       Access: Private
+//  Description: Checks all the geoms in the list to see if they all
+//               use flat color, or if there is per-vertex color in
+//               use.
+//
+//               Assumption: num_colors = 0 on entry.  On exit,
+//               num_colors = 1 if there is exactly one color in use,
+//               or 2 if there is more than one color in use.  If
+//               num_colors = 1, then geom_color is filled in with the
+//               color in use.
+////////////////////////////////////////////////////////////////////
+void MultitexReducer::
+scan_color(const MultitexReducer::GeomList &geom_list, Colorf &geom_color, 
+           int &num_colors) const {
+  GeomList::const_iterator gi;
+  for (gi = geom_list.begin(); gi != geom_list.end() && num_colors < 2; ++gi) {
+    const GeomInfo &geom_info = (*gi);
+    
+    Colorf flat_color;
+    bool has_flat_color = false;
+    bool has_vertex_color = false;
+
+    Colorf color_scale(1.0f, 1.0f, 1.0f, 1.0f);
+    const RenderAttrib *csa = geom_info._geom_net_state->get_attrib(ColorScaleAttrib::get_class_type());
+    if (csa != (const RenderAttrib *)NULL) {
+      const ColorScaleAttrib *a = DCAST(ColorScaleAttrib, csa);
+      if (a->has_scale()) {
+        color_scale = a->get_scale();
+      }
+    }
+
+    ColorAttrib::Type color_type = ColorAttrib::T_vertex;
+    const RenderAttrib *ca = geom_info._geom_net_state->get_attrib(ColorAttrib::get_class_type());
+    if (ca != (const RenderAttrib *)NULL) {
+      color_type = DCAST(ColorAttrib, ca)->get_color_type();
+    }
+
+    if (color_type == ColorAttrib::T_flat) {
+      // This geom has a flat color attrib, which overrides the vertices.
+      flat_color = DCAST(ColorAttrib, ca)->get_color();
+      has_flat_color = true;
+
+    } else if (color_type == ColorAttrib::T_vertex) {
+      // This geom gets its color from its vertices.
+      const Geom *geom = geom_info._geom_node->get_geom(geom_info._index);
+
+      int binding = geom->get_binding(G_COLOR);
+      if (binding == G_OVERALL) {
+        // This geom has a flat color on its vertices.
+        Geom::ColorIterator ci = geom->make_color_iterator();
+        flat_color = geom->get_next_color(ci);
+        has_flat_color = true;
+
+      } else if (binding != G_OFF) {
+        // This geom has per-vertex (or per-prim, or per-component)
+        // color.  Assume the colors in the table are actually
+        // different.
+        has_vertex_color = true;
+      }
+    }
+
+    if (has_vertex_color) {
+      num_colors = 2;
+
+    } else if (has_flat_color) {
+      flat_color.set(flat_color[0] * color_scale[0],
+                     flat_color[1] * color_scale[1],
+                     flat_color[2] * color_scale[2],
+                     flat_color[3] * color_scale[3]);
+
+      if (num_colors == 0) {
+        num_colors = 1;
+        geom_color = flat_color;
+
+      } else if (!flat_color.almost_equal(geom_color)) {
+        // Too bad; there are multiple colors.
+        num_colors = 2;
+      }
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MultitexReducer::scan_decal
+//       Access: Private
+//  Description: Checks all the stages in the list to see if any of
+//               them apply a texture via M_decal.  Returns true if
+//               so, false otherwise.
+////////////////////////////////////////////////////////////////////
+bool MultitexReducer::
+scan_decal(const MultitexReducer::StageList &stage_list) const {
+  StageList::const_iterator si;
+  for (si = stage_list.begin(); si != stage_list.end(); ++si) {
+    const StageInfo &stage_info = (*si);
+
+    if (stage_info._stage->get_mode() == TextureStage::M_decal) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: MultitexReducer::StageInfo::Constructor
 //     Function: MultitexReducer::StageInfo::Constructor
@@ -804,3 +957,4 @@ StageInfo(TextureStage *stage, const TextureAttrib *ta,
     _tex_mat = tma->get_transform(stage);
     _tex_mat = tma->get_transform(stage);
   }
   }
 }
 }
+

+ 17 - 1
panda/src/grutil/multitexReducer.h

@@ -98,8 +98,18 @@ private:
 
 
   typedef pvector<GeomInfo> GeomList;
   typedef pvector<GeomInfo> GeomList;
 
 
+  class GeomNodeInfo {
+  public:
+    INLINE GeomNodeInfo(const RenderState *state, GeomNode *geom_node);
+    CPT(RenderState) _state;
+    PT(GeomNode) _geom_node;
+  };
+
+  typedef pvector<GeomNodeInfo> GeomNodeList;
+
   typedef pmap<StageList, GeomList> Stages;
   typedef pmap<StageList, GeomList> Stages;
   Stages _stages;
   Stages _stages;
+  GeomNodeList _geom_node_list;
 
 
   PT(TextureStage) _target_stage;
   PT(TextureStage) _target_stage;
   bool _use_geom;
   bool _use_geom;
@@ -127,9 +137,15 @@ private:
 
 
   void make_texture_layer(const NodePath &render, 
   void make_texture_layer(const NodePath &render, 
                           const StageInfo &stage_info, 
                           const StageInfo &stage_info, 
-                          const GeomList &geom_list);
+                          const GeomList &geom_list,
+                          bool force_use_geom);
   void transfer_geom(GeomNode *geom_node, const TexCoordName *texcoord_name,
   void transfer_geom(GeomNode *geom_node, const TexCoordName *texcoord_name,
                      const GeomList &geom_list, bool preserve_color);
                      const GeomList &geom_list, bool preserve_color);
+
+  void scan_color(const GeomList &geom_list, Colorf &geom_color, 
+                  int &num_colors) const;
+  bool scan_decal(const StageList &stage_list) const;
+
 };
 };
 
 
 #include "multitexReducer.I"
 #include "multitexReducer.I"

+ 2 - 2
panda/src/testbed/pview.cxx

@@ -126,7 +126,7 @@ event_0(CPT_Event event, void *) {
   } else {
   } else {
     cerr << "flattening\n";
     cerr << "flattening\n";
     MultitexReducer mr;
     MultitexReducer mr;
-    mr.set_use_geom(true);
+    //mr.set_use_geom(true);
     mr.scan(models);
     mr.scan(models);
     
     
     WindowFramework *wf = framework.get_window(0);
     WindowFramework *wf = framework.get_window(0);
@@ -138,7 +138,7 @@ event_0(CPT_Event event, void *) {
       if (tex != (Texture *)NULL) {
       if (tex != (Texture *)NULL) {
         cerr << "Reapplying\n";
         cerr << "Reapplying\n";
         
         
-        ts->set_mode(TextureStage::M_decal);
+        ts->set_mode(TextureStage::M_add);
         models.set_texture(ts, tex);
         models.set_texture(ts, tex);
      
      
         if (count > 3 && (count % 2) == 1) {
         if (count > 3 && (count % 2) == 1) {