Browse Source

*** empty log message ***

David Rose 25 years ago
parent
commit
557ced9f66

+ 2 - 4
pandatool/src/eggbase/somethingToEgg.cxx

@@ -33,10 +33,8 @@ SomethingToEgg(const string &format_name,
 
   redescribe_option
     ("cs",
-     "Specify the coordinate system of the resulting egg file.  This may be "
-     "one of 'y-up', 'z-up', 'y-up-left', or 'z-up-left'.  The default "
-     "is the same coordinate system as the input " + _format_name +
-     " file, if this can be determined.");
+     "Specify the coordinate system of the input " + _format_name +
+     "file.  Normally, this can inferred from the file itself.");
 }
 
 ////////////////////////////////////////////////////////////////////

+ 25 - 1
pandatool/src/flt/fltBeadID.cxx

@@ -18,6 +18,28 @@ FltBeadID::
 FltBeadID(FltHeader *header) : FltBead(header) {
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: FltBeadID::get_id
+//       Access: Public
+//  Description: Returns the id (name) of this particular bead.  Each
+//               MultiGen bead will have a unique name.
+////////////////////////////////////////////////////////////////////
+const string &FltBeadID::
+get_id() const {
+  return _id;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltBeadID::set_id
+//       Access: Public
+//  Description: Changes the id (name) of this particular bead.  This
+//               should be a name that is unique to this bead.
+////////////////////////////////////////////////////////////////////
+void FltBeadID::
+set_id(const string &id) {
+  _id = id;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: FltBeadID::output
 //       Access: Public
@@ -64,7 +86,9 @@ extract_record(FltRecordReader &reader) {
 bool FltBeadID::
 extract_ancillary(FltRecordReader &reader) {
   if (reader.get_opcode() == FO_long_id) {
-    _id = reader.get_iterator().get_remaining_bytes();
+    string s = reader.get_iterator().get_remaining_bytes();
+    size_t zero_byte = s.find('\0');
+    _id = s.substr(0, zero_byte);
     return true;
   }
 

+ 1 - 1
pandatool/src/flt/fltVertex.I

@@ -12,5 +12,5 @@
 ////////////////////////////////////////////////////////////////////
 INLINE bool FltVertex::
 has_color() const {
-  return (_flags & F_no_color) == 0;
+  return (_flags & F_no_color) != 0;
 }

+ 16 - 0
pandatool/src/fltegg/Sources.pp

@@ -0,0 +1,16 @@
+#begin ss_lib_target
+  #define TARGET fltegg
+  #define LOCAL_LIBS pandatoolbase progbase flt
+  #define OTHER_LIBS \
+    egg:c pandaegg:m \
+    mathutil:c linmath:c putil:c express:c panda:m dtoolconfig dtool
+  #define UNIX_SYS_LIBS \
+    m
+
+  #define SOURCES \
+    fltToEggConverter.I fltToEggConverter.cxx fltToEggConverter.h
+
+  #define INSTALL_HEADERS \
+    fltToEggConverter.I fltToEggConverter.h
+
+#end ss_lib_target

+ 37 - 0
pandatool/src/fltegg/fltToEggConverter.I

@@ -0,0 +1,37 @@
+// Filename: fltToEggConverter.I
+// Created by:  drose (17Apr01)
+// 
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltToEggConverter::Destructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE FltToEggConverter::
+~FltToEggConverter() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltToEggConverter::set_input_units
+//       Access: Public
+//  Description: Sets the units the input flt file is considered to
+//               represent.  If this is unset or DU_invalid, the units
+//               are taken from the flt header.
+////////////////////////////////////////////////////////////////////
+INLINE void FltToEggConverter::
+set_input_units(DistanceUnit input_units) {
+  _input_units = input_units;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltToEggConverter::set_output_units
+//       Access: Public
+//  Description: Sets the units to generate in the resulting egg file.
+//               If this is unset, no units conversion is performed.
+////////////////////////////////////////////////////////////////////
+INLINE void FltToEggConverter::
+set_output_units(DistanceUnit output_units) {
+  _output_units = output_units;
+}

+ 423 - 0
pandatool/src/fltegg/fltToEggConverter.cxx

@@ -0,0 +1,423 @@
+// Filename: fltToEggConverter.cxx
+// Created by:  drose (17Apr01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#include "fltToEggConverter.h"
+
+#include <fltRecord.h>
+#include <fltLOD.h>
+#include <fltGroup.h>
+#include <fltObject.h>
+#include <fltBeadID.h>
+#include <fltBead.h>
+#include <fltFace.h>
+#include <fltVertex.h>
+#include <fltVertexList.h>
+#include <eggGroup.h>
+#include <eggSwitchCondition.h>
+#include <eggPrimitive.h>
+#include <eggPolygon.h>
+#include <eggPoint.h>
+#include <eggVertex.h>
+#include <eggVertexPool.h>
+#include <string_utils.h>
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltToEggConverter::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+FltToEggConverter::
+FltToEggConverter(EggData &egg_data) : _egg_data(egg_data) {
+  _input_units = DU_invalid;
+  _output_units = DU_invalid;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltToEggConverter::convert_flt
+//       Access: Public
+//  Description: Returns a newly-allocated EggData structure
+//               corresponding to the indicated flt structure.
+////////////////////////////////////////////////////////////////////
+void FltToEggConverter::
+convert_flt(const FltHeader *flt_header) {
+  _flt_header = flt_header;
+  
+  if (_input_units == DU_invalid) {
+    switch (_flt_header->_vertex_units) {
+    case FltHeader::U_meters:
+      _input_units = DU_meters;
+      break;
+
+    case FltHeader::U_kilometers:
+      _input_units = DU_kilometers;
+      break;
+
+    case FltHeader::U_feet:
+      _input_units = DU_feet;
+      break;
+
+    case FltHeader::U_inches:
+      _input_units = DU_inches;
+      break;
+
+    case FltHeader::U_nautical_miles:
+      _input_units = DU_nautical_miles;
+      break;
+    }
+  }
+
+  // Generate a default vertex pool.
+  _main_egg_vpool = new EggVertexPool("vpool");
+  _egg_data.add_child(_main_egg_vpool);
+
+  // We could populate the vertex pool right away, but it's better to
+  // defer each vertex until we encounter it, since some of the
+  // vertices may need to be adjusted to match the particular polygon
+  // they're assigned to (for instance, to apply a transparency or
+  // something).
+
+  convert_record(_flt_header, (FltObject *)NULL, &_egg_data);
+
+  if (_main_egg_vpool->empty()) {
+    // If we didn't get any global vertices, remove the vertex pool
+    // just for cleanliness.
+    _egg_data.remove_child(_main_egg_vpool);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltToEggConverter::convert_record
+//       Access: Private
+//  Description: Converts the record and all of its children.
+////////////////////////////////////////////////////////////////////
+void FltToEggConverter::
+convert_record(const FltRecord *flt_record, const FltObject *flt_object,
+	       EggGroupNode *egg_group) {
+  int num_children = flt_record->get_num_children();
+
+  for (int i = 0; i < num_children; i++) {
+    const FltRecord *child = flt_record->get_child(i);
+
+    if (child->is_of_type(FltLOD::get_class_type())) {
+      convert_lod(DCAST(FltLOD, child), flt_object, egg_group);
+
+    } else if (child->is_of_type(FltGroup::get_class_type())) {
+      convert_group(DCAST(FltGroup, child), flt_object, egg_group);
+
+    } else if (child->is_of_type(FltObject::get_class_type())) {
+      convert_object(DCAST(FltObject, child), flt_object, egg_group);
+
+    } else if (child->is_of_type(FltFace::get_class_type())) {
+      convert_face(DCAST(FltFace, child), flt_object, egg_group);
+
+      // Fallbacks.
+    } else if (child->is_of_type(FltBeadID::get_class_type())) {
+      convert_bead_id(DCAST(FltBeadID, child), flt_object, egg_group);
+
+    } else if (child->is_of_type(FltBead::get_class_type())) {
+      convert_bead(DCAST(FltBead, child), flt_object, egg_group);
+
+    } else {
+      convert_record(child, flt_object, egg_group);
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltToEggConverter::convert_lod
+//       Access: Private
+//  Description: Converts the LOD bead and all of its children.
+////////////////////////////////////////////////////////////////////
+void FltToEggConverter::
+convert_lod(const FltLOD *flt_lod, const FltObject *flt_object,
+	    EggGroupNode *egg_parent) {
+  EggGroup *egg_group = new EggGroup(flt_lod->get_id());
+  egg_parent->add_child(egg_group);
+
+  EggSwitchConditionDistance lod
+    (flt_lod->_switch_in, flt_lod->_switch_out,
+     LPoint3d(flt_lod->_center_x, flt_lod->_center_y, flt_lod->_center_z),
+     flt_lod->_transition_range);
+  egg_group->set_lod(lod);
+
+  convert_record(flt_lod, flt_object, egg_group);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltToEggConverter::convert_group
+//       Access: Private
+//  Description: Converts the group and all of its children.
+////////////////////////////////////////////////////////////////////
+void FltToEggConverter::
+convert_group(const FltGroup *flt_group, const FltObject *flt_object,
+	      EggGroupNode *egg_parent) {
+  EggGroup *egg_group = new EggGroup(flt_group->get_id());
+  egg_parent->add_child(egg_group);
+
+  if ((flt_group->_flags & FltGroup::F_forward_animation) != 0) {
+    // It's a sequence animation.
+    egg_group->set_switch_flag(true);
+    egg_group->set_switch_fps(24.0);
+  }
+
+  if (flt_group->has_transform()) {
+    egg_group->set_transform(flt_group->get_transform());
+  }
+
+  ///*** replicate count.
+
+  convert_record(flt_group, flt_object, egg_group);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltToEggConverter::convert_object
+//       Access: Private
+//  Description: Converts the object and all of its children.
+////////////////////////////////////////////////////////////////////
+void FltToEggConverter::
+convert_object(const FltObject *flt_object, const FltObject *,
+	       EggGroupNode *egg_parent) {
+  EggGroup *egg_group = new EggGroup(flt_object->get_id());
+  egg_parent->add_child(egg_group);
+
+  if (flt_object->has_transform()) {
+    egg_group->set_transform(flt_object->get_transform());
+  }
+
+  convert_record(flt_object, flt_object, egg_group);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltToEggConverter::convert_bead_id
+//       Access: Private
+//  Description: Converts the generic bead (with ID) and all of its
+//               children.
+////////////////////////////////////////////////////////////////////
+void FltToEggConverter::
+convert_bead_id(const FltBeadID *flt_bead, const FltObject *flt_object,
+		EggGroupNode *egg_parent) {
+  EggGroup *egg_group = new EggGroup(flt_bead->get_id());
+  egg_parent->add_child(egg_group);
+
+  if (flt_bead->has_transform()) {
+    egg_group->set_transform(flt_bead->get_transform());
+  }
+
+  convert_record(flt_bead, flt_object, egg_group);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltToEggConverter::convert_bead
+//       Access: Private
+//  Description: Converts the generic bead (without ID) and all of its
+//               children.
+////////////////////////////////////////////////////////////////////
+void FltToEggConverter::
+convert_bead(const FltBead *flt_bead, const FltObject *flt_object,
+	     EggGroupNode *egg_parent) {
+  EggGroup *egg_group = new EggGroup;
+  egg_parent->add_child(egg_group);
+
+  if (flt_bead->has_transform()) {
+    egg_group->set_transform(flt_bead->get_transform());
+  }
+
+  convert_record(flt_bead, flt_object, egg_group);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltToEggConverter::convert_face
+//       Access: Private
+//  Description: Converts the face and all of its children.
+////////////////////////////////////////////////////////////////////
+void FltToEggConverter::
+convert_face(const FltFace *flt_face, const FltObject *flt_object,
+	     EggGroupNode *egg_parent) {
+  bool is_light;
+  switch (flt_face->_draw_type) {
+  case FltGeometry::DT_omni_light:
+  case FltGeometry::DT_uni_light:
+  case FltGeometry::DT_bi_light:
+    is_light = true;
+    break;
+
+  default:
+    is_light = false;
+  }
+
+  EggPrimitive *egg_prim;
+  if (is_light) {
+    egg_prim = new EggPoint;
+  } else {
+    egg_prim = new EggPolygon;
+  }
+
+  egg_parent->add_child(egg_prim);
+
+  // Collect the vertices for this primitive.
+  vector< PT(EggVertex) > vertices;
+
+  const FltVertexList *vlist = (FltVertexList *)NULL;
+  int num_children = flt_face->get_num_children();
+  for (int i = 0; i < num_children && vlist == (FltVertexList *)NULL; i++) {
+    const FltRecord *child = flt_face->get_child(i);
+    if (child->is_of_type(FltVertexList::get_class_type())) {
+      vlist = DCAST(FltVertexList, child);
+    }
+  }
+
+  if (vlist != (FltVertexList *)NULL) {
+    int num_vertices = vlist->get_num_vertices();
+    for (int i = 0; i < num_vertices; i++) {
+      FltVertex *flt_vertex = vlist->get_vertex(i);
+      vertices.push_back(make_egg_vertex(flt_vertex));
+    }
+  }
+
+  setup_geometry(flt_face, flt_object, egg_prim, _main_egg_vpool, vertices);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltToEggConverter::setup_geometry
+//       Access: Private
+//  Description: Applies the state indicated in the FltGeometry record
+//               to the indicated EggPrimitive and all of its
+//               indicated vertices, and then officially adds the
+//               vertices to the vertex pool and to the primitive.
+////////////////////////////////////////////////////////////////////
+void FltToEggConverter::
+setup_geometry(const FltGeometry *flt_geom, const FltObject *,
+	       EggPrimitive *egg_prim, EggVertexPool *egg_vpool,
+	       const FltToEggConverter::EggVertices &vertices) {
+  EggVertices::const_iterator vi;
+
+  if (flt_geom->has_color()) {
+    egg_prim->set_color(flt_geom->get_color());
+  }
+
+  bool use_vertex_color = true;
+  bool keep_normals = true;
+  switch (flt_geom->_light_mode) {
+  case FltGeometry::LM_face_no_normal:
+    use_vertex_color = false;
+    keep_normals = false;
+    break;
+
+  case FltGeometry::LM_vertex_no_normal:
+    use_vertex_color = true;
+    keep_normals = false;
+    break;
+
+  case FltGeometry::LM_face_with_normal:
+    use_vertex_color = false;
+    keep_normals = true;
+    break;
+
+  case FltGeometry::LM_vertex_with_normal:
+    use_vertex_color = true;
+    keep_normals = true;
+    break;
+  }
+
+  if (flt_geom->has_texture()) {
+    // If the geometry has a texture, apply it.
+    egg_prim->set_texture(make_egg_texture(flt_geom->get_texture()));
+
+    if (flt_geom->_texwhite) {
+      // If the geometry should be colored white under the texture,
+      // then eliminate any explicit color; the egg loader will
+      // implicitly color it white.
+      egg_prim->clear_color();
+      use_vertex_color = false;
+    }
+  }
+
+  if (use_vertex_color) {
+    // If we're to use vertex color instead of the face color, remove
+    // the face color to eliminate any ambiguity.
+    if (flt_geom->has_color()) {
+      // Also, if some of our vertices don't have a color, set them to
+      // use the face color.
+      for (vi = vertices.begin(); vi != vertices.end(); ++vi) {
+	if (!(*vi)->has_color()) {
+	  (*vi)->set_color(flt_geom->get_color());
+	}
+      }
+      egg_prim->clear_color();
+    }
+
+  } else {
+    // If we're to use face color instead of vertex color, remove the
+    // vertex color to eliminate any ambiguity.
+    for (vi = vertices.begin(); vi != vertices.end(); ++vi) {
+      (*vi)->clear_color();
+    }
+  }    
+
+  if (!keep_normals) {
+    // If we're not to use the normals, then eliminate them.
+    for (vi = vertices.begin(); vi != vertices.end(); ++vi) {
+      (*vi)->clear_normal();
+    }
+  }
+
+  for (vi = vertices.begin(); vi != vertices.end(); ++vi) {
+    EggVertex *egg_vertex = egg_vpool->create_unique_vertex(*(*vi));
+    egg_prim->add_vertex(egg_vertex);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltToEggConverter::make_egg_vertex
+//       Access: Private
+//  Description: Makes a new EggVertex for the indicated FltVertex.
+//               The vertex is not automatically added to the vertex
+//               pool.
+////////////////////////////////////////////////////////////////////
+PT(EggVertex) FltToEggConverter::
+make_egg_vertex(const FltVertex *flt_vertex) {
+  PT(EggVertex) egg_vertex = new EggVertex;
+  egg_vertex->set_pos(flt_vertex->_pos);
+
+  if (flt_vertex->_has_normal) {
+    egg_vertex->set_normal(LCAST(double, flt_vertex->_normal));
+  }
+
+  if (flt_vertex->_has_uv) {
+    egg_vertex->set_uv(LCAST(double, flt_vertex->_uv));
+  }
+
+  if (flt_vertex->has_color()) {
+    egg_vertex->set_color(flt_vertex->get_color());
+  }
+
+  return egg_vertex;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltToEggConverter::make_egg_texture
+//       Access: Private
+//  Description: Makes a new EggTexture for the indicated FltTexture,
+//               or returns a pointer to one previously made for the
+//               same FltTexture.
+////////////////////////////////////////////////////////////////////
+PT(EggTexture) FltToEggConverter::
+make_egg_texture(const FltTexture *flt_texture) {
+  Textures::const_iterator ti;
+  ti = _textures.find(flt_texture);
+  if (ti != _textures.end()) {
+    // There's one previously created.
+    return (*ti).second;
+  }
+
+  // Create a new one.
+  string tref_name = format_string(flt_texture->_pattern_index);
+  Filename filename = flt_texture->get_texture_filename();
+  PT(EggTexture) egg_texture = new EggTexture(tref_name, filename);
+
+  _textures.insert(Textures::value_type(flt_texture, egg_texture));
+  return egg_texture;
+}

+ 92 - 0
pandatool/src/fltegg/fltToEggConverter.h

@@ -0,0 +1,92 @@
+// Filename: fltToEggConverter.h
+// Created by:  drose (17Apr01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#ifndef FLTTOEGGCONVERTER_H
+#define FLTTOEGGCONVERTER_H
+
+#include <pandatoolbase.h>
+
+#include <distanceUnit.h>
+
+#include <fltHeader.h>
+#include <eggData.h>
+#include <eggVertex.h>
+#include <eggTexture.h>
+#include <pointerTo.h>
+
+class FltRecord;
+class FltLOD;
+class FltGroup;
+class FltObject;
+class FltBeadID;
+class FltBead;
+class FltVertex;
+class FltGeometry;
+class FltFace;
+class FltTexture;
+class EggGroupNode;
+class EggPrimitive;
+class EggVertexPool;
+
+////////////////////////////////////////////////////////////////////
+// 	 Class : FltToEggConverter
+// Description : This class supervises the construction of an EggData
+//               structure from the data represented by the FltHeader.
+//               Reading and writing the egg and flt structures is
+//               left to the user.
+////////////////////////////////////////////////////////////////////
+class FltToEggConverter {
+public:
+  FltToEggConverter(EggData &egg_data);
+  INLINE ~FltToEggConverter();
+
+  INLINE void set_input_units(DistanceUnit input_units);
+  INLINE void set_output_units(DistanceUnit output_units);
+
+  void convert_flt(const FltHeader *flt_header);
+
+private:
+  typedef vector< PT(EggVertex) > EggVertices;
+
+  void convert_record(const FltRecord *flt_record, const FltObject *flt_object,
+		      EggGroupNode *egg_group);
+  void convert_lod(const FltLOD *flt_lod, const FltObject *flt_object,
+		   EggGroupNode *egg_parent);
+  void convert_group(const FltGroup *flt_group, const FltObject *flt_object,
+		     EggGroupNode *egg_parent);
+  void convert_object(const FltObject *flt_object, const FltObject *flt_object,
+		      EggGroupNode *egg_parent);
+  void convert_bead_id(const FltBeadID *flt_bead, const FltObject *flt_object,
+		       EggGroupNode *egg_parent);
+  void convert_bead(const FltBead *flt_bead, const FltObject *flt_object,
+		    EggGroupNode *egg_parent);
+  void convert_face(const FltFace *flt_face, const FltObject *flt_object,
+		    EggGroupNode *egg_parent);
+
+
+  void setup_geometry(const FltGeometry *flt_geom, const FltObject *flt_object,
+		      EggPrimitive *egg_prim, EggVertexPool *egg_vpool,
+		      const EggVertices &vertices);
+
+  PT(EggVertex) make_egg_vertex(const FltVertex *flt_vertex);
+  PT(EggTexture) make_egg_texture(const FltTexture *flt_texture);
+
+  DistanceUnit _input_units;
+  DistanceUnit _output_units;
+
+  EggData &_egg_data;
+  CPT(FltHeader) _flt_header;
+
+  EggVertexPool *_main_egg_vpool;
+
+  typedef map<const FltTexture *, PT(EggTexture) > Textures;
+  Textures _textures;
+};
+
+#include "fltToEggConverter.I"
+
+#endif
+
+

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

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

+ 15 - 14
pandatool/src/fltprogs/fltTrans.cxx

@@ -77,22 +77,23 @@ run() {
   if (result != FE_ok) {
     nout << "Unable to read: " << result << "\n";
     exit(1);
-  } else {
-    if (header->check_version()) {
-      nout << "Version is " << header->get_flt_version() << "\n";
-    }
-
-    if (_got_new_version) {
-      header->set_flt_version(_new_version);
-    }
+  }
 
-    result = header->write_flt(get_output());
-    if (result != FE_ok) {
-      nout << "Unable to write: " << result << "\n";
-    } else {
-      nout << "Successfully written.\n";
-    }
+  if (header->check_version()) {
+    nout << "Version is " << header->get_flt_version() << "\n";
   }
+  
+  if (_got_new_version) {
+    header->set_flt_version(_new_version);
+  }
+  
+  result = header->write_flt(get_output());
+  if (result != FE_ok) {
+    nout << "Unable to write: " << result << "\n";
+    exit(1);
+  }
+  
+  nout << "Successfully written.\n";
 }
 
 

+ 8 - 12
pandatool/src/maya/mayaToEgg.cxx

@@ -70,22 +70,18 @@ run() {
     exit(1);
   }
 
-  // First, we build the egg file in the same coordinate system as
-  // Maya.
-  if (MGlobal::isYAxisUp()) {
-    _data.set_coordinate_system(CS_yup_right);
-  } else {
-    _data.set_coordinate_system(CS_zup_right);
+  if (!_got_coordinate_system) {
+    // Choose a suitable coordinate system matching Maya.
+    if (MGlobal::isYAxisUp()) {
+      _coordinate_system = CS_yup_right;
+    } else {
+      _coordinate_system = CS_zup_right;
+    }
   }
+  _data.set_coordinate_system(_coordinate_system);
 
   _maya.make_egg(_data);
 
-  // Then, if the user so requested, we convert the egg file to the
-  // desired output coordinate system.
-  if (_got_coordinate_system) {
-    _data.set_coordinate_system(_coordinate_system);
-  }
-
   write_egg_file();
 }
 

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

@@ -6,6 +6,7 @@
     linmath:c putil:c express:c panda:m pystub dtool
 
   #define SOURCES \
+    distanceUnit.cxx distanceUnit.h \
     programBase.I programBase.cxx programBase.h \
     withOutputFile.cxx withOutputFile.h \
     wordWrapStream.cxx \
@@ -13,6 +14,7 @@
     wordWrapStreamBuf.h
 
   #define INSTALL_HEADERS \
+    distanceUnit.h \
     programBase.I programBase.h \
     withOutputFile.h \
     wordWrapStream.h wordWrapStreamBuf.I \

+ 144 - 0
pandatool/src/progbase/distanceUnit.cxx

@@ -0,0 +1,144 @@
+// Filename: distanceUnit.cxx
+// Created by:  drose (17Apr01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#include "distanceUnit.h"
+
+#include <string_utils.h>
+
+////////////////////////////////////////////////////////////////////
+//     Function: DistanceUnit output operator
+//  Description: 
+////////////////////////////////////////////////////////////////////
+ostream &
+operator << (ostream &out, DistanceUnit unit) {
+  switch (unit) {
+  case DU_millimeters:
+    return out << "mm";
+
+  case DU_centimeters:
+    return out << "cm";
+
+  case DU_meters:
+    return out << "m";
+
+  case DU_kilometers:
+    return out << "km";
+
+  case DU_yards:
+    return out << "yd";
+
+  case DU_feet:
+    return out << "ft";
+
+  case DU_inches:
+    return out << "in";
+
+  case DU_nautical_miles:
+    return out << "nmi";
+
+  case DU_statute_miles:
+    return out << "mi";
+
+  case DU_invalid:
+    return out << "invalid";
+  }
+  return out << "**unexpected DistanceUnit value: (" << (int)unit << ")**";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: string_distance_unit
+//  Description: Converts from a string, as might be input by the
+//               user, to one of the known DistanceUnit types.
+//               Returns DU_invalid if the string is unknown.
+////////////////////////////////////////////////////////////////////
+DistanceUnit
+string_distance_unit(const string &str) {
+  if (cmp_nocase(str, "mm") == 0 || cmp_nocase(str, "millimeters") == 0) {
+    return DU_millimeters;
+
+  } else if (cmp_nocase(str, "cm") == 0 || cmp_nocase(str, "centimeters") == 0) {
+    return DU_centimeters;
+
+  } else if (cmp_nocase(str, "m") == 0 || cmp_nocase(str, "meters") == 0) {
+    return DU_meters;
+
+  } else if (cmp_nocase(str, "km") == 0 || cmp_nocase(str, "kilometers") == 0) {
+    return DU_kilometers;
+  
+  } else if (cmp_nocase(str, "yd") == 0 || cmp_nocase(str, "yards") == 0) {
+    return DU_yards;
+  
+  } else if (cmp_nocase(str, "ft") == 0 || cmp_nocase(str, "feet") == 0) {
+    return DU_feet;
+  
+  } else if (cmp_nocase(str, "in") == 0 || cmp_nocase(str, "inches") == 0) {
+    return DU_inches;
+  
+  } else if (cmp_nocase(str, "nmi") == 0 || 
+	     cmp_nocase(str, "nm") == 0 || 
+	     cmp_nocase_uh(str, "nautical_miles") == 0) {
+    return DU_nautical_miles;
+  
+  } else if (cmp_nocase(str, "mi") == 0 || 
+	     cmp_nocase(str, "miles") == 0 ||
+	     cmp_nocase_uh(str, "statute_miles") == 0) {
+    return DU_statute_miles;
+
+  } else {
+    return DU_invalid;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: unit_scale
+//  Description: Returns the number of the indicated unit per each
+//               centimeter.  This internal function is used to
+//               implement convert_units(), below.
+////////////////////////////////////////////////////////////////////
+static double unit_scale(DistanceUnit unit) {
+  switch (unit) {
+  case DU_millimeters:
+    return 0.1;
+
+  case DU_centimeters:
+    return 1.0;
+
+  case DU_meters:
+    return 100.0;
+
+  case DU_kilometers:
+    return 100000.0;
+
+  case DU_yards:
+    return 3.0 * 12.0 * 2.54;
+
+  case DU_feet:
+    return 12.0 * 2.54;
+
+  case DU_inches:
+    return 2.54;
+
+  case DU_nautical_miles:
+    // This is the U.S. definition.
+    return 185200.0;
+
+  case DU_statute_miles:
+    return 5280.0 * 12.0 * 2.54;
+
+  case DU_invalid:
+    return 1.0;
+  }
+
+  return 1.0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: convert_units
+//  Description: Returns the scaling factor that must be applied to
+//               convert from units of "from" to "to".
+////////////////////////////////////////////////////////////////////
+double convert_units(DistanceUnit from, DistanceUnit to) {
+  return unit_scale(to) / unit_scale(from);
+}

+ 35 - 0
pandatool/src/progbase/distanceUnit.h

@@ -0,0 +1,35 @@
+// Filename: distanceUnit.h
+// Created by:  drose (17Apr01)
+// 
+////////////////////////////////////////////////////////////////////
+
+#ifndef DISTANCEUNIT_H
+#define DISTANCEUNIT_H
+
+#include <pandatoolbase.h>
+
+////////////////////////////////////////////////////////////////////
+// 	  Enum : DistanceUnit
+// Description : This enumerated type lists all the kinds of units
+//               we're likely to come across in model conversion
+//               programs.
+////////////////////////////////////////////////////////////////////
+enum DistanceUnit {
+  DU_millimeters,
+  DU_centimeters,
+  DU_meters,
+  DU_kilometers,
+  DU_yards,
+  DU_feet,
+  DU_inches,
+  DU_nautical_miles,
+  DU_statute_miles,
+  DU_invalid
+};
+
+ostream &operator << (ostream &out, DistanceUnit unit);
+DistanceUnit string_distance_unit(const string &str);
+
+double convert_units(DistanceUnit from, DistanceUnit to);
+
+#endif

+ 22 - 0
pandatool/src/progbase/programBase.cxx

@@ -904,6 +904,28 @@ dispatch_coordinate_system(const string &opt, const string &arg, void *var) {
   return true;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: ProgramBase::dispatch_units
+//       Access: Protected, Static
+//  Description: Standard dispatch function for an option that takes
+//               one parameter, which is to be interpreted as a
+//               unit of distance measurement.  The data pointer is to
+//               a DistanceUnit variable.
+////////////////////////////////////////////////////////////////////
+bool ProgramBase::
+dispatch_units(const string &opt, const string &arg, void *var) {
+  DistanceUnit *ip = (DistanceUnit *)var;
+  (*ip) = string_distance_unit(arg);
+
+  if ((*ip) == DU_invalid) {
+    nout << "Invalid units for -" << opt << ": " << arg << "\n"
+	 << "Valid units are mm, cm, m, km, yd, ft, in, nmi, and mi.\n";
+    return false;
+  }
+
+  return true;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: ProgramBase::handle_help_option
 //       Access: Protected, Static

+ 3 - 0
pandatool/src/progbase/programBase.h

@@ -8,6 +8,8 @@
 
 #include <pandatoolbase.h>
 
+#include "distanceUnit.h"
+
 #include <filename.h>
 #include <vector_string.h>
 
@@ -80,6 +82,7 @@ protected:
   static bool dispatch_filename(const string &opt, const string &arg, void *var);
   static bool dispatch_search_path(const string &opt, const string &arg, void *var);
   static bool dispatch_coordinate_system(const string &opt, const string &arg, void *var);
+  static bool dispatch_units(const string &opt, const string &arg, void *var);
 
   static bool handle_help_option(const string &opt, const string &arg, void *);