Browse Source

Fix various issues in bam2egg:
* No longer inserts an extra root group for the ModelRoot
* Support depth test, offset and cull bin attributes
* Preserve non-GeomNodes under Character
* Render attributes are applied on group level if possible

rdb 9 years ago
parent
commit
0bdafe45ce

+ 8 - 1
panda/src/egg/eggLine.cxx

@@ -17,7 +17,6 @@
 
 
 TypeHandle EggLine::_type_handle;
 TypeHandle EggLine::_type_handle;
 
 
-
 /**
 /**
  *
  *
  */
  */
@@ -26,6 +25,14 @@ EggLine::
   clear();
   clear();
 }
 }
 
 
+/**
+ * Makes a copy of this object.
+ */
+EggLine *EggLine::
+make_copy() const {
+  return new EggLine(*this);
+}
+
 /**
 /**
  * Writes the point to the indicated output stream in Egg format.
  * Writes the point to the indicated output stream in Egg format.
  */
  */

+ 2 - 0
panda/src/egg/eggLine.h

@@ -29,6 +29,8 @@ PUBLISHED:
   INLINE EggLine &operator = (const EggLine &copy);
   INLINE EggLine &operator = (const EggLine &copy);
   virtual ~EggLine();
   virtual ~EggLine();
 
 
+  virtual EggLine *make_copy() const OVERRIDE;
+
   virtual void write(ostream &out, int indent_level) const;
   virtual void write(ostream &out, int indent_level) const;
 
 
   INLINE bool has_thick() const;
   INLINE bool has_thick() const;

+ 8 - 0
panda/src/egg/eggNurbsCurve.cxx

@@ -17,6 +17,14 @@
 
 
 TypeHandle EggNurbsCurve::_type_handle;
 TypeHandle EggNurbsCurve::_type_handle;
 
 
+/**
+ * Makes a copy of this object.
+ */
+EggNurbsCurve *EggNurbsCurve::
+make_copy() const {
+  return new EggNurbsCurve(*this);
+}
+
 /**
 /**
  * Prepares a new curve definition with the indicated order and number of
  * Prepares a new curve definition with the indicated order and number of
  * knots.  This also implies a particular number of vertices as well (the
  * knots.  This also implies a particular number of vertices as well (the

+ 2 - 0
panda/src/egg/eggNurbsCurve.h

@@ -29,6 +29,8 @@ PUBLISHED:
   INLINE EggNurbsCurve(const EggNurbsCurve &copy);
   INLINE EggNurbsCurve(const EggNurbsCurve &copy);
   INLINE EggNurbsCurve &operator = (const EggNurbsCurve &copy);
   INLINE EggNurbsCurve &operator = (const EggNurbsCurve &copy);
 
 
+  virtual EggNurbsCurve *make_copy() const OVERRIDE;
+
   void setup(int order, int num_knots);
   void setup(int order, int num_knots);
 
 
   INLINE void set_order(int order);
   INLINE void set_order(int order);

+ 8 - 0
panda/src/egg/eggNurbsSurface.cxx

@@ -17,6 +17,14 @@
 
 
 TypeHandle EggNurbsSurface::_type_handle;
 TypeHandle EggNurbsSurface::_type_handle;
 
 
+/**
+ * Makes a copy of this object.
+ */
+EggNurbsSurface *EggNurbsSurface::
+make_copy() const {
+  return new EggNurbsSurface(*this);
+}
+
 /**
 /**
  * Prepares a new surface definition with the indicated order and number of
  * Prepares a new surface definition with the indicated order and number of
  * knots in each dimension.  This also implies a particular number of vertices
  * knots in each dimension.  This also implies a particular number of vertices

+ 2 - 0
panda/src/egg/eggNurbsSurface.h

@@ -36,6 +36,8 @@ PUBLISHED:
   INLINE EggNurbsSurface(const EggNurbsSurface &copy);
   INLINE EggNurbsSurface(const EggNurbsSurface &copy);
   INLINE EggNurbsSurface &operator = (const EggNurbsSurface &copy);
   INLINE EggNurbsSurface &operator = (const EggNurbsSurface &copy);
 
 
+  virtual EggNurbsSurface *make_copy() const OVERRIDE;
+
   void setup(int u_order, int v_order,
   void setup(int u_order, int v_order,
              int num_u_knots, int num_v_knots);
              int num_u_knots, int num_v_knots);
 
 

+ 7 - 0
panda/src/egg/eggPatch.cxx

@@ -21,6 +21,13 @@
 
 
 TypeHandle EggPatch::_type_handle;
 TypeHandle EggPatch::_type_handle;
 
 
+/**
+ * Makes a copy of this object.
+ */
+EggPatch *EggPatch::
+make_copy() const {
+  return new EggPatch(*this);
+}
 
 
 /**
 /**
  * Writes the patch to the indicated output stream in Egg format.
  * Writes the patch to the indicated output stream in Egg format.

+ 2 - 0
panda/src/egg/eggPatch.h

@@ -28,6 +28,8 @@ PUBLISHED:
   INLINE EggPatch(const EggPatch &copy);
   INLINE EggPatch(const EggPatch &copy);
   INLINE EggPatch &operator = (const EggPatch &copy);
   INLINE EggPatch &operator = (const EggPatch &copy);
 
 
+  virtual EggPatch *make_copy() const OVERRIDE;
+
   virtual void write(ostream &out, int indent_level) const;
   virtual void write(ostream &out, int indent_level) const;
 
 
 public:
 public:

+ 7 - 0
panda/src/egg/eggPoint.cxx

@@ -17,6 +17,13 @@
 
 
 TypeHandle EggPoint::_type_handle;
 TypeHandle EggPoint::_type_handle;
 
 
+/**
+ * Makes a copy of this object.
+ */
+EggPoint *EggPoint::
+make_copy() const {
+  return new EggPoint(*this);
+}
 
 
 /**
 /**
  * Cleans up modeling errors in whatever context this makes sense.  For
  * Cleans up modeling errors in whatever context this makes sense.  For

+ 2 - 0
panda/src/egg/eggPoint.h

@@ -28,6 +28,8 @@ PUBLISHED:
   INLINE EggPoint(const EggPoint &copy);
   INLINE EggPoint(const EggPoint &copy);
   INLINE EggPoint &operator = (const EggPoint &copy);
   INLINE EggPoint &operator = (const EggPoint &copy);
 
 
+  virtual EggPoint *make_copy() const OVERRIDE;
+
   INLINE bool has_thick() const;
   INLINE bool has_thick() const;
   INLINE double get_thick() const;
   INLINE double get_thick() const;
   INLINE void set_thick(double thick);
   INLINE void set_thick(double thick);

+ 7 - 0
panda/src/egg/eggPolygon.cxx

@@ -21,6 +21,13 @@
 
 
 TypeHandle EggPolygon::_type_handle;
 TypeHandle EggPolygon::_type_handle;
 
 
+/**
+ * Makes a copy of this object.
+ */
+EggPolygon *EggPolygon::
+make_copy() const {
+  return new EggPolygon(*this);
+}
 
 
 /**
 /**
  * Cleans up modeling errors in whatever context this makes sense.  For
  * Cleans up modeling errors in whatever context this makes sense.  For

+ 2 - 0
panda/src/egg/eggPolygon.h

@@ -27,6 +27,8 @@ PUBLISHED:
   INLINE EggPolygon(const EggPolygon &copy);
   INLINE EggPolygon(const EggPolygon &copy);
   INLINE EggPolygon &operator = (const EggPolygon &copy);
   INLINE EggPolygon &operator = (const EggPolygon &copy);
 
 
+  virtual EggPolygon *make_copy() const OVERRIDE;
+
   virtual bool cleanup();
   virtual bool cleanup();
 
 
   bool calculate_normal(LNormald &result, CoordinateSystem cs = CS_default) const;
   bool calculate_normal(LNormald &result, CoordinateSystem cs = CS_default) const;

+ 2 - 0
panda/src/egg/eggPrimitive.h

@@ -72,6 +72,8 @@ PUBLISHED:
   INLINE EggPrimitive &operator = (const EggPrimitive &copy);
   INLINE EggPrimitive &operator = (const EggPrimitive &copy);
   INLINE ~EggPrimitive();
   INLINE ~EggPrimitive();
 
 
+  virtual EggPrimitive *make_copy() const=0;
+
   virtual EggRenderMode *determine_alpha_mode();
   virtual EggRenderMode *determine_alpha_mode();
   virtual EggRenderMode *determine_depth_write_mode();
   virtual EggRenderMode *determine_depth_write_mode();
   virtual EggRenderMode *determine_depth_test_mode();
   virtual EggRenderMode *determine_depth_test_mode();

+ 8 - 1
panda/src/egg/eggTriangleFan.cxx

@@ -18,7 +18,6 @@
 
 
 TypeHandle EggTriangleFan::_type_handle;
 TypeHandle EggTriangleFan::_type_handle;
 
 
-
 /**
 /**
  *
  *
  */
  */
@@ -27,6 +26,14 @@ EggTriangleFan::
   clear();
   clear();
 }
 }
 
 
+/**
+ * Makes a copy of this object.
+ */
+EggTriangleFan *EggTriangleFan::
+make_copy() const {
+  return new EggTriangleFan(*this);
+}
+
 /**
 /**
  * Writes the triangle fan to the indicated output stream in Egg format.
  * Writes the triangle fan to the indicated output stream in Egg format.
  */
  */

+ 2 - 0
panda/src/egg/eggTriangleFan.h

@@ -29,6 +29,8 @@ PUBLISHED:
   INLINE EggTriangleFan &operator = (const EggTriangleFan &copy);
   INLINE EggTriangleFan &operator = (const EggTriangleFan &copy);
   virtual ~EggTriangleFan();
   virtual ~EggTriangleFan();
 
 
+  virtual EggTriangleFan *make_copy() const OVERRIDE;
+
   virtual void write(ostream &out, int indent_level) const;
   virtual void write(ostream &out, int indent_level) const;
   virtual void apply_first_attribute();
   virtual void apply_first_attribute();
 
 

+ 8 - 1
panda/src/egg/eggTriangleStrip.cxx

@@ -18,7 +18,6 @@
 
 
 TypeHandle EggTriangleStrip::_type_handle;
 TypeHandle EggTriangleStrip::_type_handle;
 
 
-
 /**
 /**
  *
  *
  */
  */
@@ -27,6 +26,14 @@ EggTriangleStrip::
   clear();
   clear();
 }
 }
 
 
+/**
+ * Makes a copy of this object.
+ */
+EggTriangleStrip *EggTriangleStrip::
+make_copy() const {
+  return new EggTriangleStrip(*this);
+}
+
 /**
 /**
  * Writes the triangle strip to the indicated output stream in Egg format.
  * Writes the triangle strip to the indicated output stream in Egg format.
  */
  */

+ 2 - 0
panda/src/egg/eggTriangleStrip.h

@@ -29,6 +29,8 @@ PUBLISHED:
   INLINE EggTriangleStrip &operator = (const EggTriangleStrip &copy);
   INLINE EggTriangleStrip &operator = (const EggTriangleStrip &copy);
   virtual ~EggTriangleStrip();
   virtual ~EggTriangleStrip();
 
 
+  virtual EggTriangleStrip *make_copy() const OVERRIDE;
+
   virtual void write(ostream &out, int indent_level) const;
   virtual void write(ostream &out, int indent_level) const;
 
 
 protected:
 protected:

+ 165 - 148
panda/src/egg2pg/eggSaver.cxx

@@ -23,8 +23,11 @@
 #include "colorAttrib.h"
 #include "colorAttrib.h"
 #include "materialAttrib.h"
 #include "materialAttrib.h"
 #include "textureAttrib.h"
 #include "textureAttrib.h"
+#include "cullBinAttrib.h"
 #include "cullFaceAttrib.h"
 #include "cullFaceAttrib.h"
 #include "transparencyAttrib.h"
 #include "transparencyAttrib.h"
+#include "depthTestAttrib.h"
+#include "depthOffsetAttrib.h"
 #include "depthWriteAttrib.h"
 #include "depthWriteAttrib.h"
 #include "lodNode.h"
 #include "lodNode.h"
 #include "switchNode.h"
 #include "switchNode.h"
@@ -101,6 +104,26 @@ add_node(PandaNode *node) {
   _vpool = NULL;
   _vpool = NULL;
 }
 }
 
 
+/**
+ * Adds the scene graph rooted at the indicated node (but without the node
+ * itself) to the accumulated egg data within this object.  Call
+ * get_egg_data() to retrieve the result.
+ */
+void EggSaver::
+add_subgraph(PandaNode *root) {
+  _vpool = new EggVertexPool(root->get_name());
+  _data->add_child(_vpool);
+
+  NodePath root_path(root);
+  recurse_nodes(root_path, _data, false, NULL);
+
+  // Remove the vertex pool if it has no vertices.
+  if (_vpool->empty()) {
+    _data->remove_child(_vpool);
+  }
+  _vpool = NULL;
+}
+
 /**
 /**
  * Converts the indicated node to the corresponding Egg constructs, by first
  * Converts the indicated node to the corresponding Egg constructs, by first
  * determining what kind of node it is.
  * determining what kind of node it is.
@@ -359,9 +382,12 @@ convert_character_node(Character *node, const WorkingNodePath &node_path,
                        EggGroupNode *egg_parent, bool has_decal) {
                        EggGroupNode *egg_parent, bool has_decal) {
 
 
   // A sequence node gets converted to an ordinary EggGroup, we only apply the
   // A sequence node gets converted to an ordinary EggGroup, we only apply the
-  // appropriate switch attributes to turn it into a sequence
+  // appropriate switch attributes to turn it into a sequence.
+  // We have to use DT_structured since it is the only mode that preserves the
+  // node hierarchy, including LODNodes and CollisionNodes that may be under
+  // this Character node.
   EggGroup *egg_group = new EggGroup(node->get_name());
   EggGroup *egg_group = new EggGroup(node->get_name());
-  egg_group->set_dart_type(EggGroup::DT_default);
+  egg_group->set_dart_type(EggGroup::DT_structured);
   egg_parent->add_child(egg_group);
   egg_parent->add_child(egg_group);
   apply_node_properties(egg_group, node);
   apply_node_properties(egg_group, node);
 
 
@@ -611,7 +637,8 @@ convert_geom_node(GeomNode *node, const WorkingNodePath &node_path,
   // Now get out all the various kinds of geometry.
   // Now get out all the various kinds of geometry.
   int num_geoms = node->get_num_geoms();
   int num_geoms = node->get_num_geoms();
   for (int i = 0; i < num_geoms; ++i) {
   for (int i = 0; i < num_geoms; ++i) {
-    CPT(RenderState) geom_state = net_state->compose(node->get_geom_state(i));
+    CPT(RenderState) geom_state = node->get_geom_state(i);
+    CPT(RenderState) geom_net_state = net_state->compose(geom_state);
 
 
     const Geom *geom = node->get_geom(i);
     const Geom *geom = node->get_geom(i);
     int num_primitives = geom->get_num_primitives();
     int num_primitives = geom->get_num_primitives();
@@ -620,7 +647,7 @@ convert_geom_node(GeomNode *node, const WorkingNodePath &node_path,
       CPT(GeomPrimitive) simple = primitive->decompose();
       CPT(GeomPrimitive) simple = primitive->decompose();
       CPT(GeomVertexData) vdata = geom->get_vertex_data();
       CPT(GeomVertexData) vdata = geom->get_vertex_data();
       // vdata = vdata->animate_vertices(true, Thread::get_current_thread());
       // vdata = vdata->animate_vertices(true, Thread::get_current_thread());
-      convert_primitive(vdata, simple, geom_state,
+      convert_primitive(vdata, simple, geom_state, geom_net_state,
                         net_mat, egg_parent, joint_map);
                         net_mat, egg_parent, joint_map);
     }
     }
   }
   }
@@ -634,11 +661,29 @@ convert_geom_node(GeomNode *node, const WorkingNodePath &node_path,
 void EggSaver::
 void EggSaver::
 convert_primitive(const GeomVertexData *vertex_data,
 convert_primitive(const GeomVertexData *vertex_data,
                   const GeomPrimitive *primitive,
                   const GeomPrimitive *primitive,
-                  const RenderState *net_state,
+                  const RenderState *geom_state, const RenderState *net_state,
                   const LMatrix4 &net_mat, EggGroupNode *egg_parent,
                   const LMatrix4 &net_mat, EggGroupNode *egg_parent,
                   CharacterJointMap *joint_map) {
                   CharacterJointMap *joint_map) {
   GeomVertexReader reader(vertex_data);
   GeomVertexReader reader(vertex_data);
 
 
+  // Make a zygote that will be duplicated for each primitive.
+  PT(EggPrimitive) egg_prim;
+  if (primitive->is_of_type(GeomTriangles::get_class_type())) {
+    egg_prim = new EggPolygon();
+  } else if (primitive->is_of_type(GeomPatches::get_class_type())) {
+    egg_prim = new EggPatch();
+  } else if (primitive->is_of_type(GeomPoints::get_class_type())) {
+    egg_prim = new EggPoint();
+  } else if (primitive->is_of_type(GeomLines::get_class_type())) {
+    egg_prim = new EggLine();
+  } else {
+    // Huh, an unknown geometry type.
+    return;
+  }
+
+  // Apply render attributes.
+  apply_state_properties(egg_prim, geom_state);
+
   // Check for a color scale.
   // Check for a color scale.
   LVecBase4 color_scale(1.0f, 1.0f, 1.0f, 1.0f);
   LVecBase4 color_scale(1.0f, 1.0f, 1.0f, 1.0f);
   const ColorScaleAttrib *csa;
   const ColorScaleAttrib *csa;
@@ -670,20 +715,20 @@ convert_primitive(const GeomVertexData *vertex_data,
   const MaterialAttrib *ma;
   const MaterialAttrib *ma;
   if (net_state->get_attrib(ma)) {
   if (net_state->get_attrib(ma)) {
     egg_mat = get_egg_material(ma->get_material());
     egg_mat = get_egg_material(ma->get_material());
+    if (egg_mat != (EggMaterial *)NULL) {
+      egg_prim->set_material(egg_mat);
+    }
   }
   }
 
 
   // Check for a texture.
   // Check for a texture.
-  EggTexture *egg_tex = (EggTexture *)NULL;
   const TextureAttrib *ta;
   const TextureAttrib *ta;
   if (net_state->get_attrib(ta)) {
   if (net_state->get_attrib(ta)) {
-    egg_tex = get_egg_texture(ta->get_texture());
-  }
+    EggTexture *egg_tex = get_egg_texture(ta->get_texture());
 
 
-  // Check the texture environment
-  if ((ta != (const TextureAttrib *)NULL) && (egg_tex != (const EggTexture *)NULL)) {
-    TextureStage* tex_stage = ta->get_on_stage(0);
-    if (tex_stage != (const TextureStage *)NULL) {
-      switch (tex_stage->get_mode()) {
+    if (egg_tex != (EggTexture *)NULL) {
+      TextureStage *tex_stage = ta->get_on_stage(0);
+      if (tex_stage != (TextureStage *)NULL) {
+        switch (tex_stage->get_mode()) {
         case TextureStage::M_modulate:
         case TextureStage::M_modulate:
           if (has_color_off == true) {
           if (has_color_off == true) {
             egg_tex->set_env_type(EggTexture::ET_replace);
             egg_tex->set_env_type(EggTexture::ET_replace);
@@ -708,7 +753,10 @@ convert_primitive(const GeomVertexData *vertex_data,
           break;
           break;
         default:
         default:
           break;
           break;
+        }
       }
       }
+
+      egg_prim->set_texture(egg_tex);
     }
     }
   }
   }
 
 
@@ -717,73 +765,22 @@ convert_primitive(const GeomVertexData *vertex_data,
   const CullFaceAttrib *cfa;
   const CullFaceAttrib *cfa;
   if (net_state->get_attrib(cfa)) {
   if (net_state->get_attrib(cfa)) {
     if (cfa->get_effective_mode() == CullFaceAttrib::M_cull_none) {
     if (cfa->get_effective_mode() == CullFaceAttrib::M_cull_none) {
-      bface = true;
-    }
-  }
-
-  // Check the depth write flag - only needed for AM_blend_no_occlude
-  bool has_depthwrite = false;
-  DepthWriteAttrib::Mode depthwrite = DepthWriteAttrib::M_on;
-  const DepthWriteAttrib *dwa;
-  if (net_state->get_attrib(dwa)) {
-    depthwrite = dwa->get_mode();
-    has_depthwrite = true;
-  }
-
-  // Check the transparency flag.
-  bool has_transparency = false;
-  TransparencyAttrib::Mode transparency = TransparencyAttrib::M_none;
-  const TransparencyAttrib *tra;
-  if (net_state->get_attrib(tra)) {
-    transparency = tra->get_mode();
-    has_transparency = true;
-  }
-  if (has_transparency && (egg_tex != (EggTexture *)NULL)) {
-    EggRenderMode::AlphaMode tex_trans = EggRenderMode::AM_unspecified;
-    switch (transparency) {
-      case TransparencyAttrib::M_none:
-        tex_trans = EggRenderMode::AM_off;
-        break;
-      case TransparencyAttrib::M_alpha:
-        if (has_depthwrite && (depthwrite == DepthWriteAttrib::M_off)) {
-          tex_trans = EggRenderMode::AM_blend_no_occlude;
-          has_depthwrite = false;
-        } else {
-          tex_trans = EggRenderMode::AM_blend;
-        }
-        break;
-      case TransparencyAttrib::M_premultiplied_alpha:
-        tex_trans = EggRenderMode::AM_premultiplied;
-        break;
-      case TransparencyAttrib::M_multisample:
-        tex_trans = EggRenderMode::AM_ms;
-        break;
-      case TransparencyAttrib::M_multisample_mask:
-        tex_trans = EggRenderMode::AM_ms_mask;
-        break;
-      case TransparencyAttrib::M_binary:
-        tex_trans = EggRenderMode::AM_binary;
-        break;
-      case TransparencyAttrib::M_dual:
-        tex_trans = EggRenderMode::AM_dual;
-        break;
-      default:  // intentional fall-through
-        break;
-    }
-    if (tex_trans != EggRenderMode::AM_unspecified) {
-      egg_tex->set_alpha_mode(tex_trans);
+      egg_prim->set_bface_flag(true);
     }
     }
   }
   }
 
 
   // Check for line thickness and such.
   // Check for line thickness and such.
-  bool has_render_mode = false;
-  bool perspective = false;
-  PN_stdfloat thickness = 1;
   const RenderModeAttrib *rma;
   const RenderModeAttrib *rma;
   if (net_state->get_attrib(rma)) {
   if (net_state->get_attrib(rma)) {
-    has_render_mode = true;
-    thickness = rma->get_thickness();
-    perspective = rma->get_perspective();
+    if (egg_prim->is_of_type(EggPoint::get_class_type())) {
+      EggPoint *egg_point = (EggPoint *)egg_prim.p();
+      egg_point->set_thick(rma->get_thickness());
+      egg_point->set_perspective(rma->get_perspective());
+
+    } else if (egg_prim->is_of_type(EggLine::get_class_type())) {
+      EggLine *egg_line = (EggLine *)egg_prim.p();
+      egg_line->set_thick(rma->get_thickness());
+    }
   }
   }
 
 
   LNormal normal;
   LNormal normal;
@@ -793,48 +790,9 @@ convert_primitive(const GeomVertexData *vertex_data,
   int num_primitives = primitive->get_num_primitives();
   int num_primitives = primitive->get_num_primitives();
   int num_vertices = primitive->get_num_vertices_per_primitive();
   int num_vertices = primitive->get_num_vertices_per_primitive();
 
 
-  EggPrimitive *(*make_func)(void);
-
-  if (primitive->is_of_type(GeomTriangles::get_class_type())) {
-    make_func = make_egg_polygon;
-  } else if (primitive->is_of_type(GeomPatches::get_class_type())) {
-    make_func = make_egg_patch;
-  } else if (primitive->is_of_type(GeomPoints::get_class_type())) {
-    make_func = make_egg_point;
-  } else if (primitive->is_of_type(GeomLines::get_class_type())) {
-    make_func = make_egg_line;
-  } else {
-    // Huh, an unknown geometry type.
-    return;
-  }
-
   for (int i = 0; i < num_primitives; ++i) {
   for (int i = 0; i < num_primitives; ++i) {
-    PT(EggPrimitive) egg_prim = (*make_func)();
-
-    egg_parent->add_child(egg_prim);
-
-    if (egg_mat != (EggMaterial *)NULL) {
-      egg_prim->set_material(egg_mat);
-    }
-    if (egg_tex != (EggTexture *)NULL) {
-      egg_prim->set_texture(egg_tex);
-    }
-
-    if (bface) {
-      egg_prim->set_bface_flag(true);
-    }
-
-    if (has_render_mode) {
-      if (egg_prim->is_of_type(EggPoint::get_class_type())) {
-        EggPoint *egg_point = (EggPoint *)egg_prim.p();
-        egg_point->set_thick(thickness);
-        egg_point->set_perspective(perspective);
-
-      } else if (egg_prim->is_of_type(EggLine::get_class_type())) {
-        EggLine *egg_line = (EggLine *)egg_prim.p();
-        egg_line->set_thick(thickness);
-      }
-    }
+    PT(EggPrimitive) egg_child = egg_prim->make_copy();
+    egg_parent->add_child(egg_child);
 
 
     for (int j = 0; j < num_vertices; j++) {
     for (int j = 0; j < num_vertices; j++) {
       EggVertex egg_vert;
       EggVertex egg_vert;
@@ -898,7 +856,7 @@ convert_primitive(const GeomVertexData *vertex_data,
         }
         }
       }
       }
 
 
-      egg_prim->add_vertex(new_egg_vert);
+      egg_child->add_vertex(new_egg_vert);
     }
     }
   }
   }
 }
 }
@@ -1004,6 +962,97 @@ apply_node_properties(EggGroup *egg_group, PandaNode *node, bool allow_backstage
     any_applied = true;
     any_applied = true;
   }
   }
 
 
+  const RenderState *state = node->get_state();
+  if (apply_state_properties(egg_group, state)) {
+    return true;
+  }
+
+  return any_applied;
+}
+
+/**
+ * Applies any special render state settings on the primitive or group.
+ * Returns true if any were applied, false otherwise.
+ */
+bool EggSaver::
+apply_state_properties(EggRenderMode *egg_render_mode, const RenderState *state) {
+  if (state->is_empty()) {
+    return false;
+  }
+
+  bool any_applied = false;
+
+  // Check the transparency mode.
+  const TransparencyAttrib *tra;
+  if (state->get_attrib(tra)) {
+    EggRenderMode::AlphaMode tex_trans = EggRenderMode::AM_unspecified;
+    switch (tra->get_mode()) {
+    case TransparencyAttrib::M_none:
+      tex_trans = EggRenderMode::AM_off;
+      break;
+    case TransparencyAttrib::M_alpha:
+      tex_trans = EggRenderMode::AM_blend;
+      break;
+    case TransparencyAttrib::M_premultiplied_alpha:
+      tex_trans = EggRenderMode::AM_premultiplied;
+      break;
+    case TransparencyAttrib::M_multisample:
+      tex_trans = EggRenderMode::AM_ms;
+      break;
+    case TransparencyAttrib::M_multisample_mask:
+      tex_trans = EggRenderMode::AM_ms_mask;
+      break;
+    case TransparencyAttrib::M_binary:
+      tex_trans = EggRenderMode::AM_binary;
+      break;
+    case TransparencyAttrib::M_dual:
+      tex_trans = EggRenderMode::AM_dual;
+      break;
+    default:  // intentional fall-through
+      break;
+    }
+    egg_render_mode->set_alpha_mode(tex_trans);
+  }
+
+  const DepthWriteAttrib *dwa;
+  if (state->get_attrib(dwa)) {
+    if (dwa->get_mode() != DepthWriteAttrib::M_off) {
+      egg_render_mode->set_depth_write_mode(EggRenderMode::DWM_on);
+
+    } else if (egg_render_mode->get_alpha_mode() == EggRenderMode::AM_blend) {
+      // AM_blend_no_occlude is like AM_blend but also implies DWM_off.
+      egg_render_mode->set_alpha_mode(EggRenderMode::AM_blend_no_occlude);
+
+    } else {
+      egg_render_mode->set_depth_write_mode(EggRenderMode::DWM_off);
+    }
+    any_applied = true;
+  }
+
+  const DepthTestAttrib *dta;
+  if (state->get_attrib(dta)) {
+    RenderAttrib::PandaCompareFunc mode = dta->get_mode();
+    if (mode == DepthTestAttrib::M_none || mode == DepthTestAttrib::M_always) {
+      egg_render_mode->set_depth_test_mode(EggRenderMode::DTM_off);
+    } else {
+      egg_render_mode->set_depth_test_mode(EggRenderMode::DTM_on);
+    }
+    any_applied = true;
+  }
+
+  const DepthOffsetAttrib *doa;
+  if (state->get_attrib(doa)) {
+    egg_render_mode->set_depth_offset(doa->get_offset());
+    any_applied = true;
+  }
+
+  const CullBinAttrib *cba;
+  if (state->get_attrib(cba)) {
+    egg_render_mode->set_bin(cba->get_bin_name());
+    egg_render_mode->set_draw_order(cba->get_draw_order());
+    any_applied = true;
+  }
+
   return any_applied;
   return any_applied;
 }
 }
 
 
@@ -1250,35 +1299,3 @@ get_egg_texture(Texture *tex) {
 
 
   return NULL;
   return NULL;
 }
 }
-
-/**
- * A factory function to make a new EggPolygon instance.
- */
-EggPrimitive *EggSaver::
-make_egg_polygon() {
-  return new EggPolygon;
-}
-
-/**
- * A factory function to make a new EggPatch instance.
- */
-EggPrimitive *EggSaver::
-make_egg_patch() {
-  return new EggPatch;
-}
-
-/**
- * A factory function to make a new EggPoint instance.
- */
-EggPrimitive *EggSaver::
-make_egg_point() {
-  return new EggPoint;
-}
-
-/**
- * A factory function to make a new EggLine instance.
- */
-EggPrimitive *EggSaver::
-make_egg_line() {
-  return new EggLine;
-}

+ 3 - 5
panda/src/egg2pg/eggSaver.h

@@ -55,6 +55,7 @@ PUBLISHED:
   EggSaver(EggData *data = NULL);
   EggSaver(EggData *data = NULL);
 
 
   void add_node(PandaNode *node);
   void add_node(PandaNode *node);
+  void add_subgraph(PandaNode *root);
   INLINE EggData *get_egg_data() const;
   INLINE EggData *get_egg_data() const;
 
 
 private:
 private:
@@ -84,6 +85,7 @@ private:
                          EggGroupNode *egg_parent, bool has_decal, CharacterJointMap *jointMap=NULL);
                          EggGroupNode *egg_parent, bool has_decal, CharacterJointMap *jointMap=NULL);
   void convert_primitive(const GeomVertexData *vertex_data,
   void convert_primitive(const GeomVertexData *vertex_data,
                          const GeomPrimitive *primitive,
                          const GeomPrimitive *primitive,
+                         const RenderState *geom_state,
                          const RenderState *net_state,
                          const RenderState *net_state,
                          const LMatrix4 &net_mat, EggGroupNode *egg_parent,
                          const LMatrix4 &net_mat, EggGroupNode *egg_parent,
                          CharacterJointMap *jointMap);
                          CharacterJointMap *jointMap);
@@ -91,17 +93,13 @@ private:
   void recurse_nodes(const WorkingNodePath &node_path, EggGroupNode *egg_parent,
   void recurse_nodes(const WorkingNodePath &node_path, EggGroupNode *egg_parent,
                      bool has_decal, CharacterJointMap *joint_map);
                      bool has_decal, CharacterJointMap *joint_map);
   bool apply_node_properties(EggGroup *egg_group, PandaNode *node, bool allow_backstage = true);
   bool apply_node_properties(EggGroup *egg_group, PandaNode *node, bool allow_backstage = true);
+  bool apply_state_properties(EggRenderMode *egg_render_mode, const RenderState *state);
   bool apply_tags(EggGroup *egg_group, PandaNode *node);
   bool apply_tags(EggGroup *egg_group, PandaNode *node);
   bool apply_tag(EggGroup *egg_group, PandaNode *node, const string &tag);
   bool apply_tag(EggGroup *egg_group, PandaNode *node, const string &tag);
 
 
   EggMaterial *get_egg_material(Material *tex);
   EggMaterial *get_egg_material(Material *tex);
   EggTexture *get_egg_texture(Texture *tex);
   EggTexture *get_egg_texture(Texture *tex);
 
 
-  static EggPrimitive *make_egg_polygon();
-  static EggPrimitive *make_egg_patch();
-  static EggPrimitive *make_egg_point();
-  static EggPrimitive *make_egg_line();
-
   PT(EggData) _data;
   PT(EggData) _data;
 
 
   PT(EggVertexPool) _vpool;
   PT(EggVertexPool) _vpool;

+ 14 - 2
panda/src/egg2pg/save_egg_file.cxx

@@ -31,7 +31,13 @@ save_egg_file(const Filename &filename, PandaNode *node, CoordinateSystem cs) {
   data->set_coordinate_system(cs);
   data->set_coordinate_system(cs);
 
 
   EggSaver saver(data);
   EggSaver saver(data);
-  saver.add_node(node);
+  if (node->is_of_type(ModelRoot::get_class_type())) {
+    // If this is a ModelRoot, only write the nodes below it.  Otherwise we
+    // end up inserting a node when we do a bam2egg.
+    saver.add_subgraph(node);
+  } else {
+    saver.add_node(node);
+  }
 
 
   return data->write_egg(filename);
   return data->write_egg(filename);
 }
 }
@@ -43,6 +49,12 @@ save_egg_file(const Filename &filename, PandaNode *node, CoordinateSystem cs) {
 bool
 bool
 save_egg_data(EggData *data, PandaNode *node) {
 save_egg_data(EggData *data, PandaNode *node) {
   EggSaver saver(data);
   EggSaver saver(data);
-  saver.add_node(node);
+  if (node->is_of_type(ModelRoot::get_class_type())) {
+    // If this is a ModelRoot, only write the nodes below it.  Otherwise we
+    // end up inserting a node when we do a bam2egg.
+    saver.add_subgraph(node);
+  } else {
+    saver.add_node(node);
+  }
   return true;
   return true;
 }
 }