Browse Source

add egg2flt

David Rose 22 years ago
parent
commit
891c04db07

+ 32 - 0
pandatool/src/flt/fltGeometry.I

@@ -39,6 +39,22 @@ get_texture() const {
   return _header->get_texture(_texture_index);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: FltGeometry::set_texture
+//       Access: Public
+//  Description: Applies the indicated texture to this face, or if the
+//               texture is NULL, clears it.
+////////////////////////////////////////////////////////////////////
+INLINE void FltGeometry::
+set_texture(FltTexture *texture) {
+  if (texture == (FltTexture *)NULL) {
+    _texture_index = -1;
+  } else {
+    _header->add_texture(texture);
+    _texture_index = texture->_pattern_index;
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: FltGeometry::has_material
 //       Access: Public
@@ -61,6 +77,22 @@ get_material() const {
   return _header->get_material(_material_index);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: FltGeometry::set_material
+//       Access: Public
+//  Description: Applies the indicated material to this face, or if the
+//               material is NULL, clears it.
+////////////////////////////////////////////////////////////////////
+INLINE void FltGeometry::
+set_material(FltMaterial *material) {
+  if (material == (FltMaterial *)NULL) {
+    _material_index = -1;
+  } else {
+    _header->add_material(material);
+    _material_index = material->_material_index;
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: FltGeometry::has_color
 //       Access: Public

+ 30 - 2
pandatool/src/flt/fltGeometry.cxx

@@ -33,7 +33,7 @@ FltGeometry::
 FltGeometry(FltHeader *header) : FltBeadID(header) {
   _ir_color = 0;
   _relative_priority = 0;
-  _draw_type = DT_solid_backface;
+  _draw_type = DT_solid_cull_backface;
   _texwhite = false;
   _color_name_index = 0;
   _alt_color_name_index = 0;
@@ -47,7 +47,7 @@ FltGeometry(FltHeader *header) : FltBeadID(header) {
   _transparency = 0;
   _lod_generation_control = 0;
   _line_style_index = 0;
-  _flags = 0;
+  _flags = F_no_color;
   _light_mode = LM_face_no_normal;
   _texture_mapping_index = 0;
   _color_index = 0;
@@ -94,6 +94,18 @@ get_color() const {
   return color;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: FltGeometry::set_color
+//       Access: Public
+//  Description: Sets the primary color of the face, using the packed
+//               color convention.
+////////////////////////////////////////////////////////////////////
+void FltGeometry::
+set_color(const Colorf &color) {
+  set_rgb(RGBColorf(color[0], color[1], color[2]));
+  _transparency = (int)floor((1.0 - color[3]) * 65535.0);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: FltGeometry::get_rgb
 //       Access: Public
@@ -117,6 +129,22 @@ get_rgb() const {
                           _packed_color);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: FltGeometry::set_rgb
+//       Access: Public
+//  Description: Sets the primary color of the face, using the packed
+//               color convention; does not affect transparency.
+////////////////////////////////////////////////////////////////////
+void FltGeometry::
+set_rgb(const RGBColorf &rgb) {
+  _packed_color.set_rgb(rgb);
+  _flags = ((_flags & ~F_no_color) | F_packed_color);
+
+  // If we have a color, we can't have a material.
+  _material_index = -1;
+  _texwhite = false;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: FltGeometry::has_alt_color
 //       Access: Public

+ 9 - 5
pandatool/src/flt/fltGeometry.h

@@ -42,14 +42,14 @@ public:
   FltGeometry(FltHeader *header);
 
   enum DrawType {
-    DT_solid_backface      = 0,
-    DT_solid_no_backface   = 1,
+    DT_solid_cull_backface = 0,
+    DT_solid_no_cull       = 1,
     DT_wireframe           = 2,
     DT_wireframe_close     = 3,
     DT_wireframe_highlight = 4,
-    DT_omni_light          = 5,
-    DT_uni_light           = 6,
-    DT_bi_light            = 7
+    DT_omni_light          = 8,
+    DT_uni_light           = 9,
+    DT_bi_light            = 10
   };
 
   enum BillboardType {
@@ -102,13 +102,17 @@ public:
 public:
   INLINE bool has_texture() const;
   INLINE FltTexture *get_texture() const;
+  INLINE void set_texture(FltTexture *texture);
 
   INLINE bool has_material() const;
   INLINE FltMaterial *get_material() const;
+  INLINE void set_material(FltMaterial *material);
 
   INLINE bool has_color() const;
   Colorf get_color() const;
+  void set_color(const Colorf &color);
   RGBColorf get_rgb() const;
+  void set_rgb(const RGBColorf &rgb);
 
   bool has_alt_color() const;
   Colorf get_alt_color() const;

+ 24 - 0
pandatool/src/flt/fltHeader.cxx

@@ -103,6 +103,8 @@ FltHeader(PathReplace *path_replace) : FltBeadID(this) {
 
   _vertex_lookups_stale = false;
   _current_vertex_offset = 0;
+  _next_material_index = 1;
+  _next_pattern_index = 1;
   _got_color_palette = false;
   _got_14_material_palette = false;
   _got_eyepoint_trackplane_palette = false;
@@ -957,6 +959,17 @@ clear_materials() {
 ////////////////////////////////////////////////////////////////////
 void FltHeader::
 add_material(FltMaterial *material) {
+  if (material->_material_index < 0) {
+    // We need to make up a new material index for the material.
+    material->_material_index = _next_material_index;
+    _next_material_index++;
+
+  } else {
+    // Make sure our next generated material index will be different
+    // from any existing material indices.
+    _next_material_index = max(_next_material_index, material->_material_index + 1);
+  }
+
   _materials[material->_material_index] = material;
 }
 
@@ -1018,6 +1031,17 @@ clear_textures() {
 ////////////////////////////////////////////////////////////////////
 void FltHeader::
 add_texture(FltTexture *texture) {
+  if (texture->_pattern_index < 0) {
+    // We need to make up a new pattern index for the texture.
+    texture->_pattern_index = _next_pattern_index;
+    _next_pattern_index++;
+
+  } else {
+    // Make sure our next generated pattern index will be different
+    // from any existing texture indices.
+    _next_pattern_index = max(_next_pattern_index, texture->_pattern_index + 1);
+  }
+
   _textures[texture->_pattern_index] = texture;
 }
 

+ 2 - 0
pandatool/src/flt/fltHeader.h

@@ -279,12 +279,14 @@ private:
   bool _got_14_material_palette;
   typedef pmap<int, PT(FltMaterial)> Materials;
   Materials _materials;
+  int _next_material_index;
 
 
   // Support for the texture palette.
   AttrUpdate _auto_attr_update;
   typedef pmap<int, PT(FltTexture)> Textures;
   Textures _textures;
+  int _next_pattern_index;
 
 
   // Support for the light source palette.

+ 1 - 1
pandatool/src/flt/fltMaterial.cxx

@@ -29,7 +29,7 @@ TypeHandle FltMaterial::_type_handle;
 ////////////////////////////////////////////////////////////////////
 FltMaterial::
 FltMaterial(FltHeader *header) : FltRecord(header) {
-  _material_index = 0;
+  _material_index = -1;
   _flags = 0;
   _ambient.set(0.0, 0.0, 0.0);
   _diffuse.set(0.0, 0.0, 0.0);

+ 5 - 5
pandatool/src/flt/fltPackedColor.I

@@ -68,9 +68,9 @@ get_rgb() const {
 INLINE void FltPackedColor::
 set_color(const Colorf &color) {
   _r = (int)floor(color[0] * 255.0);
-  _g = (int)floor(color[0] * 255.0);
-  _b = (int)floor(color[0] * 255.0);
-  _a = (int)floor(color[0] * 255.0);
+  _g = (int)floor(color[1] * 255.0);
+  _b = (int)floor(color[2] * 255.0);
+  _a = (int)floor(color[3] * 255.0);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -83,7 +83,7 @@ set_color(const Colorf &color) {
 INLINE void FltPackedColor::
 set_rgb(const RGBColorf &color) {
   _r = (int)floor(color[0] * 255.0);
-  _g = (int)floor(color[0] * 255.0);
-  _b = (int)floor(color[0] * 255.0);
+  _g = (int)floor(color[1] * 255.0);
+  _b = (int)floor(color[2] * 255.0);
   _a = 255;
 }

+ 1 - 1
pandatool/src/flt/fltTexture.cxx

@@ -32,7 +32,7 @@ TypeHandle FltTexture::_type_handle;
 ////////////////////////////////////////////////////////////////////
 FltTexture::
 FltTexture(FltHeader *header) : FltRecord(header) {
-  _pattern_index = 0;
+  _pattern_index = -1;
   _x_location = 0;
   _y_location = 0;
 

+ 11 - 0
pandatool/src/flt/fltVertex.I

@@ -30,3 +30,14 @@ has_color() const {
   return ((_flags & F_no_color) == 0 &&
           (_color_index != -1 || ((_flags & F_packed_color) != 0)));
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltVertex::set_color
+//       Access: Public
+//  Description: Sets the color of the vertex, using the packed
+//               color convention.  The alpha component is ignored.
+////////////////////////////////////////////////////////////////////
+INLINE void FltVertex::
+set_color(const Colorf &color) {
+  set_rgb(RGBColorf(color[0], color[1], color[2]));
+}

+ 19 - 8
pandatool/src/flt/fltVertex.cxx

@@ -31,7 +31,7 @@ TypeHandle FltVertex::_type_handle;
 FltVertex::
 FltVertex(FltHeader *header) : FltRecord(header) {
   _color_name_index = 0;
-  _flags = 0;
+  _flags = F_no_color;
   _pos.set(0.0, 0.0, 0.0);
   _normal.set(0.0, 0.0, 0.0);
   _uv.set(0.0, 0.0);
@@ -117,10 +117,10 @@ get_record_length() const {
 ////////////////////////////////////////////////////////////////////
 //     Function: FltVertex::get_color
 //       Access: Public
-//  Description: If has_color() indicates true, returns the primary
-//               color of the face, as a four-component value.  In the
-//               case of a vertex, the alpha channel will always be
-//               1.0, as MultiGen does not store transparency
+//  Description: If has_color() indicates true, returns the 
+//               color of the vertex, as a four-component value.  In
+//               the case of a vertex, the alpha channel will always
+//               be 1.0, as MultiGen does not store transparency
 //               per-vertex.
 ////////////////////////////////////////////////////////////////////
 Colorf FltVertex::
@@ -134,9 +134,8 @@ get_color() const {
 ////////////////////////////////////////////////////////////////////
 //     Function: FltVertex::get_rgb
 //       Access: Public
-//  Description: If has_color() indicates true, returns the primary
-//               color of the face, as a three-component value
-//               ignoring transparency.
+//  Description: If has_color() indicates true, returns the 
+//               color of the vertex, as a three-component value.
 ////////////////////////////////////////////////////////////////////
 RGBColorf FltVertex::
 get_rgb() const {
@@ -146,6 +145,18 @@ get_rgb() const {
                           _packed_color);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: FltVertex::set_rgb
+//       Access: Public
+//  Description: Sets the color of the vertex, using the packed
+//               color convention.
+////////////////////////////////////////////////////////////////////
+void FltVertex::
+set_rgb(const RGBColorf &rgb) {
+  _packed_color.set_rgb(rgb);
+  _flags = ((_flags & ~F_no_color) | F_packed_color);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: FltVertex::extract_record
 //       Access: Protected, Virtual

+ 2 - 0
pandatool/src/flt/fltVertex.h

@@ -64,7 +64,9 @@ public:
 public:
   INLINE bool has_color() const;
   Colorf get_color() const;
+  INLINE void set_color(const Colorf &color);
   RGBColorf get_rgb() const;
+  void set_rgb(const RGBColorf &rgb);
 
 
 protected:

+ 1 - 2
pandatool/src/flt/fltVertexList.cxx

@@ -67,11 +67,10 @@ clear_vertices() {
 //     Function: FltVertexList::add_vertex
 //       Access: Public
 //  Description: Adds a new vertex to the end of the vertex list.
-//               Care must be taken to ensure the vertex is also added
-//               to the vertex palette.
 ////////////////////////////////////////////////////////////////////
 void FltVertexList::
 add_vertex(FltVertex *vertex) {
+  _header->add_vertex(vertex);
   _vertices.push_back(vertex);
 }
 

+ 1 - 1
pandatool/src/fltegg/fltToEggConverter.cxx

@@ -526,7 +526,7 @@ setup_geometry(const FltGeometry *flt_geom, FltToEggLevelState &state,
     }
   }
 
-  if (flt_geom->_draw_type == FltGeometry::DT_solid_no_backface) {
+  if (flt_geom->_draw_type == FltGeometry::DT_solid_no_cull) {
     // A double-sided polygon.
     egg_prim->set_bface_flag(true);
   }

+ 1 - 1
pandatool/src/fltegg/fltToEggLevelState.cxx

@@ -65,7 +65,7 @@ ParentNodes() {
 //
 //               This collects together polygons that share the same
 //               billboard axis and/or transform space into the same
-//               group, rather that wastefully creating a group per
+//               group, rather than wastefully creating a group per
 //               polygon.
 ////////////////////////////////////////////////////////////////////
 EggGroupNode *FltToEggLevelState::

+ 15 - 0
pandatool/src/fltprogs/Sources.pp

@@ -59,3 +59,18 @@
     fltToEgg.cxx fltToEgg.h
 
 #end bin_target
+
+#begin bin_target
+  #define TARGET egg2flt
+  #define LOCAL_LIBS flt eggbase progbase
+
+  #define OTHER_LIBS \
+    egg:c pandaegg:m \
+    linmath:c panda:m \
+    express:c pandaexpress:m \
+    dtoolutil:c dtoolbase:c dconfig:c dtoolconfig:m dtool:m pystub
+
+  #define SOURCES \
+    eggToFlt.cxx eggToFlt.h
+
+#end bin_target

+ 660 - 0
pandatool/src/fltprogs/eggToFlt.cxx

@@ -0,0 +1,660 @@
+// Filename: eggToFlt.cxx
+// Created by:  drose (01Oct03)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "eggToFlt.h"
+#include "fltHeader.h"
+#include "fltBead.h"
+#include "fltGroup.h"
+#include "fltFace.h"
+#include "fltVertexList.h"
+#include "fltVertex.h"
+#include "fltTexture.h"
+#include "fltTransformTranslate.h"
+#include "fltTransformRotateAboutEdge.h"
+#include "fltTransformScale.h"
+#include "fltTransformGeneralMatrix.h"
+#include "eggPolygon.h"
+#include "eggPoint.h"
+#include "eggPrimitive.h"
+#include "eggExternalReference.h"
+#include "eggGroup.h"
+#include "eggGroupNode.h"
+#include "eggTexture.h"
+#include "eggTransform3d.h"
+#include "dcast.h"
+#include "string_utils.h"
+#include "vector_string.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggToFlt::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+EggToFlt::
+EggToFlt() :
+  EggToSomething("MultiGen", ".flt", true, false)
+{
+  set_binary_output(true);
+  set_program_description
+    ("egg2flt converts files from egg format to MultiGen .flt "
+     "format.  It attempts to be as robust as possible, and matches "
+     "the capabilities of flt2egg.  Generally, converting a model "
+     "from egg2flt and then back via flt2egg will result in essentially "
+     "the same egg file, within the limitations of what can be "
+     "represented in flt.");
+
+  add_option
+    ("attr", "none/new/all", 0,
+     "Specifies whether to write (or rewrite) .attr files for each "
+     "texture image.  MultiGen stores texture properties like mipmapping "
+     "in a separate .attr file for each different texture image.  "
+     "If this parameter is \"none\", these files will not be generated; "
+     "if this is \"new\", these files will only be generated if they "
+     "do not already exist (even if the properties have changed).  "
+     "Specifying \"all\" causes these to be rewritten every time.",
+     &EggToFlt::dispatch_attr, NULL, &_auto_attr_update);
+
+  // Flt files are always in the z-up coordinate system.  Don't
+  // confuse the user with this meaningless option.
+  remove_option("cs");
+  _coordinate_system = CS_zup_right;
+  _got_coordinate_system = true;
+  _auto_attr_update = FltHeader::AU_if_missing;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggToFlt::run
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+void EggToFlt::
+run() {
+  _flt_header = new FltHeader(_path_replace);
+  _flt_header->set_auto_attr_update(_auto_attr_update);
+
+  traverse(&_data, _flt_header, FltGeometry::BT_none);
+
+  // Finally, write the resulting file out.
+  FltError result = _flt_header->write_flt(get_output());
+  if (result != FE_ok) {
+    nout << "Cannot write " << get_output_filename() << "\n";
+    exit(1);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggToFlt::dispatch_attr
+//       Access: Protected, Static
+//  Description: Dispatch function for the -attr parameter.
+////////////////////////////////////////////////////////////////////
+bool EggToFlt::
+dispatch_attr(const string &opt, const string &arg, void *var) {
+  FltHeader::AttrUpdate *ip = (FltHeader::AttrUpdate *)var;
+
+  if (cmp_nocase(arg, "none") == 0) {
+    *ip = FltHeader::AU_none;
+
+  } else if (cmp_nocase(arg, "new") == 0) {
+    *ip = FltHeader::AU_if_missing;
+
+  } else if (cmp_nocase(arg, "all") == 0) {
+    *ip = FltHeader::AU_always;
+
+  } else {
+    nout << "-" << opt
+         << " requires either \"none\", \"new\", or \"all\".\n";
+    return false;
+  }
+   
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggToFlt::traverse
+//       Access: Private
+//  Description:
+////////////////////////////////////////////////////////////////////
+void EggToFlt::
+traverse(EggNode *egg_node, FltBead *flt_node, 
+         FltGeometry::BillboardType billboard) {
+  if (egg_node->is_of_type(EggPolygon::get_class_type()) ||
+      egg_node->is_of_type(EggPoint::get_class_type())) {
+    // It's a polygon or point light.
+    EggPrimitive *egg_primitive = DCAST(EggPrimitive, egg_node);
+    convert_primitive(egg_primitive, flt_node, billboard);
+
+  } else if (egg_node->is_of_type(EggExternalReference::get_class_type())) {
+    // Convert external references.
+
+  } else if (egg_node->is_of_type(EggGroup::get_class_type())) {
+    // An EggGroup creates a fltBead, and recurses.
+    EggGroup *egg_group = DCAST(EggGroup, egg_node);
+
+    if (egg_group->get_group_type() == EggGroup::GT_joint) {
+      // Ignore joints and their children.
+      return;
+    }
+
+    convert_group(egg_group, flt_node, billboard);
+
+  } else if (egg_node->is_of_type(EggGroupNode::get_class_type())) {
+    // Some kind of grouping node other than an EggGroup.  Just recurse.
+    EggGroupNode *egg_group = DCAST(EggGroupNode, egg_node);
+    EggGroupNode::iterator ci;
+    for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) {
+      traverse(*ci, flt_node, billboard);
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggToFlt::convert_primitive
+//       Access: Private
+//  Description: Converts an egg polygon or series of light points to
+//               the corresponding Flt geometry, and adds it to the
+//               indicated flt_node.
+////////////////////////////////////////////////////////////////////
+void EggToFlt::
+convert_primitive(EggPrimitive *egg_primitive, FltBead *flt_node,
+                  FltGeometry::BillboardType billboard) {
+  FltFace *flt_face = new FltFace(_flt_header);
+  flt_node->add_child(flt_face);
+
+  flt_face->_billboard_type = billboard;
+
+  if (egg_primitive->has_color()) {
+    flt_face->set_color(egg_primitive->get_color());
+  }
+
+  if (egg_primitive->is_of_type(EggPoint::get_class_type())) {
+    // A series of points, instead of a polygon.
+    flt_face->_draw_type = FltFace::DT_omni_light;
+      
+  } else if (egg_primitive->get_bface_flag()) {
+    // A polygon whose backface is visible.
+    flt_face->_draw_type = FltFace::DT_solid_no_cull;
+      
+  } else {
+    // A normal polygon.
+    flt_face->_draw_type = FltFace::DT_solid_cull_backface;
+  }
+
+  if (egg_primitive->has_texture()) {
+    EggTexture *egg_texture = egg_primitive->get_texture();
+    FltTexture *flt_texture = get_flt_texture(egg_texture);
+    flt_face->set_texture(flt_texture);
+  }
+
+  // Create a vertex list representing the vertices in the
+  // primitive, and add it as a child of the face bead.  This is how
+  // Flt files associate vertices with faces.
+  FltVertexList *flt_vertices = new FltVertexList(_flt_header);
+  flt_face->add_child(flt_vertices);
+
+  EggPrimitive::iterator vi;
+  bool all_verts_have_color = true;
+  bool all_verts_have_normal = true;
+  for (vi = egg_primitive->begin(); vi != egg_primitive->end(); ++vi) {
+    EggVertex *egg_vertex = (*vi);
+    FltVertex *flt_vertex = get_flt_vertex(egg_vertex, egg_primitive);
+    flt_vertices->add_vertex(flt_vertex);
+
+    if (!egg_vertex->has_color()) {
+      all_verts_have_color = false;
+    }
+    if (!egg_vertex->has_normal()) {
+      all_verts_have_normal = false;
+    }
+  }
+  if (all_verts_have_color) {
+    // If all the vertices of the face have a color specification,
+    // then we specify per-vertex color on the face.
+    if (all_verts_have_normal) {
+      // And similarly with the normals.
+      flt_face->_light_mode = FltFace::LM_vertex_with_normal;
+    } else {
+      flt_face->_light_mode = FltFace::LM_vertex_no_normal;
+    }
+  } else {
+    if (all_verts_have_normal) {
+      flt_face->_light_mode = FltFace::LM_face_with_normal;
+    } else {
+      flt_face->_light_mode = FltFace::LM_face_no_normal;
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggToFlt::convert_group
+//       Access: Private
+//  Description: Converts an egg group to the corresponding flt group,
+//              and adds it to the indicated parent node.  Also
+//              recurses on the children of the egg group.
+////////////////////////////////////////////////////////////////////
+void EggToFlt::
+convert_group(EggGroup *egg_group, FltBead *flt_node, 
+              FltGeometry::BillboardType billboard) {
+  ostringstream egg_syntax;
+
+  FltGroup *flt_group = new FltGroup(_flt_header);
+  flt_node->add_child(flt_group);
+  
+  flt_group->set_id(egg_group->get_name());
+
+  switch (egg_group->get_billboard_type()) {
+    // MultiGen represents billboarding at the polygon level, so we
+    // have to remember this flag for later.
+  case EggGroup::BT_axis:
+    billboard = FltGeometry::BT_axial;
+    break;
+
+  case EggGroup::BT_point_world_relative:
+    billboard = FltGeometry::BT_point;
+    break;
+
+  case EggGroup::BT_point_camera_relative:
+    // Not sure if this is the right flag for MultiGen.
+    billboard = FltGeometry::BT_fixed;
+    break;
+
+  default:
+    break;
+  }
+  
+  if (egg_group->has_transform()) {
+    apply_transform(egg_group, flt_group);
+  }
+  
+  if (egg_group->get_switch_flag()) {
+    if (egg_group->get_switch_fps() != 0.0) {
+      // A sequence animation.
+      flt_group->_flags |= FltGroup::F_forward_animation;
+      egg_syntax
+        << "  <Scalar> fps { " << egg_group->get_switch_fps() << " }\n";
+    } else {
+      // Just a switch node.
+      egg_group->write_switch_flags(egg_syntax, 2);
+    }
+  }
+
+  // Pick up any additional egg attributes that MultiGen doesn't
+  // support; these will get written to the comment field where
+  // flt2egg will find it.
+  egg_group->write_collide_flags(egg_syntax, 2);
+  egg_group->write_model_flags(egg_syntax, 2);
+  egg_group->write_object_types(egg_syntax, 2);
+  egg_group->write_decal_flags(egg_syntax, 2);
+  egg_group->write_tags(egg_syntax, 2);
+  egg_group->write_render_mode(egg_syntax, 2);
+
+  apply_egg_syntax(egg_syntax.str(), flt_group);
+  
+  EggGroup::iterator ci;
+  for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) {
+    traverse(*ci, flt_group, billboard);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggToFlt::apply_transform
+//       Access: Private
+//  Description: Applies the indicated egg transform to the indicated
+//               flt bead.
+////////////////////////////////////////////////////////////////////
+void EggToFlt::
+apply_transform(EggTransform3d *egg_transform, FltBead *flt_node) {
+  flt_node->clear_transform();
+
+  bool components_ok = true;
+  int num_components = egg_transform->get_num_components();
+  for (int i = num_components - 1; i >= 0 && components_ok; i--) {
+    switch (egg_transform->get_component_type(i)) {
+    case EggTransform3d::CT_translate:
+      {
+        FltTransformTranslate *translate = 
+          new FltTransformTranslate(_flt_header);
+        translate->set(LPoint3d::zero(), egg_transform->get_component_vector(i));
+        flt_node->add_transform_step(translate);
+      }
+      break;
+
+    case EggTransform3d::CT_rotx:
+      {
+        FltTransformRotateAboutEdge *rotate = 
+          new FltTransformRotateAboutEdge(_flt_header);
+        rotate->set(LPoint3d::zero(), LPoint3d(1.0, 0.0, 0.0),
+                    egg_transform->get_component_number(i));
+        flt_node->add_transform_step(rotate);
+      }
+      break;
+
+    case EggTransform3d::CT_roty:
+      {
+        FltTransformRotateAboutEdge *rotate = 
+          new FltTransformRotateAboutEdge(_flt_header);
+        rotate->set(LPoint3d::zero(), LPoint3d(0.0, 1.0, 0.0),
+                    egg_transform->get_component_number(i));
+        flt_node->add_transform_step(rotate);
+      }
+      break;
+
+    case EggTransform3d::CT_rotz:
+      {
+        FltTransformRotateAboutEdge *rotate = 
+          new FltTransformRotateAboutEdge(_flt_header);
+        rotate->set(LPoint3d::zero(), LPoint3d(0.0, 0.0, 1.0),
+                    egg_transform->get_component_number(i));
+        flt_node->add_transform_step(rotate);
+      }
+      break;
+
+    case EggTransform3d::CT_rotate:
+      {
+        FltTransformRotateAboutEdge *rotate = 
+          new FltTransformRotateAboutEdge(_flt_header);
+        rotate->set(LPoint3d::zero(), egg_transform->get_component_vector(i),
+                    egg_transform->get_component_number(i));
+        flt_node->add_transform_step(rotate);
+      }
+      break;
+
+    case EggTransform3d::CT_scale:
+      {
+        FltTransformScale *scale = new FltTransformScale(_flt_header);
+        scale->set(LPoint3d::zero(), LCAST(float, egg_transform->get_component_vector(i)));
+        flt_node->add_transform_step(scale);
+      }
+      break;
+
+    case EggTransform3d::CT_uniform_scale:
+      {
+        FltTransformScale *scale = new FltTransformScale(_flt_header);
+        float factor = (float)egg_transform->get_component_number(i);
+        scale->set(LPoint3d::zero(), LVecBase3f(factor, factor, factor));
+        flt_node->add_transform_step(scale);
+      }
+      break;
+
+    case EggTransform3d::CT_matrix:
+      {
+        FltTransformGeneralMatrix *matrix = 
+          new FltTransformGeneralMatrix(_flt_header);
+        matrix->set_matrix(egg_transform->get_component_matrix(i));
+        flt_node->add_transform_step(matrix);
+      }
+      break;
+
+    default:
+      // Don't know how to convert this component.
+      components_ok = false;
+    }
+  }
+
+  if (components_ok) {
+    // Verify that the transform was computed correctly.
+    if (!flt_node->get_transform().almost_equal(egg_transform->get_transform())) {
+      nout << "Incorrect transform!  Expected:\n";
+      egg_transform->get_transform().write(nout, 2);
+      nout << "Computed:\n";
+      flt_node->get_transform().write(nout, 2);
+      nout << "\n";
+      components_ok = false;
+    }
+  }
+
+  if (!components_ok) {
+    // Just store the overall transform.
+    flt_node->set_transform(egg_transform->get_transform());
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggToFlt::apply_egg_syntax
+//       Access: Private
+//  Description: Adds the indicated sequence of egg syntax lines
+//               (presumably representing egg features not directly
+//               supported by MultiGen) to the flt record as a
+//               comment, so that flt2egg will reapply it to the egg
+//               groups.
+////////////////////////////////////////////////////////////////////
+void EggToFlt::
+apply_egg_syntax(const string &egg_syntax, FltRecord *flt_record) {
+  if (!egg_syntax.empty()) {
+    ostringstream out;
+    out << "<egg> {\n" 
+        << egg_syntax
+        << "}";
+    flt_record->set_comment(out.str());
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggToFlt::get_flt_vertex
+//       Access: Private
+//  Description: Returns a FltVertex corresponding to the indicated
+//               EggVertex.  If the vertex has not been seen before
+//               (in this particular vertex frame), creates a new one.
+////////////////////////////////////////////////////////////////////
+FltVertex *EggToFlt::
+get_flt_vertex(EggVertex *egg_vertex, EggNode *context) {
+  const LMatrix4d *frame = context->get_vertex_to_node_ptr();
+  VertexMap &vertex_map = _vertex_map_per_frame[frame];
+
+  VertexMap::iterator vi = vertex_map.find(egg_vertex);
+  if (vi != vertex_map.end()) {
+    return (*vi).second;
+  }
+  FltVertex *flt_vertex = new FltVertex(_flt_header);
+  flt_vertex->_pos = egg_vertex->get_pos3();
+
+  if (egg_vertex->has_color()) {
+    flt_vertex->set_color(egg_vertex->get_color());
+  }
+  if (egg_vertex->has_normal()) {
+    flt_vertex->_normal = LCAST(float, egg_vertex->get_normal());
+    flt_vertex->_has_normal = true;
+  }
+  if (egg_vertex->has_uv()) {
+    flt_vertex->_uv = LCAST(float, egg_vertex->get_uv());
+    flt_vertex->_has_uv = true;
+  }
+
+  if (frame != (const LMatrix4d *)NULL) {
+    flt_vertex->_pos = flt_vertex->_pos * (*frame);
+    flt_vertex->_normal = flt_vertex->_normal * LCAST(float, (*frame));
+  }
+
+  _flt_header->add_vertex(flt_vertex);
+  vertex_map[egg_vertex] = flt_vertex;
+
+  return flt_vertex;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggToFlt::get_flt_texture
+//       Access: Private
+//  Description: Returns a FltTexture corresponding to the indicated
+//               EggTexture.  If the texture has not been seen before,
+//               creates a new one.
+////////////////////////////////////////////////////////////////////
+FltTexture *EggToFlt::
+get_flt_texture(EggTexture *egg_texture) {
+  // We have to maintain this map based on the filename, not the egg
+  // pointer, because there may be multiple EggTextures with the same
+  // filename, and we have to collapse them together.
+  Filename filename = egg_texture->get_filename();
+  TextureMap::iterator vi = _texture_map.find(filename);
+  if (vi != _texture_map.end()) {
+    return (*vi).second;
+  }
+  FltTexture *flt_texture = new FltTexture(_flt_header);
+  flt_texture->set_texture_filename(filename);
+
+  switch (egg_texture->get_minfilter()) {
+  case EggTexture::FT_nearest:
+    flt_texture->_min_filter = FltTexture::MN_point;
+    break;
+
+  case EggTexture::FT_linear:
+    flt_texture->_min_filter = FltTexture::MN_bilinear;
+    break;
+
+  case EggTexture::FT_nearest_mipmap_nearest:
+    flt_texture->_min_filter = FltTexture::MN_mipmap_point;
+    break;
+
+  case EggTexture::FT_nearest_mipmap_linear:
+    flt_texture->_min_filter = FltTexture::MN_mipmap_linear;
+    break;
+
+  case EggTexture::FT_linear_mipmap_nearest:
+    flt_texture->_min_filter = FltTexture::MN_mipmap_bilinear;
+    break;
+
+  case EggTexture::FT_linear_mipmap_linear:
+    flt_texture->_min_filter = FltTexture::MN_mipmap_trilinear;
+    break;
+
+  default:
+    break;
+  }
+
+  switch (egg_texture->get_magfilter()) {
+  case EggTexture::FT_nearest:
+    flt_texture->_mag_filter = FltTexture::MG_point;
+    break;
+
+  case EggTexture::FT_linear:
+    flt_texture->_mag_filter = FltTexture::MG_bilinear;
+    break;
+
+  default:
+    break;
+  }
+
+  switch (egg_texture->get_wrap_mode()) {
+  case EggTexture::WM_repeat:
+    flt_texture->_repeat = FltTexture::RT_repeat;
+    break;
+
+  case EggTexture::WM_clamp:
+    flt_texture->_repeat = FltTexture::RT_clamp;
+    break;
+
+  default:
+    break;
+  }
+
+  switch (egg_texture->get_wrap_u()) {
+  case EggTexture::WM_repeat:
+    flt_texture->_repeat_u = FltTexture::RT_repeat;
+    break;
+
+  case EggTexture::WM_clamp:
+    flt_texture->_repeat_u = FltTexture::RT_clamp;
+    break;
+
+  default:
+    break;
+  }
+
+  switch (egg_texture->get_wrap_v()) {
+  case EggTexture::WM_repeat:
+    flt_texture->_repeat_v = FltTexture::RT_repeat;
+    break;
+
+  case EggTexture::WM_clamp:
+    flt_texture->_repeat_v = FltTexture::RT_clamp;
+    break;
+
+  default:
+    break;
+  }
+
+  switch (egg_texture->get_env_type()) {
+  case EggTexture::ET_modulate:
+    flt_texture->_env_type = FltTexture::ET_modulate;
+    break;
+
+  case EggTexture::ET_decal:
+    flt_texture->_env_type = FltTexture::ET_decal;
+    break;
+
+  default:
+    break;
+  }
+
+  switch (egg_texture->get_format()) {
+  case EggTexture::F_luminance_alpha:
+  case EggTexture::F_luminance_alphamask:
+    flt_texture->_internal_format = FltTexture::IF_ia_8;
+    break;
+
+  case EggTexture::F_rgb5:
+  case EggTexture::F_rgb332:
+    flt_texture->_internal_format = FltTexture::IF_rgb_5;
+    break;
+
+  case EggTexture::F_rgba4:
+  case EggTexture::F_rgba5:
+    flt_texture->_internal_format = FltTexture::IF_rgba_4;
+    break;
+
+  case EggTexture::F_rgba8:
+  case EggTexture::F_rgba:
+  case EggTexture::F_rgbm:
+  case EggTexture::F_rgb:
+  case EggTexture::F_rgb8:
+    flt_texture->_internal_format = FltTexture::IF_rgba_8;
+    break;
+
+  case EggTexture::F_rgba12:
+    flt_texture->_internal_format = FltTexture::IF_rgba_12;
+    break;
+
+  case EggTexture::F_alpha:
+    flt_texture->_internal_format = FltTexture::IF_i_16;
+    flt_texture->_intensity_is_alpha = true;
+    break;
+
+  case EggTexture::F_luminance:
+    flt_texture->_internal_format = FltTexture::IF_i_16;
+    break;
+
+  case EggTexture::F_rgb12:
+    flt_texture->_internal_format = FltTexture::IF_rgb_12;
+    break;
+
+  default:
+    break;
+  }
+
+  _flt_header->add_texture(flt_texture);
+  _texture_map[filename] = flt_texture;
+
+  return flt_texture;
+}
+
+
+
+int main(int argc, char *argv[]) {
+  EggToFlt prog;
+  prog.parse_command_line(argc, argv);
+  prog.run();
+  return 0;
+}

+ 77 - 0
pandatool/src/fltprogs/eggToFlt.h

@@ -0,0 +1,77 @@
+// Filename: eggToFlt.h
+// Created by:  drose (01Oct03)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef EGGTOFLT_H
+#define EGGTOFLT_H
+
+#include "pandatoolbase.h"
+
+#include "eggToSomething.h"
+#include "fltHeader.h"
+#include "fltGeometry.h"
+#include "pointerTo.h"
+#include "pmap.h"
+#include "vector_string.h"
+
+class EggGroup;
+class EggVertex;
+class EggPrimitive;
+class EggTexture;
+class EggTransform3d;
+class FltVertex;
+class FltBead;
+class FltTexture;
+
+////////////////////////////////////////////////////////////////////
+//       Class : EggToFlt
+// Description : A program to read an egg file and write a flt file.
+////////////////////////////////////////////////////////////////////
+class EggToFlt : public EggToSomething {
+public:
+  EggToFlt();
+
+  void run();
+
+private:
+  static bool dispatch_attr(const string &opt, const string &arg, void *var);
+
+  void traverse(EggNode *egg_node, FltBead *flt_node,
+                FltGeometry::BillboardType billboard);
+  void convert_primitive(EggPrimitive *egg_primitive, FltBead *flt_node, 
+                         FltGeometry::BillboardType billboard);
+  void convert_group(EggGroup *egg_group, FltBead *flt_node,
+                     FltGeometry::BillboardType billboard);
+  void apply_transform(EggTransform3d *egg_transform, FltBead *flt_node);
+  void apply_egg_syntax(const string &egg_syntax, FltRecord *flt_record);
+  FltVertex *get_flt_vertex(EggVertex *egg_vertex, EggNode *context);
+  FltTexture *get_flt_texture(EggTexture *egg_texture);
+
+  FltHeader::AttrUpdate _auto_attr_update;
+
+  PT(FltHeader) _flt_header;
+  
+  typedef pmap<EggVertex *, FltVertex *> VertexMap;
+  typedef pmap<const LMatrix4d *, VertexMap> VertexMapPerFrame;
+  VertexMapPerFrame _vertex_map_per_frame;
+  
+  typedef pmap<Filename, FltTexture *> TextureMap;
+  TextureMap _texture_map;
+};
+
+#endif
+

+ 2 - 2
pandatool/src/fltprogs/fltToEgg.cxx

@@ -18,8 +18,8 @@
 
 #include "fltToEgg.h"
 
-#include <fltToEggConverter.h>
-#include <config_flt.h>
+#include "fltToEggConverter.h"
+#include "config_flt.h"
 
 ////////////////////////////////////////////////////////////////////
 //     Function: FltToEgg::Constructor

+ 5 - 5
pandatool/src/fltprogs/fltToEgg.h

@@ -15,16 +15,16 @@
 // [email protected] .
 //
 ////////////////////////////////////////////////////////////////////
-
+ 
 #ifndef FLTTOEGG_H
 #define FLTTOEGG_H
 
-#include <pandatoolbase.h>
+#include "pandatoolbase.h"
 
-#include <somethingToEgg.h>
-#include <fltToEggConverter.h>
+#include "somethingToEgg.h"
+#include "fltToEggConverter.h"
 
-#include <dSearchPath.h>
+#include "dSearchPath.h"
 
 ////////////////////////////////////////////////////////////////////
 //       Class : FltToEgg

+ 3 - 2
pandatool/src/progbase/Sources.pp

@@ -9,7 +9,8 @@
 
   #define SOURCES \
     programBase.I programBase.h \
-    withOutputFile.h wordWrapStream.h wordWrapStreamBuf.I \
+    withOutputFile.I withOutputFile.h \
+    wordWrapStream.h wordWrapStreamBuf.I \
     wordWrapStreamBuf.h
     
   #define INCLUDED_SOURCES \
@@ -18,7 +19,7 @@
 
   #define INSTALL_HEADERS \
     programBase.I programBase.h \
-    withOutputFile.h \
+    withOutputFile.I withOutputFile.h \
     wordWrapStream.h wordWrapStreamBuf.I \
     wordWrapStreamBuf.h
 

+ 29 - 0
pandatool/src/progbase/withOutputFile.I

@@ -0,0 +1,29 @@
+// Filename: withOutputFile.I
+// Created by:  drose (01Oct03)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: WithOutputFile::set_binary_output
+//       Access: Protected
+//  Description: Changes the flag specifying whether the output file
+//               is to be opened in binary mode or not.
+////////////////////////////////////////////////////////////////////
+INLINE void WithOutputFile::
+set_binary_output(bool binary_output) {
+  _binary_output = binary_output;
+}

+ 4 - 0
pandatool/src/progbase/withOutputFile.h

@@ -45,6 +45,8 @@ public:
   Filename get_output_filename() const;
 
 protected:
+  INLINE void set_binary_output(bool binary_output);
+
   bool check_last_arg(ProgramBase::Args &args, int minimum_args);
   bool verify_output_file_safe() const;
 
@@ -61,6 +63,8 @@ private:
   ostream *_output_ptr;
 };
 
+#include "withOutputFile.I"
+
 #endif