Browse Source

*** empty log message ***

David Rose 24 years ago
parent
commit
228231fa09

+ 1 - 1
pandatool/src/eggbase/eggFilter.cxx

@@ -55,7 +55,7 @@ EggFilter(bool allow_last_param, bool allow_stdout) :
 ////////////////////////////////////////////////////////////////////
 bool EggFilter::
 handle_args(ProgramBase::Args &args) {
-  if (!check_last_arg(args, 0)) {
+  if (!check_last_arg(args, 1)) {
     return false;
   }
 

+ 5 - 4
pandatool/src/eggbase/eggReader.cxx

@@ -54,6 +54,11 @@ EggReader() {
 //               program.  If the user specifies one of the options on
 //               the command line, the textures will be copied and
 //               converted as each egg file is read.
+//
+//               Note that if you call this function to add these
+//               options, you must call copy_textures() at the
+//               appropriate point before or during processing to
+//               execute the options if the user specified them.
 ////////////////////////////////////////////////////////////////////
 void EggReader::
 add_texture_options() {
@@ -153,10 +158,6 @@ handle_args(ProgramBase::Args &args) {
 ////////////////////////////////////////////////////////////////////
 bool EggReader::
 post_command_line() {
-  if (!copy_textures()) {
-    exit(1);
-  }
-
   return EggBase::post_command_line();
 }
 

+ 3 - 1
pandatool/src/eggbase/eggReader.h

@@ -43,10 +43,12 @@ protected:
   virtual bool handle_args(Args &args);
   virtual bool post_command_line();
 
-private:
   bool copy_textures();
 
+protected:
   bool _force_complete;
+
+private:
   Filename _tex_dirname;
   bool _got_tex_dirname;
   string _tex_extension;

+ 4 - 0
pandatool/src/eggprogs/eggTrans.cxx

@@ -112,6 +112,10 @@ run() {
     uniquifier.uniquify(&_data);
   }
 
+  if (!copy_textures()) {
+    exit(1);
+  }
+
   write_egg_file();
 }
 

+ 2 - 0
pandatool/src/ptloader/config_ptloader.cxx

@@ -25,6 +25,7 @@
 #include "lwoToEggConverter.h"
 
 #ifdef HAVE_DX
+#include "config_xfile.h"
 #include "xFileToEggConverter.h"
 #endif
 
@@ -67,6 +68,7 @@ init_libptloader() {
   reg->register_type(new LoaderFileTypePandatool(lwo));
 
 #ifdef HAVE_DX
+  init_libxfile();
   XFileToEggConverter *xfile = new XFileToEggConverter;
   reg->register_type(new LoaderFileTypePandatool(xfile));
 #endif

+ 1 - 0
pandatool/src/xfile/Sources.pp

@@ -14,6 +14,7 @@
     d3dxof.lib
 
   #define SOURCES \
+    config_xfile.cxx config_xfile.h \
     xFileFace.cxx xFileFace.h \
     xFileMaker.cxx xFileMaker.h \
     xFileMaterial.cxx xFileMaterial.h \

+ 52 - 0
pandatool/src/xfile/config_xfile.cxx

@@ -0,0 +1,52 @@
+// Filename: config_xfile.cxx
+// Created by:  drose (24Aug00)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "config_xfile.h"
+
+#include <dconfig.h>
+
+Configure(config_xfile);
+NotifyCategoryDef(xfile, "");
+
+// This is set true, typically by the user's command-line options, to
+// indicate that when a X file is generated it should include all
+// geometry in one big mesh, instead of preserving the hierarchy
+// from the source egg file.
+bool xfile_one_mesh = false;
+
+ConfigureFn(config_xfile) {
+  init_libxfile();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: init_libxfile
+//  Description: Initializes the library.  This must be called at
+//               least once before any of the functions or classes in
+//               this library can be used.  Normally it will be
+//               called by the static initializers and need not be
+//               called explicitly, but special cases exist.
+////////////////////////////////////////////////////////////////////
+void
+init_libxfile() {
+  static bool initialized = false;
+  if (initialized) {
+    return;
+  }
+  initialized = true;
+}
+

+ 32 - 0
pandatool/src/xfile/config_xfile.h

@@ -0,0 +1,32 @@
+// Filename: config_xfile.h
+// Created by:  drose (22Jun01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 CONFIG_XFILE_H
+#define CONFIG_XFILE_H
+
+#include "pandatoolbase.h"
+
+#include "notifyCategoryProxy.h"
+
+NotifyCategoryDeclNoExport(xfile);
+
+extern bool xfile_one_mesh;
+
+extern void init_libxfile();
+
+#endif

+ 240 - 127
pandatool/src/xfile/xFileMaker.cxx

@@ -20,6 +20,7 @@
 #include "xFileMesh.h"
 #include "xFileMaterial.h"
 #include "xFileTemplates.h"
+#include "config_xfile.h"
 
 #include "notify.h"
 #include "eggGroupNode.h"
@@ -99,12 +100,14 @@ open(const Filename &filename) {
     &TID_D3DRMColorRGB,
     &TID_D3DRMIndexedColor,
     &TID_D3DRMTextureFilename,
+    &TID_D3DRMMatrix4x4,
     &TID_D3DRMMaterial,
     &TID_D3DRMMeshFace,
     &TID_D3DRMMesh,
     &TID_D3DRMMeshNormals,
     &TID_D3DRMMeshTextureCoords,
     &TID_D3DRMMeshMaterialList,
+    &TID_D3DRMFrameTransformMatrix,
     &TID_D3DRMFrame,
   };
   static const int num_temps = sizeof(temps) / sizeof(temps[0]);
@@ -145,12 +148,24 @@ close() {
 ////////////////////////////////////////////////////////////////////
 bool XFileMaker::
 add_tree(EggData &egg_data) {
+  _meshes.clear();
+
   // Now collect all the polygons together into polysets.
   EggPolysetMaker pmaker;
   int num_bins = pmaker.make_bins(&egg_data);
 
   // And now we're ready to traverse the egg hierarchy.
-  return recurse_nodes(&egg_data, NULL);
+  if (!recurse_nodes(&egg_data, NULL)) {
+    return false;
+  }
+
+  // Make sure we finalize any meshes in the root.
+  if (!finalize_mesh(NULL)) {
+    return false;
+  }
+
+  nassertr(_meshes.empty(), false);
+  return true;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -171,17 +186,28 @@ add_node(EggNode *egg_node, LPDIRECTXFILEDATA dx_parent) {
     // A grouping node of some kind.
     EggGroupNode *egg_group = DCAST(EggGroupNode, egg_node);
     LPDIRECTXFILEDATA obj;
-    if (!create_frame(obj, egg_group->get_name())) {
-      return false;
-    }
-    
-    if (!recurse_nodes(egg_group, obj)) {
-      obj->Release();
-      return false;
-    }
+
+    if (xfile_one_mesh) {
+      // Don't create any additional frames representing the egg
+      // hierarchy.
+      if (!recurse_nodes(egg_group, dx_parent)) {
+        return false;
+      }
+
+    } else {
+      // Create a frame for each EggGroup.
+      if (!create_frame(obj, egg_group->get_name())) {
+        return false;
+      }
     
-    if (!attach_and_release(obj, dx_parent)) {
-      return false;
+      if (!recurse_nodes(egg_group, obj)) {
+        obj->Release();
+        return false;
+      }
+      
+      if (!attach_and_release(obj, dx_parent)) {
+        return false;
+      }
     }
     
     return true;
@@ -198,18 +224,33 @@ add_node(EggNode *egg_node, LPDIRECTXFILEDATA dx_parent) {
 ////////////////////////////////////////////////////////////////////
 bool XFileMaker::
 add_group(EggGroup *egg_group, LPDIRECTXFILEDATA dx_parent) {
-  LPDIRECTXFILEDATA obj;
-  if (!create_frame(obj, egg_group->get_name())) {
-    return false;
-  }
+  if (xfile_one_mesh) {
+    // Don't create any additional frames representing the egg
+    // hierarchy.
+    if (!recurse_nodes(egg_group, dx_parent)) {
+      return false;
+    }
 
-  if (!recurse_nodes(egg_group, obj)) {
-    obj->Release();
-    return false;
-  }
+  } else {
+    // Create a frame for each EggGroup.
+    LPDIRECTXFILEDATA obj;
+    if (!create_frame(obj, egg_group->get_name())) {
+      return false;
+    }
 
-  if (!attach_and_release(obj, dx_parent)) {
-    return false;
+    // Set the transform on the frame, if we have one.
+    if (egg_group->has_transform()) {
+      add_frame_transform(obj, LCAST(float, egg_group->get_transform()));
+    }
+    
+    if (!recurse_nodes(egg_group, obj)) {
+      obj->Release();
+      return false;
+    }
+    
+    if (!attach_and_release(obj, dx_parent)) {
+      return false;
+    }
   }
 
   return true;
@@ -228,7 +269,8 @@ add_bin(EggBin *egg_bin, LPDIRECTXFILEDATA dx_parent) {
     return add_polyset(egg_bin, dx_parent);
   }
 
-  cerr << "Unexpected bin type " << egg_bin->get_bin_number() << "\n";
+  xfile_cat.error()
+    << "Unexpected bin type " << egg_bin->get_bin_number() << "\n";
   return false;
 }
 
@@ -243,121 +285,19 @@ add_polyset(EggBin *egg_bin, LPDIRECTXFILEDATA dx_parent) {
   // Make sure that all our polygons are reasonable.
   egg_bin->remove_invalid_primitives();
 
-  XFileMesh mesh;
+  XFileMesh *mesh = get_mesh(dx_parent);
 
   EggGroupNode::iterator ci;
   for (ci = egg_bin->begin(); ci != egg_bin->end(); ++ci) {
     EggPolygon *poly;
     DCAST_INTO_R(poly, *ci, false);
 
-    mesh.add_polygon(poly);
-  }
-
-  // Get a unique number for each mesh.
-  _mesh_index++;
-  string mesh_index = format_string(_mesh_index);
-
-  // Finally, create the Mesh object.
-  Datagram raw_data;
-  mesh.make_mesh_data(raw_data);
-
-  LPDIRECTXFILEDATA xobj;
-  if (!create_object(xobj, TID_D3DRMMesh, "mesh" + mesh_index, raw_data)) {
-    return false;
-  }
-
-  if (mesh.has_normals()) {
-    // Tack on normals.
-    LPDIRECTXFILEDATA xnormals;
-    mesh.make_normal_data(raw_data);
-    if (!create_object(xnormals, TID_D3DRMMeshNormals, "norms" + mesh_index,
-                       raw_data)) {
-      return false;
-    }
-    if (!attach_and_release(xnormals, xobj)) {
-      return false;
-    }
-  }
-
-  if (mesh.has_colors()) {
-    // Tack on colors.
-    LPDIRECTXFILEDATA xcolors;
-    mesh.make_color_data(raw_data);
-    if (!create_object(xcolors, TID_D3DRMMeshVertexColors, 
-                       "colors" + mesh_index, raw_data)) {
-      return false;
-    }
-    if (!attach_and_release(xcolors, xobj)) {
-      return false;
-    }
-  }
-
-  if (mesh.has_uvs()) {
-    // Tack on texture coordinates.
-    LPDIRECTXFILEDATA xuvs;
-    mesh.make_uv_data(raw_data);
-    if (!create_object(xuvs, TID_D3DRMMeshTextureCoords, 
-                       "uvs" + mesh_index, raw_data)) {
-      return false;
-    }
-    if (!attach_and_release(xuvs, xobj)) {
-      return false;
-    }
-  }
-
-  if (mesh.has_materials()) {
-    // Tack on material definitions.
-    LPDIRECTXFILEDATA xmaterial_list;
-    mesh.make_material_list_data(raw_data);
-    if (!create_object(xmaterial_list, TID_D3DRMMeshMaterialList, 
-                       "materials" + mesh_index, raw_data)) {
-      return false;
-    }
-
-    // Now we need to iterate through the list of Materials
-    // themselves, and add *these* as children of the material list.
-    int num_materials = mesh.get_num_materials();
-    for (int i = 0; i < num_materials; i++) {
-      XFileMaterial *material = mesh.get_material(i);
-      LPDIRECTXFILEDATA xmaterial;
-      material->make_material_data(raw_data);
-      if (!create_object(xmaterial, TID_D3DRMMaterial, 
-                         "material" + mesh_index + "_" + format_string(i),
-                         raw_data)) {
-        return false;
-      }
-
-      // Also, if the Material has a texture map, we must add *this*
-      // as a child of the material.  What a weird system.
-      if (material->has_texture()) {
-        LPDIRECTXFILEDATA xtexture;
-        material->make_texture_data(raw_data);
-        if (!create_object(xtexture, TID_D3DRMTextureFilename, 
-                           "texture" + mesh_index + "_" + format_string(i),
-                           raw_data)) {
-          return false;
-        }
-
-        if (!attach_and_release(xtexture, xmaterial)) {
-          return false;
-        }
-      }
-
-      if (!attach_and_release(xmaterial, xmaterial_list)) {
-        return false;
-      }
-    }
-
-    if (!attach_and_release(xmaterial_list, xobj)) {
-      return false;
-    }
+    mesh->add_polygon(poly);
   }
 
-  if (!attach_and_release(xobj, dx_parent)) {
-    return false;
-  }
   return true;
 }
+
   
 ////////////////////////////////////////////////////////////////////
 //     Function: XFileMaker::recurse_nodes
@@ -418,6 +358,28 @@ create_frame(LPDIRECTXFILEDATA &obj, const string &name) {
   return create_object(obj, TID_D3DRMFrame, name, Datagram());
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: XFileMaker::add_frame_transform
+//       Access: Private
+//  Description: Adds a transformation matrix to the indicated frame.
+////////////////////////////////////////////////////////////////////
+bool XFileMaker::
+add_frame_transform(LPDIRECTXFILEDATA obj, const LMatrix4f &mat) {
+  Datagram raw_data;
+  mat.write_datagram(raw_data);
+
+  LPDIRECTXFILEDATA xtransform;
+  if (!create_object(xtransform, TID_D3DRMFrameTransformMatrix, 
+                     "transform", raw_data)) {
+    return false;
+  }
+  if (!attach_and_release(xtransform, obj)) {
+    return false;
+  }
+
+  return true;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: XFileMaker::attach_and_release
 //       Access: Private
@@ -428,6 +390,12 @@ bool XFileMaker::
 attach_and_release(LPDIRECTXFILEDATA obj, LPDIRECTXFILEDATA dx_parent) {
   HRESULT hr;
 
+  // First, make sure we don't have an outstanding mesh for this
+  // object.
+  if (!finalize_mesh(obj)) {
+    return false;
+  }
+
   if (dx_parent == NULL) {
     // No parent; it's a toplevel object.
     hr = _dx_file_save->SaveData(obj);
@@ -471,3 +439,148 @@ make_nice_name(const string &str) {
 
   return result;
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileMaker::get_mesh
+//       Access: Private
+//  Description: Returns a suitable XFileMesh object for creating
+//               meshes within the indicated dx_parent object.
+////////////////////////////////////////////////////////////////////
+XFileMesh *XFileMaker::
+get_mesh(LPDIRECTXFILEDATA dx_parent) {
+  Meshes::iterator mi = _meshes.find(dx_parent);
+  if (mi != _meshes.end()) {
+    // We've already started working on this dx_parent before; use the
+    // same mesh object.
+    return (*mi).second;
+  }
+
+  // We haven't seen this dx_parent before; create a new mesh object.
+  XFileMesh *mesh = new XFileMesh;
+  _meshes.insert(Meshes::value_type(dx_parent, mesh));
+  return mesh;
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileMaker::finalize_mesh
+//       Access: Private
+//  Description: Creates the actual DX mesh object corresponding to
+//               the indicated dx_parent object.
+////////////////////////////////////////////////////////////////////
+bool XFileMaker::
+finalize_mesh(LPDIRECTXFILEDATA dx_parent) {
+  Meshes::iterator mi = _meshes.find(dx_parent);
+  if (mi == _meshes.end()) {
+    // We haven't got a mesh for this object; do nothing.
+    return true;
+  }
+
+  XFileMesh *mesh = (*mi).second;
+  _meshes.erase(mi);
+
+  // Get a unique number for each mesh.
+  _mesh_index++;
+  string mesh_index = format_string(_mesh_index);
+
+  // Finally, create the Mesh object.
+  Datagram raw_data;
+  mesh->make_mesh_data(raw_data);
+
+  LPDIRECTXFILEDATA xobj;
+  if (!create_object(xobj, TID_D3DRMMesh, "mesh" + mesh_index, raw_data)) {
+    return false;
+  }
+
+  if (mesh->has_normals()) {
+    // Tack on normals.
+    LPDIRECTXFILEDATA xnormals;
+    mesh->make_normal_data(raw_data);
+    if (!create_object(xnormals, TID_D3DRMMeshNormals, "norms" + mesh_index,
+                       raw_data)) {
+      return false;
+    }
+    if (!attach_and_release(xnormals, xobj)) {
+      return false;
+    }
+  }
+
+  if (mesh->has_colors()) {
+    // Tack on colors.
+    LPDIRECTXFILEDATA xcolors;
+    mesh->make_color_data(raw_data);
+    if (!create_object(xcolors, TID_D3DRMMeshVertexColors, 
+                       "colors" + mesh_index, raw_data)) {
+      return false;
+    }
+    if (!attach_and_release(xcolors, xobj)) {
+      return false;
+    }
+  }
+
+  if (mesh->has_uvs()) {
+    // Tack on texture coordinates.
+    LPDIRECTXFILEDATA xuvs;
+    mesh->make_uv_data(raw_data);
+    if (!create_object(xuvs, TID_D3DRMMeshTextureCoords, 
+                       "uvs" + mesh_index, raw_data)) {
+      return false;
+    }
+    if (!attach_and_release(xuvs, xobj)) {
+      return false;
+    }
+  }
+
+  if (mesh->has_materials()) {
+    // Tack on material definitions.
+    LPDIRECTXFILEDATA xmaterial_list;
+    mesh->make_material_list_data(raw_data);
+    if (!create_object(xmaterial_list, TID_D3DRMMeshMaterialList, 
+                       "materials" + mesh_index, raw_data)) {
+      return false;
+    }
+
+    // Now we need to iterate through the list of Materials
+    // themselves, and add *these* as children of the material list.
+    int num_materials = mesh->get_num_materials();
+    for (int i = 0; i < num_materials; i++) {
+      XFileMaterial *material = mesh->get_material(i);
+      LPDIRECTXFILEDATA xmaterial;
+      material->make_material_data(raw_data);
+      if (!create_object(xmaterial, TID_D3DRMMaterial, 
+                         "material" + mesh_index + "_" + format_string(i),
+                         raw_data)) {
+        return false;
+      }
+
+      // Also, if the Material has a texture map, we must add *this*
+      // as a child of the material.  What a weird system.
+      if (material->has_texture()) {
+        LPDIRECTXFILEDATA xtexture;
+        material->make_texture_data(raw_data);
+        if (!create_object(xtexture, TID_D3DRMTextureFilename, 
+                           "texture" + mesh_index + "_" + format_string(i),
+                           raw_data)) {
+          return false;
+        }
+
+        if (!attach_and_release(xtexture, xmaterial)) {
+          return false;
+        }
+      }
+
+      if (!attach_and_release(xmaterial, xmaterial_list)) {
+        return false;
+      }
+    }
+
+    if (!attach_and_release(xmaterial_list, xobj)) {
+      return false;
+    }
+  }
+
+  if (!attach_and_release(xobj, dx_parent)) {
+    return false;
+  }
+  return true;
+}

+ 13 - 2
pandatool/src/xfile/xFileMaker.h

@@ -19,9 +19,11 @@
 #ifndef XFILEMAKER_H
 #define XFILEMAKER_H
 
-#include <pandatoolbase.h>
+#include "pandatoolbase.h"
 
-#include <filename.h>
+#include "filename.h"
+#include "pmap.h"
+#include "luse.h"
 
 #define WIN32_LEAN_AND_MEAN
 #include <windows.h>
@@ -37,6 +39,7 @@ class EggBin;
 class EggData;
 class EggVertexPool;
 class Datagram;
+class XFileMesh;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : XFileMaker
@@ -64,14 +67,22 @@ private:
   bool create_object(LPDIRECTXFILEDATA &obj, REFGUID template_id,
                      const string &name, const Datagram &dg);
   bool create_frame(LPDIRECTXFILEDATA &obj, const string &name);
+  bool add_frame_transform(LPDIRECTXFILEDATA obj, const LMatrix4f &mat);
+
   bool attach_and_release(LPDIRECTXFILEDATA obj, LPDIRECTXFILEDATA dx_parent);
 
   static string make_nice_name(const string &str);
 
+  XFileMesh *get_mesh(LPDIRECTXFILEDATA dx_parent);
+  bool finalize_mesh(LPDIRECTXFILEDATA dx_parent);
+
   LPDIRECTXFILE _dx_file;
   LPDIRECTXFILESAVEOBJECT _dx_file_save;
 
   int _mesh_index;
+
+  typedef pmap<LPDIRECTXFILEDATA, XFileMesh *> Meshes;
+  Meshes _meshes;
 };
 
 #endif

+ 5 - 0
pandatool/src/xfile/xFileMesh.cxx

@@ -86,6 +86,11 @@ clear() {
   _unique_vertices.clear();
   _unique_normals.clear();
   _unique_materials.clear();
+
+  _has_normals = false;
+  _has_colors = false;
+  _has_uvs = false;
+  _has_materials = false;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 0 - 1
pandatool/src/xfile/xFileMesh.h

@@ -91,7 +91,6 @@ private:
   Materials _materials;
   Faces _faces;
 
-private:
   typedef pmap<XFileVertex *, int, IndirectCompareTo<XFileVertex> > UniqueVertices;
   typedef pmap<XFileNormal *, int, IndirectCompareTo<XFileNormal> > UniqueNormals;
   typedef pmap<XFileMaterial *, int, IndirectCompareTo<XFileMaterial> > UniqueMaterials;

+ 19 - 5
pandatool/src/xfile/xFileNormal.cxx

@@ -19,6 +19,7 @@
 #include "xFileNormal.h"
 #include "eggVertex.h"
 #include "eggPrimitive.h"
+#include "config_xfile.h"
 
 ////////////////////////////////////////////////////////////////////
 //     Function: XFileNormal::Constructor
@@ -38,11 +39,24 @@ XFileNormal() {
 ////////////////////////////////////////////////////////////////////
 void XFileNormal::
 set_from_egg(EggVertex *egg_vertex, EggPrimitive *egg_prim) {
-  if (egg_vertex->has_normal()) {
-    _normal = LCAST(float, egg_vertex->get_normal());
-    _has_normal = true;
-  } else if (egg_prim->has_normal()) {
-    _normal = LCAST(float, egg_prim->get_normal());
+  if (egg_vertex->has_normal() || egg_prim->has_normal()) {
+    Normald norm;
+    if (egg_vertex->has_normal()) {
+      norm = egg_vertex->get_normal();
+    } else {
+      norm = egg_prim->get_normal();
+    }
+
+    if (xfile_one_mesh) {
+      // If this is going into one big mesh, we must ensure every
+      // vertex is in world coordinates.
+      norm = norm * egg_prim->get_vertex_frame();
+    } else {
+      // Otherwise, we ensure the vertex is in local coordinates.
+      norm = norm * egg_prim->get_vertex_to_node();
+    }
+
+    _normal = LCAST(float, norm);
     _has_normal = true;
   }
 }

+ 90 - 30
pandatool/src/xfile/xFileToEggConverter.cxx

@@ -20,6 +20,7 @@
 #include "xFileMesh.h"
 #include "xFileMaterial.h"
 #include "xFileTemplates.h"
+#include "config_xfile.h"
 
 #include "eggData.h"
 #include "eggGroup.h"
@@ -202,7 +203,8 @@ get_toplevel() {
   }
 
   if (hr != DXFILEERR_NOMOREOBJECTS) {
-    cerr << "Error extracting top-level objects.\n";
+    xfile_cat.error()
+      << "Error extracting top-level objects.\n";
     return false;
   }
 
@@ -228,8 +230,9 @@ convert_object(LPDIRECTXFILEOBJECT obj, EggGroupNode *egg_parent) {
   }
 
   // It isn't.
-  cerr << "Ignoring object of unknown type: " << get_object_name(obj)
-       << "\n";
+  xfile_cat.error()
+    << "Ignoring object of unknown type: " << get_object_name(obj)
+    << "\n";
   return true;
 }
 
@@ -248,7 +251,8 @@ convert_data_object(LPDIRECTXFILEDATA obj, EggGroupNode *egg_parent) {
   const GUID *type;
   hr = obj->GetType(&type);
   if (hr != DXFILE_OK) {
-    cerr << "Unable to get type of template\n";
+    xfile_cat.error()
+      << "Unable to get type of template\n";
     return false;
   }
 
@@ -259,13 +263,21 @@ convert_data_object(LPDIRECTXFILEDATA obj, EggGroupNode *egg_parent) {
     if (!convert_frame(obj, egg_parent)) {
       return false;
     }
+
+  } else if (*type == TID_D3DRMFrameTransformMatrix) {
+    if (!convert_transform(obj, egg_parent)) {
+      return false;
+    }
+
   } else if (*type == TID_D3DRMMesh) {
     if (!convert_mesh(obj, egg_parent)) {
       return false;
     }
+
   } else {
-    cerr << "Ignoring data object of unknown type: " << get_object_name(obj)
-         << "\n";
+    xfile_cat.error()
+      << "Ignoring data object of unknown type: " << get_object_name(obj)
+      << "\n";
   }
   
   return true;
@@ -297,13 +309,47 @@ convert_frame(LPDIRECTXFILEDATA obj, EggGroupNode *egg_parent) {
   }
 
   if (hr != DXFILEERR_NOMOREOBJECTS) {
-    cerr << "Error extracting children of frame " << name << ".\n";
+    xfile_cat.error()
+      << "Error extracting children of frame " << name << ".\n";
     return false;
   }
 
   return true;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: XFileToEggConverter::convert_transform
+//       Access: Private
+//  Description: Reads a transform matrix, a child of a given frame,
+//               and applies it to the node.  Normally this can only
+//               be done if the node in question is an EggGroup, which
+//               should be the case if the transform was a child of a
+//               frame.
+////////////////////////////////////////////////////////////////////
+bool XFileToEggConverter::
+convert_transform(LPDIRECTXFILEDATA obj, EggGroupNode *egg_parent) {
+  Datagram raw_data;
+  if (!get_data(obj, raw_data)) {
+    return false;
+  }
+
+  DatagramIterator di(raw_data);
+  LMatrix4f mat;
+  mat.read_datagram(di);
+
+  if (egg_parent->is_of_type(EggGroup::get_class_type())) {
+    EggGroup *egg_group = DCAST(EggGroup, egg_parent);
+    egg_group->set_transform(LCAST(double, mat));
+    egg_group->set_group_type(EggGroup::GT_instance);
+  } else {
+    xfile_cat.error()
+      << "Transform " << get_object_name(obj)
+      << " encountered without frame!\n";
+  }
+
+  return true;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: XFileToEggConverter::convert_mesh
 //       Access: Private
@@ -337,8 +383,9 @@ convert_mesh(LPDIRECTXFILEDATA obj, EggGroupNode *egg_parent) {
   }
 
   if (hr != DXFILEERR_NOMOREOBJECTS) {
-    cerr << "Error extracting children of mesh " << get_object_name(obj)
-         << ".\n";
+    xfile_cat.error()
+      << "Error extracting children of mesh " << get_object_name(obj)
+      << ".\n";
     return false;
   }
 
@@ -368,8 +415,9 @@ convert_mesh_object(LPDIRECTXFILEOBJECT obj, XFileMesh &mesh) {
   }
 
   // It isn't.
-  cerr << "Ignoring object of unknown type: " << get_object_name(obj)
-       << "\n";
+  xfile_cat.error()
+    << "Ignoring object of unknown type: " << get_object_name(obj)
+    << "\n";
   return true;
 }
 
@@ -387,7 +435,8 @@ convert_mesh_data_object(LPDIRECTXFILEDATA obj, XFileMesh &mesh) {
   const GUID *type;
   hr = obj->GetType(&type);
   if (hr != DXFILE_OK) {
-    cerr << "Unable to get type of template\n";
+    xfile_cat.error()
+      << "Unable to get type of template\n";
     return false;
   }
 
@@ -412,8 +461,9 @@ convert_mesh_data_object(LPDIRECTXFILEDATA obj, XFileMesh &mesh) {
     }
 
   } else {
-    cerr << "Ignoring data object of unknown type: " << get_object_name(obj)
-         << "\n";
+    xfile_cat.error()
+      << "Ignoring data object of unknown type: " << get_object_name(obj)
+      << "\n";
   }
   
   return true;
@@ -511,8 +561,9 @@ convert_mesh_material_list(LPDIRECTXFILEDATA obj, XFileMesh &mesh) {
   }
 
   if (hr != DXFILEERR_NOMOREOBJECTS) {
-    cerr << "Error extracting children of MeshMaterialList "
-         << get_object_name(obj) << ".\n";
+    xfile_cat.error()
+      << "Error extracting children of MeshMaterialList "
+      << get_object_name(obj) << ".\n";
     return false;
   }
 
@@ -538,8 +589,9 @@ convert_material_list_object(LPDIRECTXFILEOBJECT obj, XFileMesh &mesh) {
   }
 
   // It isn't.
-  cerr << "Ignoring object of unknown type: " << get_object_name(obj)
-       << "\n";
+  xfile_cat.error()
+    << "Ignoring object of unknown type: " << get_object_name(obj)
+    << "\n";
   return true;
 }
 
@@ -557,7 +609,8 @@ convert_material_list_data_object(LPDIRECTXFILEDATA obj, XFileMesh &mesh) {
   const GUID *type;
   hr = obj->GetType(&type);
   if (hr != DXFILE_OK) {
-    cerr << "Unable to get type of template\n";
+    xfile_cat.error()
+      << "Unable to get type of template\n";
     return false;
   }
 
@@ -566,8 +619,9 @@ convert_material_list_data_object(LPDIRECTXFILEDATA obj, XFileMesh &mesh) {
       return false;
     }
   } else {
-    cerr << "Ignoring data object of unknown type: " << get_object_name(obj)
-         << "\n";
+    xfile_cat.error()
+      << "Ignoring data object of unknown type: " << get_object_name(obj)
+      << "\n";
   }
   
   return true;
@@ -609,8 +663,9 @@ convert_material(LPDIRECTXFILEDATA obj, XFileMesh &mesh) {
   }
 
   if (hr != DXFILEERR_NOMOREOBJECTS) {
-    cerr << "Error extracting children of Material " 
-         << get_object_name(obj) << ".\n";
+    xfile_cat.error()
+      << "Error extracting children of Material " 
+      << get_object_name(obj) << ".\n";
     return false;
   }
 
@@ -636,8 +691,9 @@ convert_material_object(LPDIRECTXFILEOBJECT obj, XFileMaterial &material) {
   }
 
   // It isn't.
-  cerr << "Ignoring object of unknown type: " << get_object_name(obj)
-       << "\n";
+  xfile_cat.error()
+    << "Ignoring object of unknown type: " << get_object_name(obj)
+    << "\n";
   return true;
 }
 
@@ -655,7 +711,8 @@ convert_material_data_object(LPDIRECTXFILEDATA obj, XFileMaterial &material) {
   const GUID *type;
   hr = obj->GetType(&type);
   if (hr != DXFILE_OK) {
-    cerr << "Unable to get type of template\n";
+    xfile_cat.error()
+      << "Unable to get type of template\n";
     return false;
   }
 
@@ -664,8 +721,9 @@ convert_material_data_object(LPDIRECTXFILEDATA obj, XFileMaterial &material) {
       return false;
     }
   } else {
-    cerr << "Ignoring data object of unknown type: " << get_object_name(obj)
-         << "\n";
+    xfile_cat.error()
+      << "Ignoring data object of unknown type: " << get_object_name(obj)
+      << "\n";
   }
   
   return true;
@@ -711,7 +769,8 @@ get_object_name(LPDIRECTXFILEOBJECT obj) {
 
   string result;
   if (hr != DXFILE_OK) {
-    cerr << "Unable to get object name.\n";
+    xfile_cat.error()
+      << "Unable to get object name.\n";
   } else {
     result = buffer;
   }
@@ -732,7 +791,8 @@ get_data(LPDIRECTXFILEDATA obj, Datagram &raw_data) {
   void *data;
   hr = obj->GetData(NULL, &length, &data);
   if (hr != DXFILE_OK) {
-    cerr << "Unable to get data for " << get_object_name(obj) << "\n";
+    xfile_cat.error()
+      << "Unable to get data for " << get_object_name(obj) << "\n";
     return false;
   }
 

+ 1 - 0
pandatool/src/xfile/xFileToEggConverter.h

@@ -64,6 +64,7 @@ private:
   bool convert_object(LPDIRECTXFILEOBJECT obj, EggGroupNode *egg_parent);
   bool convert_data_object(LPDIRECTXFILEDATA obj, EggGroupNode *egg_parent);
   bool convert_frame(LPDIRECTXFILEDATA obj, EggGroupNode *egg_parent);
+  bool convert_transform(LPDIRECTXFILEDATA obj, EggGroupNode *egg_parent);
   bool convert_mesh(LPDIRECTXFILEDATA obj, EggGroupNode *egg_parent);
 
   bool convert_mesh_object(LPDIRECTXFILEOBJECT obj, XFileMesh &mesh);

+ 13 - 1
pandatool/src/xfile/xFileVertex.cxx

@@ -19,6 +19,7 @@
 #include "xFileVertex.h"
 #include "eggVertex.h"
 #include "eggPrimitive.h"
+#include "config_xfile.h"
 
 ////////////////////////////////////////////////////////////////////
 //     Function: XFileVertex::Constructor
@@ -41,7 +42,18 @@ XFileVertex() {
 ////////////////////////////////////////////////////////////////////
 void XFileVertex::
 set_from_egg(EggVertex *egg_vertex, EggPrimitive *egg_prim) {
-  _point = LCAST(float, egg_vertex->get_pos3());
+  Vertexd pos = egg_vertex->get_pos3();
+
+  if (xfile_one_mesh) {
+    // If this is going into one big mesh, we must ensure every
+    // vertex is in world coordinates.
+    pos = pos * egg_prim->get_vertex_frame();
+  } else {
+    // Otherwise, we ensure the vertex is in local coordinates.
+    pos = pos * egg_prim->get_vertex_to_node();
+  }
+
+  _point = LCAST(float, pos);
 
   if (egg_vertex->has_uv()) {
     TexCoordd uv = egg_vertex->get_uv();

+ 20 - 1
pandatool/src/xfileprogs/eggToX.cxx

@@ -17,6 +17,7 @@
 ////////////////////////////////////////////////////////////////////
 
 #include "eggToX.h"
+#include "config_xfile.h"
 
 ////////////////////////////////////////////////////////////////////
 //     Function: EggToX::Constructor
@@ -24,17 +25,30 @@
 //  Description:
 ////////////////////////////////////////////////////////////////////
 EggToX::
-EggToX() : EggToSomething("DirectX", ".x") {
+EggToX() : EggToSomething("DirectX", ".x", true, false) {
+  add_texture_options();
+
   set_program_description
     ("This program reads an Egg file and outputs an equivalent, "
      "or nearly equivalent, DirectX-style .x file.  Only simple "
      "hierarchy and polygon meshes are supported; advanced features "
      "like LOD's, decals, and characters cannot be supported.");
 
+  add_option
+    ("m", "", 0,
+     "Convert all the objects in the egg file as one big mesh, instead of "
+     "preserving the normal egg hierarchy.",
+     &EggToX::dispatch_none, &xfile_one_mesh);
+
   // X files are always y-up-left.
   remove_option("cs");
   _got_coordinate_system = true;
   _coordinate_system = CS_yup_left;
+
+  // We always have -f on: force complete load.  X files don't support
+  // external references.
+  remove_option("f");
+  _force_complete = true;
 }
 
 
@@ -50,6 +64,10 @@ run() {
     exit(1);
   }
 
+  if (!copy_textures()) {
+    exit(1);
+  }
+
   if (!_x.add_tree(_data)) {
     nout << "Unable to define egg structure.\n";
     exit(1);
@@ -60,6 +78,7 @@ run() {
 
 
 int main(int argc, char *argv[]) {
+  init_libxfile();
   EggToX prog;
   prog.parse_command_line(argc, argv);
   prog.run();

+ 2 - 0
pandatool/src/xfileprogs/xFileToEgg.cxx

@@ -18,6 +18,7 @@
 
 #include "xFileToEgg.h"
 #include "xFileToEggConverter.h"
+#include "config_xfile.h"
 
 ////////////////////////////////////////////////////////////////////
 //     Function: XFileToEgg::Constructor
@@ -71,6 +72,7 @@ run() {
 
 
 int main(int argc, char *argv[]) {
+  init_libxfile();
   XFileToEgg prog;
   prog.parse_command_line(argc, argv);
   prog.run();