Browse Source

bring bam2egg to new scene graph

David Rose 23 years ago
parent
commit
e44199d552
3 changed files with 399 additions and 304 deletions
  1. 1 3
      pandatool/src/bam/Sources.pp
  2. 371 294
      pandatool/src/bam/bamToEgg.cxx
  3. 27 7
      pandatool/src/bam/bamToEgg.h

+ 1 - 3
pandatool/src/bam/Sources.pp

@@ -36,14 +36,13 @@
 #end bin_target
 
 
-#if // Temporarily broken until we can bring it into the new scene graph.
 #begin bin_target
   #define TARGET bam2egg
   #define LOCAL_LIBS \
     converter eggbase progbase
   #define OTHER_LIBS \
     egg:c pandaegg:m \
-    pgraph:cparametrics:c collide:c chan:c char:c \
+    pgraph:c parametrics:c collide:c chan:c char:c \
     gobj:c pnmimagetypes:c pstatclient:c \
     putil:c linmath:c event:c express:c panda:m pandaexpress:m \
     interrogatedb:c dtoolutil:c dtoolbase:c dconfig:c dtoolconfig:m dtool:m pystub
@@ -55,4 +54,3 @@
     bamToEgg.cxx bamToEgg.h
 
 #end bin_target
-#endif // Temporarily broken until we can bring it into the new scene graph.

+ 371 - 294
pandatool/src/bam/bamToEgg.cxx

@@ -18,8 +18,17 @@
 
 #include "bamToEgg.h"
 
-#include "node.h"
-#include "LODNode.h"
+#include "pandaNode.h"
+#include "workingNodePath.h"
+#include "nodePath.h"
+#include "billboardEffect.h"
+#include "renderEffects.h"
+#include "transformState.h"
+#include "colorScaleAttrib.h"
+#include "colorAttrib.h"
+#include "textureAttrib.h"
+#include "cullFaceAttrib.h"
+#include "lodNode.h"
 #include "geomNode.h"
 #include "geom.h"
 #include "geomTri.h"
@@ -33,153 +42,9 @@
 #include "eggTexture.h"
 #include "eggMaterial.h"
 #include "somethingToEggConverter.h"
+#include "dcast.h"
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: BamToEgg::GeomState::Constructor
-//       Access: Public
-//  Description: 
-////////////////////////////////////////////////////////////////////
-BamToEgg::GeomState::
-GeomState() {
-  _mat = LMatrix4f::ident_mat();
-  _tex_mat = LMatrix4f::ident_mat();
-  _color_mat = LMatrix4f::ident_mat();
-  _alpha_scale = 1.0;
-  _alpha_offset = 0.0;
-  _tex = (Texture *)NULL;
-  _bface = false;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: BamToEgg::GeomState::get_net_state
-//       Access: Public
-//  Description: Gets the accumulated state of the indicated node (and
-//               its corresponding ArcChain) into the GeomState.
-////////////////////////////////////////////////////////////////////
-void BamToEgg::GeomState::
-get_net_state(Node *node, ArcChain &chain, EggGroupNode *egg_parent) {
-  AllTransitionsWrapper atw;
-
-  wrt(node, chain.begin(), chain.end(),
-      (Node *)NULL,
-      atw, RenderRelation::get_class_type());
-
-  // Check for transform space.
-  const TransformTransition *tt;
-  if (get_transition_into(tt, atw)) {
-    _mat = tt->get_matrix();
-    LMatrix4f inv = LCAST(float, egg_parent->get_vertex_frame_inv());
-    _mat = _mat * inv;
-  }
-
-  // Check for texture matrix.
-  const TexMatrixTransition *tmt;
-  if (get_transition_into(tmt, atw)) {
-    _tex_mat = tmt->get_matrix();
-  }
-
-  // Check for color matrix.
-  const ColorMatrixTransition *cmt;
-  if (get_transition_into(cmt, atw)) {
-    _color_mat = cmt->get_matrix();
-  }
-
-  // Check for alpha scale/offset.
-  const AlphaTransformTransition *att;
-  if (get_transition_into(att, atw)) {
-    _alpha_scale = att->get_scale();
-    _alpha_offset = att->get_offset();
-  }
-
-  // Check for texture.
-  const TextureTransition *txt;
-  if (get_transition_into(txt, atw)) {
-    if (txt->is_on()) {
-      _tex = txt->get_texture();
-    }
-  }
-
-  // Check for bface.
-  const CullFaceTransition *cft;
-  if (get_transition_into(cft, atw)) {
-    if (cft->get_mode() == CullFaceProperty::M_cull_none) {
-      _bface = true;
-    }
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: BamToEgg::GeomState::apply_vertex
-//       Access: Public
-//  Description: Applies the indicated vertex coordinate to the given
-//               EggVertex, after modifying it according to the
-//               current state.
-////////////////////////////////////////////////////////////////////
-void BamToEgg::GeomState::
-apply_vertex(EggVertex &egg_vert, const Vertexf &vertex) {
-  LPoint3f transformed = vertex * _mat;
-  egg_vert.set_pos(LCAST(double, transformed));
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: BamToEgg::GeomState::apply_normal
-//       Access: Public
-//  Description: Applies the indicated vertex normal to the given
-//               EggVertex, after modifying it according to the
-//               current state.
-////////////////////////////////////////////////////////////////////
-void BamToEgg::GeomState::
-apply_normal(EggVertex &egg_vert, const Normalf &normal) {
-  LPoint3f transformed = normal * _mat;
-  egg_vert.set_normal(LCAST(double, transformed));
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: BamToEgg::GeomState::apply_uv
-//       Access: Public
-//  Description: Applies the indicated vertex UV to the given
-//               EggVertex, after modifying it according to the
-//               current state.
-////////////////////////////////////////////////////////////////////
-void BamToEgg::GeomState::
-apply_uv(EggVertex &egg_vert, const TexCoordf &uv) {
-  LVecBase4f v4(uv[0], uv[1], 0.0, 1.0);
-  v4 = v4 * _tex_mat;
-  egg_vert.set_uv(LCAST(double, uv));
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: BamToEgg::GeomState::apply_color
-//       Access: Public
-//  Description: Applies the indicated vertex color to the given
-//               EggVertex, after modifying it according to the
-//               current state.
-////////////////////////////////////////////////////////////////////
-void BamToEgg::GeomState::
-apply_color(EggVertex &egg_vert, const Colorf &color) {
-  LPoint3f temp(color[0], color[1], color[2]);
-  temp = temp * _color_mat;
-  float alpha = (color[3] * _alpha_scale) +
-    _alpha_offset;
-  
-  Colorf transformed(temp[0], temp[1], temp[2], alpha);
-  egg_vert.set_color(transformed);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: BamToEgg::GeomState::apply_prim
-//       Access: Public
-//  Description: Applies generic, non-vertex-specific properties to
-//               the primitive.
-////////////////////////////////////////////////////////////////////
-void BamToEgg::GeomState::
-apply_prim(EggPrimitive *egg_prim) {
-  if (_bface) {
-    egg_prim->set_bface_flag(true);
-  }
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: BamToEgg::Constructor
 //       Access: Public
@@ -189,9 +54,8 @@ BamToEgg::
 BamToEgg() :
   SomethingToEgg("Bam", ".bam")
 {
-  add_texture_path_options();
-  add_rel_dir_options();
-  add_search_path_options(true);
+  add_path_replace_options();
+  add_path_store_options();
 
   set_program_description
     ("This program converts native Panda Bam files to egg.  The conversion "
@@ -241,10 +105,11 @@ run() {
   _vpool = new EggVertexPool("vpool");
   _data.add_child(_vpool);
 
-  if (objects.size() == 1 && objects[0]->is_of_type(Node::get_class_type())) {
-    Node *node = DCAST(Node, objects[0]);
-    ArcChain chain(node);
-    convert_node(node, chain, &_data);
+  if (objects.size() == 1 && 
+      objects[0]->is_of_type(PandaNode::get_class_type())) {
+    PandaNode *node = DCAST(PandaNode, objects[0]);
+    NodePath root(node);
+    convert_node(WorkingNodePath(root), &_data, false);
 
   } else {
     nout << "File does not contain a scene graph.\n";
@@ -267,25 +132,22 @@ run() {
 //               is.
 ////////////////////////////////////////////////////////////////////
 void BamToEgg::
-convert_node(Node *node, ArcChain &chain, EggGroupNode *egg_parent) {
-  if (node->is_of_type(LODNode::get_class_type())) {
-    convert_lod_node(DCAST(LODNode, node), chain, egg_parent);
+convert_node(const WorkingNodePath &node_path, EggGroupNode *egg_parent,
+             bool has_decal) {
+  PandaNode *node = node_path.node();
+  if (node->is_geom_node()) {
+    convert_geom_node(DCAST(GeomNode, node), node_path, egg_parent, has_decal);
 
-  } else if (node->is_of_type(GeomNode::get_class_type())) {
-    convert_geom_node(DCAST(GeomNode, node), chain, egg_parent);
+  } else if (node->is_of_type(LODNode::get_class_type())) {
+    convert_lod_node(DCAST(LODNode, node), node_path, egg_parent, has_decal);
 
   } else {
-    // Just a generic node.  See if it has a name, at least.
-    string name;
-    if (node->is_of_type(NamedNode::get_class_type())) {
-      name = DCAST(NamedNode, node)->get_name();
-    }
-    
-    EggGroup *egg_group = new EggGroup(name);
+    // Just a generic node.
+    EggGroup *egg_group = new EggGroup(node->get_name());
     egg_parent->add_child(egg_group);
-    apply_arc_properties(egg_group, chain);
+    apply_node_properties(egg_group, node);
     
-    recurse_nodes(node, chain, egg_group);
+    recurse_nodes(node_path, egg_group, has_decal);
   }
 }
 
@@ -296,29 +158,25 @@ convert_node(Node *node, ArcChain &chain, EggGroupNode *egg_parent) {
 //               Egg constructs.
 ////////////////////////////////////////////////////////////////////
 void BamToEgg::
-convert_lod_node(LODNode *node, ArcChain &chain, EggGroupNode *egg_parent) {
+convert_lod_node(LODNode *node, const WorkingNodePath &node_path,
+                 EggGroupNode *egg_parent, bool has_decal) {
   // An LOD node gets converted to an ordinary EggGroup, but we apply
   // the appropriate switch conditions to each of our children.
-  string name = node->get_name();
-
-  EggGroup *egg_group = new EggGroup(name);
+  EggGroup *egg_group = new EggGroup(node->get_name());
   egg_parent->add_child(egg_group);
-  apply_arc_properties(egg_group, chain);
+  apply_node_properties(egg_group, node);
 
-  int num_children = node->get_num_children(RenderRelation::get_class_type());
+  int num_children = node->get_num_children();
   int num_switches = node->get_num_switches();
 
   num_children = min(num_children, num_switches);
 
   for (int i = 0; i < num_children; i++) {
-    NodeRelation *arc = 
-      node->get_child(RenderRelation::get_class_type(), i);
-    ArcChain next_chain(chain);
-    next_chain.push_back(arc);
+    PandaNode *child = node->get_child(i);
 
     // Convert just this one node to an EggGroup.
     PT(EggGroup) next_group = new EggGroup;
-    convert_node(arc->get_child(), next_chain, next_group);
+    convert_node(WorkingNodePath(node_path, child), next_group, has_decal);
 
     if (next_group->size() == 1) {
       // If we have exactly one child, and that child is an EggGroup,
@@ -334,7 +192,7 @@ convert_lod_node(LODNode *node, ArcChain &chain, EggGroupNode *egg_parent) {
     // Now set up the switching properties appropriately.
     float in = node->get_in(i);
     float out = node->get_out(i);
-    LPoint3f center = node->_lod._center;
+    LPoint3f center = node->get_center();
     EggSwitchConditionDistance dist(in, out, LCAST(double, center));
     next_group->set_lod(dist);
     egg_group->add_child(next_group.p());
@@ -344,50 +202,57 @@ convert_lod_node(LODNode *node, ArcChain &chain, EggGroupNode *egg_parent) {
 ////////////////////////////////////////////////////////////////////
 //     Function: BamToEgg::convert_geom_node
 //       Access: Private
-//  Description: 
+//  Description: Converts a GeomNode to the corresponding egg
+//               structures.
 ////////////////////////////////////////////////////////////////////
 void BamToEgg::
-convert_geom_node(GeomNode *node, ArcChain &chain, EggGroupNode *egg_parent) {
-  bool parent_has_decal = false;
-  if (egg_parent->is_of_type(EggGroup::get_class_type())) {
-    EggGroup *pg = DCAST(EggGroup, egg_parent);
-    parent_has_decal = pg->get_decal_flag();
+convert_geom_node(GeomNode *node, const WorkingNodePath &node_path, 
+                  EggGroupNode *egg_parent, bool has_decal) {
+  PT(EggGroup) egg_group = new EggGroup(node->get_name());
+  bool fancy_attributes = apply_node_properties(egg_group, node);
+
+  if (node->get_effects()->has_decal()) {
+    has_decal = true;
   }
 
-  PT(EggGroup) egg_group = new EggGroup(node->get_name());
-  bool fancy_transitions = apply_arc_properties(egg_group, chain);
-  if (fancy_transitions || parent_has_decal) {
-    // If we have any fancy transitions on the arc, or if we're making
+  if (has_decal) {
+    egg_group->set_decal_flag(true);
+  }
+
+  if (fancy_attributes || has_decal) {
+    // If we have any fancy attributes on the node, or if we're making
     // decal geometry, we have to make a special node to hold the
     // geometry (normally it would just appear within its parent).
     egg_parent->add_child(egg_group.p());
     egg_parent = egg_group;
   }
-    
 
-  // Get the state associated with this GeomNode.
-  GeomState state;
-  state.get_net_state(node, chain, egg_parent);
+  NodePath np = node_path.get_node_path();
+  CPT(RenderState) net_state = np.get_net_state();
+  CPT(TransformState) net_transform = np.get_net_transform();
+  LMatrix4f net_mat = net_transform->get_mat();
+  LMatrix4f inv = LCAST(float, egg_parent->get_vertex_frame_inv());
+  net_mat = net_mat * inv;
 
   // Now get out all the various kinds of geometry.
   int num_geoms = node->get_num_geoms();
   for (int i = 0; i < num_geoms; i++) {
-    dDrawable *drawable = node->get_geom(i);
-    if (drawable->is_of_type(Geom::get_class_type())) {
-      // Explode the Geom before we try to deal with it.  That way, we
-      // don't have to know about tristrips or whatnot.
-      Geom *geom = DCAST(Geom, drawable);
-      PT(Geom) exploded = geom->explode();
-
-      // Now determine what kind of Geom we've got.  Chances are good
-      // it's triangles.
-      if (exploded->is_of_type(GeomTri::get_class_type())) {
-        convert_geom_tri(DCAST(GeomTri, exploded), state, egg_parent);
-      }
+    CPT(RenderState) geom_state = net_state->compose(node->get_geom_state(i));
+
+    Geom *geom = node->get_geom(i);
+    // Explode the Geom before we try to deal with it.  That way, we
+    // don't have to know about tristrips or whatnot.
+    PT(Geom) exploded = geom->explode();
+
+    // Now determine what kind of Geom we've got.  Chances are good
+    // it's triangles.
+    if (exploded->is_of_type(GeomTri::get_class_type())) {
+      convert_geom_tri(DCAST(GeomTri, exploded), geom_state, net_mat,
+                       egg_parent);
     }
   }
   
-  recurse_nodes(node, chain, egg_parent);
+  recurse_nodes(node_path, egg_parent, has_decal);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -396,7 +261,8 @@ convert_geom_node(GeomNode *node, ArcChain &chain, EggGroupNode *egg_parent) {
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 void BamToEgg::
-convert_geom_tri(GeomTri *geom, BamToEgg::GeomState &state, EggGroupNode *egg_parent) {
+convert_geom_tri(GeomTri *geom, const RenderState *net_state, 
+                 const LMatrix4f &net_mat, EggGroupNode *egg_parent) {
   int nprims = geom->get_num_prims();
   Geom::VertexIterator vi = geom->make_vertex_iterator();
   Geom::NormalIterator ni = geom->make_normal_iterator();
@@ -408,70 +274,113 @@ convert_geom_tri(GeomTri *geom, BamToEgg::GeomState &state, EggGroupNode *egg_pa
   GeomBindType tb = geom->get_binding(G_TEXCOORD);
   GeomBindType cb = geom->get_binding(G_COLOR);
 
-  Vertexf vertex;
+  // Check for a color scale.
+  LVecBase4f color_scale(1.0f, 1.0f, 1.0f, 1.0f);
+  const RenderAttrib *color_scale_attrib = net_state->get_attrib(ColorScaleAttrib::get_class_type());
+  if (color_scale_attrib != (const RenderAttrib *)NULL) {
+    const ColorScaleAttrib *csa = DCAST(ColorScaleAttrib, color_scale_attrib);
+    color_scale = csa->get_scale();
+  }
+
+  // Check for a color override.
+  bool has_color_override = false;
+  bool has_color_off = false;
+  Colorf color_override;
+  const RenderAttrib *color_attrib = net_state->get_attrib(ColorAttrib::get_class_type());
+  if (color_attrib != (const RenderAttrib *)NULL) {
+    const ColorAttrib *ca = DCAST(ColorAttrib, color_attrib);
+    if (ca->get_color_type() == ColorAttrib::T_flat) {
+      has_color_override = true;
+      color_override = ca->get_color();
+      color_override.set(color_override[0] * color_scale[0],
+                         color_override[1] * color_scale[1],
+                         color_override[2] * color_scale[2],
+                         color_override[3] * color_scale[3]);
+
+    } else if (ca->get_color_type() == ColorAttrib::T_off) {
+      has_color_off = true;
+    }
+  }
+
+  // Check for a texture.
+  EggTexture *egg_tex = (EggTexture *)NULL;
+  const RenderAttrib *tex_attrib = net_state->get_attrib(TextureAttrib::get_class_type());
+  if (tex_attrib != (const RenderAttrib *)NULL) {
+    const TextureAttrib *ta = DCAST(TextureAttrib, tex_attrib);
+    egg_tex = get_egg_texture(ta->get_texture());
+  }
+
+  // Check the backface flag.
+  bool bface = false;
+  const RenderAttrib *cf_attrib = net_state->get_attrib(CullFaceAttrib::get_class_type());
+  if (cf_attrib != (const RenderAttrib *)NULL) {
+    const CullFaceAttrib *cfa = DCAST(CullFaceAttrib, cf_attrib);
+    if (cfa->get_mode() == CullFaceAttrib::M_cull_none) {
+      bface = true;
+    }
+  }
+
   Normalf normal;
-  TexCoordf uv;
   Colorf color;
 
   // Get overall properties.
-  if (vb == G_OVERALL) {
-    vertex = geom->get_next_vertex(vi);
-  }
   if (nb == G_OVERALL) {
     normal = geom->get_next_normal(ni);
   }
-  if (tb == G_OVERALL) {
-    uv = geom->get_next_texcoord(ti);
-  }
   if (cb == G_OVERALL) {
     color = geom->get_next_color(ci);
   }
 
   for (int i = 0; i < nprims; i++) {
     // Get per-prim properties.
-    if (vb == G_PER_PRIM) {
-      vertex = geom->get_next_vertex(vi);
-    }
     if (nb == G_PER_PRIM) {
       normal = geom->get_next_normal(ni);
     }
-    if (tb == G_PER_PRIM) {
-      uv = geom->get_next_texcoord(ti);
-    }
     if (cb == G_PER_PRIM) {
       color = geom->get_next_color(ci);
     }
 
     EggPolygon *egg_poly = new EggPolygon;
     egg_parent->add_child(egg_poly);
-    apply_texture(egg_poly, state._tex);
-    state.apply_prim(egg_poly);
+    if (egg_tex != (EggTexture *)NULL) {
+      egg_poly->set_texture(egg_tex);
+    }
+
+    if (bface) {
+      egg_poly->set_bface_flag(true);
+    }
 
     for (int j = 0; j < 3; j++) {
+      EggVertex egg_vert;
+
       // Get per-vertex properties.
       if (vb == G_PER_VERTEX) {
-        vertex = geom->get_next_vertex(vi);
+        Vertexf vertex = geom->get_next_vertex(vi);
+        egg_vert.set_pos(LCAST(double, vertex * net_mat));
       }
       if (nb == G_PER_VERTEX) {
-        normal = geom->get_next_normal(ni);
+        normal = geom->get_next_normal(ni) * net_mat;
       }
       if (tb == G_PER_VERTEX) {
-        uv = geom->get_next_texcoord(ti);
+        TexCoordf uv = geom->get_next_texcoord(ti);
+        egg_vert.set_uv(LCAST(double, uv));
       }
       if (cb == G_PER_VERTEX) {
         color = geom->get_next_color(ci);
       }
 
-      EggVertex egg_vert;
-      state.apply_vertex(egg_vert, vertex);
       if (nb != G_OFF) {
-        state.apply_normal(egg_vert, normal);
-      }
-      if (tb != G_OFF) {
-        state.apply_uv(egg_vert, uv);
+        egg_vert.set_normal(LCAST(double, normal * net_mat));
       }
-      if (cb != G_OFF) {
-        state.apply_color(egg_vert, color);
+
+      if (has_color_override) {
+        egg_vert.set_color(color_override);
+
+      } else if (!has_color_off && cb != G_OFF) {
+        egg_vert.set_color(Colorf(color[0] * color_scale[0],
+                                  color[1] * color_scale[1],
+                                  color[2] * color_scale[2],
+                                  color[3] * color_scale[3]));
       }
 
       EggVertex *new_egg_vert = _vpool->create_unique_vertex(egg_vert);
@@ -480,48 +389,106 @@ convert_geom_tri(GeomTri *geom, BamToEgg::GeomState &state, EggGroupNode *egg_pa
   }
 }
 
-
 ////////////////////////////////////////////////////////////////////
 //     Function: BamToEgg::recurse_nodes
 //       Access: Private
 //  Description: Converts all the children of the indicated node.
 ////////////////////////////////////////////////////////////////////
 void BamToEgg::
-recurse_nodes(Node *node, ArcChain &chain, EggGroupNode *egg_parent) {
-  int num_children = node->get_num_children(RenderRelation::get_class_type());
-
+recurse_nodes(const WorkingNodePath &node_path, EggGroupNode *egg_parent,
+              bool has_decal) {
+  PandaNode *node = node_path.node();
+  int num_children = node->get_num_children();
+  
   for (int i = 0; i < num_children; i++) {
-    NodeRelation *arc = 
-      node->get_child(RenderRelation::get_class_type(), i);
-    ArcChain next_chain(chain);
-    next_chain.push_back(arc);
-    convert_node(arc->get_child(), next_chain, egg_parent);
+    PandaNode *child = node->get_child(i);
+    convert_node(WorkingNodePath(node_path, child), egg_parent, has_decal);
   }
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: BamToEgg::apply_texture
+//     Function: BamToEgg::apply_node_properties
 //       Access: Public
-//  Description: Applies the texture, if any, to the indicated
-//               EggPrimitive.
+//  Description: Applies any special properties that might be stored
+//               on the node, like billboarding.  Returns true if any
+//               were applied, false otherwise.
 ////////////////////////////////////////////////////////////////////
-void BamToEgg::
-apply_texture(EggPrimitive *egg_prim, Texture *tex) {
+bool BamToEgg::
+apply_node_properties(EggGroup *egg_group, PandaNode *node) {
+  bool any_applied = false;
+
+  if (node->get_draw_mask().is_zero()) {
+    // This node is hidden.  We'll go ahead and convert it, but we'll
+    // put in the "backstage" flag to mean it's not real geometry.
+    egg_group->add_object_type("backstage");
+  }
+
+  const RenderEffects *effects = node->get_effects();
+  const BillboardEffect *bbe = effects->get_billboard();
+  if (bbe != (const BillboardEffect *)NULL) {
+    if (bbe->get_axial_rotate()) {
+      egg_group->set_billboard_type(EggGroup::BT_axis);
+      any_applied = true;
+
+    } else if (bbe->get_eye_relative()) {
+      egg_group->set_billboard_type(EggGroup::BT_point_camera_relative);
+      any_applied = true;
+
+    } else {
+      egg_group->set_billboard_type(EggGroup::BT_point_world_relative);
+      any_applied = true;
+    }
+  }
+
+  const TransformState *transform = node->get_transform();
+  if (!transform->is_identity()) {
+    if (transform->has_components()) {
+      // If the transform can be represented componentwise, we prefer
+      // storing it that way in the egg file.
+      const LVecBase3f &scale = transform->get_scale();
+      const LQuaternionf &quat = transform->get_quat();
+      const LVecBase3f &pos = transform->get_pos();
+      if (!scale.almost_equal(LVecBase3f(1.0f, 1.0f, 1.0f))) {
+        egg_group->add_scale(LCAST(double, scale));
+      }
+      if (!quat.is_identity()) {
+        egg_group->add_rotate(LCAST(double, quat));
+      }
+      if (!pos.almost_equal(LVecBase3f::zero())) {
+        egg_group->add_translate(LCAST(double, pos));
+      }
+
+    } else if (transform->has_mat()) {
+      // Otherwise, we store the raw matrix.
+      const LMatrix4f &mat = transform->get_mat();
+      egg_group->set_transform(LCAST(double, mat));
+    }
+    any_applied = true;
+  }
+
+  return any_applied;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BamToEgg::get_egg_texture
+//       Access: Public
+//  Description: Returns an EggTexture pointer that corresponds to the
+//               indicated Texture.
+////////////////////////////////////////////////////////////////////
+EggTexture *BamToEgg::
+get_egg_texture(Texture *tex) {
   if (tex != (Texture *)NULL) {
     if (tex->has_filename()) {
-      Filename filename = SomethingToEggConverter::convert_path
-        (tex->get_filename(), get_texture_path(), _make_rel_dir, 
-         _texture_path_convert);
-
-      EggTexture temp("", filename);
+      Filename filename = tex->get_filename();
+      EggTexture temp(filename.get_basename_wo_extension(), filename);
       if (tex->has_alpha_filename()) {
-        Filename alpha = SomethingToEggConverter::convert_path
-          (tex->get_alpha_filename(), get_texture_path(), _make_rel_dir, 
-           _texture_path_convert);
-        temp.set_alpha_file(alpha);
+        Filename alpha = tex->get_alpha_filename();
+        temp.set_alpha_filename(alpha);
       }
 
       switch (tex->get_minfilter()) {
+      case Texture::FT_invalid:
+        break;
       case Texture::FT_nearest:
         temp.set_minfilter(EggTexture::FT_nearest);
         break;
@@ -560,6 +527,11 @@ apply_texture(EggPrimitive *egg_prim, Texture *tex) {
       case Texture::WM_repeat:
         temp.set_wrap_u(EggTexture::WM_repeat);
         break;
+
+      default:
+        // There are some new wrap options on Texture that aren't yet
+        // supported in egg.
+        break;
       }
 
       switch (tex->get_wrapv()) {
@@ -569,6 +541,11 @@ apply_texture(EggPrimitive *egg_prim, Texture *tex) {
       case Texture::WM_repeat:
         temp.set_wrap_v(EggTexture::WM_repeat);
         break;
+
+      default:
+        // There are some new wrap options on Texture that aren't yet
+        // supported in egg.
+        break;
       }
 
       PixelBuffer *pbuf = tex->get_ram_image();
@@ -633,61 +610,161 @@ apply_texture(EggPrimitive *egg_prim, Texture *tex) {
         }
       }
 
-      EggTexture *egg_tex = 
-        _textures.create_unique_texture(temp, ~EggTexture::E_tref_name);
-      egg_prim->set_texture(egg_tex);
+      return _textures.create_unique_texture(temp, ~EggTexture::E_tref_name);
     }
   }
+
+  return NULL;
 }
 
+#if 0
+
+
 ////////////////////////////////////////////////////////////////////
-//     Function: BamToEgg::apply_arc_properties
+//     Function: BamToEgg::GeomState::Constructor
 //       Access: Public
-//  Description: Applies any special properties that might be stored
-//               on the arc, like billboarding.  Returns true if any
-//               were applied, false otherwise.
+//  Description: 
 ////////////////////////////////////////////////////////////////////
-bool BamToEgg::
-apply_arc_properties(EggGroup *egg_group, ArcChain &chain) {
-  if (!chain.has_arcs()) {
-    return false;
+BamToEgg::GeomState::
+GeomState() {
+  _mat = LMatrix4f::ident_mat();
+  _tex_mat = LMatrix4f::ident_mat();
+  _color_mat = LMatrix4f::ident_mat();
+  _alpha_scale = 1.0;
+  _alpha_offset = 0.0;
+  _tex = (Texture *)NULL;
+  _bface = false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BamToEgg::GeomState::get_net_state
+//       Access: Public
+//  Description: Gets the accumulated state of the indicated node (and
+//               its corresponding ArcChain) into the GeomState.
+////////////////////////////////////////////////////////////////////
+void BamToEgg::GeomState::
+get_net_state(Node *node, ArcChain &chain, EggGroupNode *egg_parent) {
+  AllTransitionsWrapper atw;
+
+  wrt(node, chain.begin(), chain.end(),
+      (Node *)NULL,
+      atw, RenderRelation::get_class_type());
+
+  // Check for transform space.
+  const TransformTransition *tt;
+  if (get_transition_into(tt, atw)) {
+    _mat = tt->get_matrix();
+    LMatrix4f inv = LCAST(float, egg_parent->get_vertex_frame_inv());
+    _mat = _mat * inv;
   }
-  NodeRelation *arc = chain.back();
-  bool any_applied = false;
 
-  BillboardTransition *bt;
-  if (get_transition_into(bt, arc)) {
-    if (bt->get_axial_rotate()) {
-      egg_group->set_billboard_type(EggGroup::BT_axis);
-      any_applied = true;
+  // Check for texture matrix.
+  const TexMatrixTransition *tmt;
+  if (get_transition_into(tmt, atw)) {
+    _tex_mat = tmt->get_matrix();
+  }
 
-    } else if (bt->get_eye_relative()) {
-      egg_group->set_billboard_type(EggGroup::BT_point_camera_relative);
-      any_applied = true;
+  // Check for color matrix.
+  const ColorMatrixTransition *cmt;
+  if (get_transition_into(cmt, atw)) {
+    _color_mat = cmt->get_matrix();
+  }
 
-    } else {
-      egg_group->set_billboard_type(EggGroup::BT_point_world_relative);
-      any_applied = true;
-    }
+  // Check for alpha scale/offset.
+  const AlphaTransformTransition *att;
+  if (get_transition_into(att, atw)) {
+    _alpha_scale = att->get_scale();
+    _alpha_offset = att->get_offset();
   }
 
-  const TransformTransition *tt;
-  if (get_transition_into(tt, arc)) {
-    LMatrix4f mat = tt->get_matrix();
-    egg_group->set_transform(LCAST(double, mat));
-    any_applied = true;
+  // Check for texture.
+  const TextureTransition *txt;
+  if (get_transition_into(txt, atw)) {
+    if (txt->is_on()) {
+      _tex = txt->get_texture();
+    }
   }
 
-  const DecalTransition *dt;
-  if (get_transition_into(dt, arc)) {
-    if (dt->is_on()) {
-      egg_group->set_decal_flag(true);
-      any_applied = true;
+  // Check for bface.
+  const CullFaceTransition *cft;
+  if (get_transition_into(cft, atw)) {
+    if (cft->get_mode() == CullFaceProperty::M_cull_none) {
+      _bface = true;
     }
   }
+}
 
-  return any_applied;
+////////////////////////////////////////////////////////////////////
+//     Function: BamToEgg::GeomState::apply_vertex
+//       Access: Public
+//  Description: Applies the indicated vertex coordinate to the given
+//               EggVertex, after modifying it according to the
+//               current state.
+////////////////////////////////////////////////////////////////////
+void BamToEgg::GeomState::
+apply_vertex(EggVertex &egg_vert, const Vertexf &vertex) {
+  LPoint3f transformed = vertex * _mat;
+  egg_vert.set_pos(LCAST(double, transformed));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BamToEgg::GeomState::apply_normal
+//       Access: Public
+//  Description: Applies the indicated vertex normal to the given
+//               EggVertex, after modifying it according to the
+//               current state.
+////////////////////////////////////////////////////////////////////
+void BamToEgg::GeomState::
+apply_normal(EggVertex &egg_vert, const Normalf &normal) {
+  LPoint3f transformed = normal * _mat;
+  egg_vert.set_normal(LCAST(double, transformed));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BamToEgg::GeomState::apply_uv
+//       Access: Public
+//  Description: Applies the indicated vertex UV to the given
+//               EggVertex, after modifying it according to the
+//               current state.
+////////////////////////////////////////////////////////////////////
+void BamToEgg::GeomState::
+apply_uv(EggVertex &egg_vert, const TexCoordf &uv) {
+  LVecBase4f v4(uv[0], uv[1], 0.0, 1.0);
+  v4 = v4 * _tex_mat;
+  egg_vert.set_uv(LCAST(double, uv));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BamToEgg::GeomState::apply_color
+//       Access: Public
+//  Description: Applies the indicated vertex color to the given
+//               EggVertex, after modifying it according to the
+//               current state.
+////////////////////////////////////////////////////////////////////
+void BamToEgg::GeomState::
+apply_color(EggVertex &egg_vert, const Colorf &color) {
+  LPoint3f temp(color[0], color[1], color[2]);
+  temp = temp * _color_mat;
+  float alpha = (color[3] * _alpha_scale) +
+    _alpha_offset;
+  
+  Colorf transformed(temp[0], temp[1], temp[2], alpha);
+  egg_vert.set_color(transformed);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BamToEgg::GeomState::apply_prim
+//       Access: Public
+//  Description: Applies generic, non-vertex-specific properties to
+//               the primitive.
+////////////////////////////////////////////////////////////////////
+void BamToEgg::GeomState::
+apply_prim(EggPrimitive *egg_prim) {
+  if (_bface) {
+    egg_prim->set_bface_flag(true);
+  }
 }
+#endif
 
 
 int main(int argc, char *argv[]) {

+ 27 - 7
pandatool/src/bam/bamToEgg.h

@@ -26,20 +26,23 @@
 #include "eggTextureCollection.h"
 #include "eggMaterialCollection.h"
 
-class Node;
+class WorkingNodePath;
+class EggGroup;
+class EggGroupNode;
+class EggVertexPool;
+class EggTexture;
 class LODNode;
 class GeomNode;
-class ArcChain;
 class GeomTri;
-class EggVertexPool;
-class EggVertex;
-class EggPrimitive;
-class EggGroup;
+class PandaNode;
+class RenderState;
 class Texture;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : BamToEgg
-// Description :
+// Description : This program reads a bam file, for instance as
+//               written out from a real-time interaction session, and
+//               generates a corresponding egg file.
 ////////////////////////////////////////////////////////////////////
 class BamToEgg : public SomethingToEgg {
 public:
@@ -48,6 +51,22 @@ public:
   void run();
 
 private:
+  void convert_node(const WorkingNodePath &node_path, EggGroupNode *egg_parent,
+                    bool has_decal);
+  void convert_lod_node(LODNode *node, const WorkingNodePath &node_path,
+                        EggGroupNode *egg_parent, bool has_decal);
+  void convert_geom_node(GeomNode *node, const WorkingNodePath &node_path, 
+                         EggGroupNode *egg_parent, bool has_decal);
+  void convert_geom_tri(GeomTri *geom, const RenderState *net_state,
+                        const LMatrix4f &net_mat, EggGroupNode *egg_parent);
+  void recurse_nodes(const WorkingNodePath &node_path, EggGroupNode *egg_parent,
+                     bool has_decal);
+  bool apply_node_properties(EggGroup *egg_group, PandaNode *node);
+
+  EggTexture *get_egg_texture(Texture *tex);
+
+
+  /*
   class GeomState {
   public:
     GeomState();
@@ -78,6 +97,7 @@ private:
 
   void apply_texture(EggPrimitive *egg_prim, Texture *tex);
   bool apply_arc_properties(EggGroup *egg_group, ArcChain &chain);
+  */
 
   EggVertexPool *_vpool;
   EggTextureCollection _textures;