Browse Source

*** empty log message ***

David Rose 24 years ago
parent
commit
3bd11c3cda

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

@@ -15,13 +15,46 @@
 
 
   #define SOURCES \
   #define SOURCES \
     xFileFace.cxx xFileFace.h \
     xFileFace.cxx xFileFace.h \
-    xFileMaker.cxx xFileMaker.h \
+    xFileMaterial.cxx xFileMaterial.h \
     xFileMesh.cxx xFileMesh.h \
     xFileMesh.cxx xFileMesh.h \
     xFileNormal.cxx xFileNormal.h \
     xFileNormal.cxx xFileNormal.h \
     xFileVertex.cxx xFileVertex.h
     xFileVertex.cxx xFileVertex.h
 
 
+  #define SOURCES \
+    $[SOURCES] \
+    xFileMaker.cxx xFileMaker.h
+
   #define SOURCES \
   #define SOURCES \
     $[SOURCES] \
     $[SOURCES] \
     eggToX.cxx eggToX.h
     eggToX.cxx eggToX.h
 
 
 #end bin_target
 #end bin_target
+
+#begin bin_target
+  #define TARGET x2egg
+  #define LOCAL_LIBS converter eggbase progbase pandatoolbase
+  #define OTHER_LIBS \
+    egg:c pandaegg:m \
+    mathutil:c linmath:c putil:c panda:m \
+    express:c pandaexpress:m \
+    dtoolconfig dtool pystub \
+
+  #define WIN_SYS_LIBS \
+    d3dxof.lib
+
+  #define SOURCES \
+    xFileFace.cxx xFileFace.h \
+    xFileMaterial.cxx xFileMaterial.h \
+    xFileMesh.cxx xFileMesh.h \
+    xFileNormal.cxx xFileNormal.h \
+    xFileVertex.cxx xFileVertex.h
+
+  #define SOURCES \
+    $[SOURCES] \
+    xFileToEggConverter.cxx xFileToEggConverter.h
+
+  #define SOURCES \
+    $[SOURCES] \
+    xFileToEgg.cxx xFileToEgg.h
+
+#end bin_target

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

@@ -26,7 +26,17 @@
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 XFileFace::
 XFileFace::
-XFileFace(XFileMesh *mesh, EggPolygon *egg_poly) {
+XFileFace() {
+  _material_index = -1;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileFace::set_from_egg
+//       Access: Public
+//  Description: Sets the structure up from the indicated egg data.
+////////////////////////////////////////////////////////////////////
+void XFileFace::
+set_from_egg(XFileMesh *mesh, EggPolygon *egg_poly) {
   // Walk through the polygon's vertices in reverse order, to change
   // Walk through the polygon's vertices in reverse order, to change
   // from Egg's counter-clockwise convention to DX's clockwise.
   // from Egg's counter-clockwise convention to DX's clockwise.
   EggPolygon::reverse_iterator vi;
   EggPolygon::reverse_iterator vi;
@@ -37,4 +47,6 @@ XFileFace(XFileMesh *mesh, EggPolygon *egg_poly) {
     v._normal_index = mesh->add_normal(egg_vertex, egg_poly);
     v._normal_index = mesh->add_normal(egg_vertex, egg_poly);
     _vertices.push_back(v);
     _vertices.push_back(v);
   }
   }
+
+  _material_index = mesh->add_material(egg_poly);
 }
 }

+ 4 - 1
pandatool/src/xfile/xFileFace.h

@@ -31,7 +31,8 @@ class EggPolygon;
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 class XFileFace {
 class XFileFace {
 public:
 public:
-  XFileFace(XFileMesh *mesh, EggPolygon *egg_poly);
+  XFileFace();
+  void set_from_egg(XFileMesh *mesh, EggPolygon *egg_poly);
 
 
   class Vertex {
   class Vertex {
   public:
   public:
@@ -40,6 +41,8 @@ public:
   };
   };
   typedef pvector<Vertex> Vertices;
   typedef pvector<Vertex> Vertices;
   Vertices _vertices;
   Vertices _vertices;
+
+  int _material_index;
 };
 };
 
 
 #endif
 #endif

+ 50 - 0
pandatool/src/xfile/xFileMaker.cxx

@@ -18,6 +18,8 @@
 
 
 #include "xFileMaker.h"
 #include "xFileMaker.h"
 #include "xFileMesh.h"
 #include "xFileMesh.h"
+#include "xFileMaterial.h"
+
 #include "notify.h"
 #include "notify.h"
 #include "eggGroupNode.h"
 #include "eggGroupNode.h"
 #include "eggGroup.h"
 #include "eggGroup.h"
@@ -305,6 +307,54 @@ add_polyset(EggBin *egg_bin, LPDIRECTXFILEDATA dx_parent) {
     }
     }
   }
   }
 
 
+  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)) {
   if (!attach_and_release(xobj, dx_parent)) {
     return false;
     return false;
   }
   }

+ 284 - 0
pandatool/src/xfile/xFileMaterial.cxx

@@ -0,0 +1,284 @@
+// Filename: xFileMaterial.cxx
+// Created by:  drose (19Jun01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "xFileMaterial.h"
+
+#include "eggMaterial.h"
+#include "eggTexture.h"
+#include "eggMaterialCollection.h"
+#include "eggTextureCollection.h"
+#include "eggPrimitive.h"
+#include "datagram.h"
+
+#include <string.h>  // for strcmp, strdup
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileMaterial::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+XFileMaterial::
+XFileMaterial() {
+  _face_color.set(1.0, 1.0, 1.0, 1.0);
+  _specular_color.set(0.0, 0.0, 0.0);
+  _emissive_color.set(0.0, 0.0, 0.0);
+  _power = 64.0;
+
+  _has_material = false;
+  _has_texture = false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileMaterial::Destructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+XFileMaterial::
+~XFileMaterial() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileMaterial::set_from_egg
+//       Access: Public
+//  Description: Sets the structure up from the indicated egg data.
+////////////////////////////////////////////////////////////////////
+void XFileMaterial::
+set_from_egg(EggPrimitive *egg_prim) {
+  // First, determine the face color.
+  if (egg_prim->has_color()) {
+    _face_color = egg_prim->get_color();
+    _has_material = true;
+  }
+
+  // Do we have an actual EggMaterial, to control lighting effects?
+  if (egg_prim->has_material()) {
+    _has_material = true;
+    EggMaterial *egg_mat = egg_prim->get_material();
+    if (egg_mat->has_diff()) {
+      _face_color = egg_mat->get_diff();
+    }
+    if (egg_mat->has_spec()) {
+      const Colorf &spec = egg_mat->get_spec();
+      _specular_color.set(spec[0], spec[1], spec[2]);
+    }
+    if (egg_mat->has_emit()) {
+      const Colorf &emit = egg_mat->get_emit();
+      _emissive_color.set(emit[0], emit[1], emit[2]);
+    }
+    if (egg_mat->has_shininess()) {
+      _power = egg_mat->get_shininess();
+    }
+  }
+
+  // Finally, if we also have a texture, record that.
+  if (egg_prim->has_texture()) {
+    _has_material = true;
+    _has_texture = true;
+    EggTexture *egg_tex = egg_prim->get_texture();
+    _texture = egg_tex->get_filename();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileMaterial::apply_to_egg
+//       Access: Public
+//  Description: Applies the properties in the material to the
+//               indicated egg primitive.
+////////////////////////////////////////////////////////////////////
+void XFileMaterial::
+apply_to_egg(EggPrimitive *egg_prim,
+             EggTextureCollection &textures,
+             EggMaterialCollection &materials) {
+  // Is there a texture?
+  if (_has_texture) {
+    EggTexture temp("", _texture);
+    EggTexture *egg_tex =
+      textures.create_unique_texture(temp, ~EggTexture::E_tref_name);
+    egg_prim->set_texture(egg_tex);
+  }
+
+  // Are there any fancy lighting effects?
+  bool got_spec = (_specular_color != RGBColorf::zero());
+  bool got_emit = (_emissive_color != RGBColorf::zero());
+  if (got_spec || got_emit) {
+    EggMaterial temp("");
+    temp.set_diff(_face_color);
+    if (got_spec) {
+      temp.set_shininess(_power);
+      temp.set_spec(Colorf(_specular_color[0], _specular_color[1],
+                           _specular_color[2], 1.0));
+    }
+    if (got_emit) {
+      temp.set_emit(Colorf(_emissive_color[0], _emissive_color[1],
+                           _emissive_color[2], 1.0));
+    }
+    EggMaterial *egg_mat =
+      materials.create_unique_material(temp, ~EggMaterial::E_mref_name);
+    egg_prim->set_material(egg_mat);
+  }
+
+  // Also apply the face color.
+  egg_prim->set_color(_face_color);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileMaterial::compare_to
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+int XFileMaterial::
+compare_to(const XFileMaterial &other) const {
+  int ct;
+  ct = _face_color.compare_to(other._face_color);
+  if (ct == 0) {
+    ct = (_power == other._power) ? 0 : ((_power < other._power) ? -1 : 1);
+  }
+  if (ct == 0) {
+    ct = _specular_color.compare_to(other._specular_color);
+  }
+  if (ct == 0) {
+    ct = _emissive_color.compare_to(other._emissive_color);
+  }
+  if (ct == 0) {
+    ct = strcmp(_texture.c_str(), other._texture.c_str());
+  }
+  return ct;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileMaterial::has_material
+//       Access: Public
+//  Description: Returns true if this material represents something
+//               meaningful, or false if the default material is
+//               sufficient.
+////////////////////////////////////////////////////////////////////
+bool XFileMaterial::
+has_material() const {
+  return _has_material;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileMaterial::has_texture
+//       Access: Public
+//  Description: Returns true if this material includes a texture map,
+//               false otherwise.
+////////////////////////////////////////////////////////////////////
+bool XFileMaterial::
+has_texture() const {
+  return _has_texture;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileMaterial::make_material_data
+//       Access: Public
+//  Description: Fills the datagram with the raw data for the DX
+//               Material template.
+////////////////////////////////////////////////////////////////////
+void XFileMaterial::
+make_material_data(Datagram &raw_data) {
+  raw_data.clear();
+  raw_data.add_float32(_face_color[0]);
+  raw_data.add_float32(_face_color[1]);
+  raw_data.add_float32(_face_color[2]);
+  raw_data.add_float32(_face_color[3]);
+  raw_data.add_float32(_power);
+  raw_data.add_float32(_specular_color[0]);
+  raw_data.add_float32(_specular_color[1]);
+  raw_data.add_float32(_specular_color[2]);
+  raw_data.add_float32(_emissive_color[0]);
+  raw_data.add_float32(_emissive_color[1]);
+  raw_data.add_float32(_emissive_color[2]);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileMaterial::make_texture_data
+//       Access: Public
+//  Description: Fills the datagram with the raw data for the DX
+//               TextureFilename template.
+////////////////////////////////////////////////////////////////////
+void XFileMaterial::
+make_texture_data(Datagram &raw_data) {
+  raw_data.clear();
+
+  // Get a char * pointer to the texture filename, to pass into the
+  // Microsoft DX file interface.  Unfortunately, we can't delete this
+  // again, since it needs to live longer than the life of the
+  // XFileMaterial object itself, so this becomes a memory leak
+  // (unless the DX file interface frees it, but the documentation is
+  // far from clear).  Too bad.
+  string filename = _texture.to_os_specific();
+  char *filename_str = strdup(filename.c_str());
+
+  // The Microsoft convention is to stuff a pointer into a four-byte
+  // field.  Not terribly portable, but that's the interface.
+  raw_data.add_int32((int)filename_str);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileMaterial::read_material_data
+//       Access: Public
+//  Description: Fills the structure based on the raw data from the
+//               Material template.
+////////////////////////////////////////////////////////////////////
+bool XFileMaterial::
+read_material_data(const Datagram &raw_data) {
+  DatagramIterator di(raw_data);
+
+  _face_color[0] = di.get_float32();
+  _face_color[1] = di.get_float32();
+  _face_color[2] = di.get_float32();
+  _face_color[3] = di.get_float32();
+  _power = di.get_float32();
+  _specular_color[0] = di.get_float32();
+  _specular_color[1] = di.get_float32();
+  _specular_color[2] = di.get_float32();
+  _emissive_color[0] = di.get_float32();
+  _emissive_color[1] = di.get_float32();
+  _emissive_color[2] = di.get_float32();
+  _has_material = true;
+
+  if (di.get_remaining_size() != 0) {
+    cerr << "Ignoring " << di.get_remaining_size()
+         << " trailing MeshMaterial.\n";
+  }
+
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileMaterial::read_texture_data
+//       Access: Public
+//  Description: Fills the structure based on the raw data from the
+//               TextureFilename template.
+////////////////////////////////////////////////////////////////////
+bool XFileMaterial::
+read_texture_data(const Datagram &raw_data) {
+  DatagramIterator di(raw_data);
+
+  // The Microsoft convention is to stuff a pointer into a four-byte
+  // field.  Not terribly portable, but that's the interface.
+  const char *ptr = (const char *)di.get_int32();
+  _texture = ptr;
+  _has_texture = true;
+
+  if (di.get_remaining_size() != 0) {
+    cerr << "Ignoring " << di.get_remaining_size()
+         << " trailing MeshMaterial.\n";
+  }
+  return true;
+}

+ 69 - 0
pandatool/src/xfile/xFileMaterial.h

@@ -0,0 +1,69 @@
+// Filename: xFileMaterial.h
+// Created by:  drose (19Jun01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 XFILEMATERIAL_H
+#define XFILEMATERIAL_H
+
+#include "pandatoolbase.h"
+#include "luse.h"
+#include "filename.h"
+
+class EggPrimitive;
+class EggTextureCollection;
+class EggMaterialCollection;
+class Datagram;
+
+////////////////////////////////////////////////////////////////////
+//       Class : XFileMaterial
+// Description : This represents an X file "material", which consists
+//               of a color, lighting, and/or texture specification.
+////////////////////////////////////////////////////////////////////
+class XFileMaterial {
+public:
+  XFileMaterial();
+  ~XFileMaterial();
+
+  void set_from_egg(EggPrimitive *egg_prim);
+  void apply_to_egg(EggPrimitive *egg_prim,
+                    EggTextureCollection &textures,
+                    EggMaterialCollection &materials);
+
+  int compare_to(const XFileMaterial &other) const;
+
+  bool has_material() const;
+  bool has_texture() const;
+
+  void make_material_data(Datagram &raw_data);
+  void make_texture_data(Datagram &raw_data);
+
+  bool read_material_data(const Datagram &raw_data);
+  bool read_texture_data(const Datagram &raw_data);
+
+private:
+  Colorf _face_color;
+  float _power;
+  RGBColorf _specular_color;
+  RGBColorf _emissive_color;
+  Filename _texture;
+
+  bool _has_material;
+  bool _has_texture;
+};
+
+#endif
+

+ 445 - 3
pandatool/src/xfile/xFileMesh.cxx

@@ -20,6 +20,12 @@
 #include "xFileFace.h"
 #include "xFileFace.h"
 #include "xFileVertex.h"
 #include "xFileVertex.h"
 #include "xFileNormal.h"
 #include "xFileNormal.h"
+#include "xFileMaterial.h"
+
+#include "eggVertexPool.h"
+#include "eggVertex.h"
+#include "eggPolygon.h"
+#include "eggGroupNode.h"
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: XFileMesh::Constructor
 //     Function: XFileMesh::Constructor
@@ -31,6 +37,7 @@ XFileMesh() {
   _has_normals = false;
   _has_normals = false;
   _has_colors = false;
   _has_colors = false;
   _has_uvs = false;
   _has_uvs = false;
+  _has_materials = false;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -40,6 +47,16 @@ XFileMesh() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 XFileMesh::
 XFileMesh::
 ~XFileMesh() {
 ~XFileMesh() {
+  clear();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileMesh::clear
+//       Access: Public
+//  Description: Empties all data from the mesh.
+////////////////////////////////////////////////////////////////////
+void XFileMesh::
+clear() {
   Vertices::iterator vi;
   Vertices::iterator vi;
   for (vi = _vertices.begin(); vi != _vertices.end(); ++vi) {
   for (vi = _vertices.begin(); vi != _vertices.end(); ++vi) {
     XFileVertex *vertex = (*vi);
     XFileVertex *vertex = (*vi);
@@ -50,6 +67,25 @@ XFileMesh::
     XFileNormal *normal = (*ni);
     XFileNormal *normal = (*ni);
     delete normal;
     delete normal;
   }
   }
+  Materials::iterator mi;
+  for (mi = _materials.begin(); mi != _materials.end(); ++mi) {
+    XFileMaterial *material = (*mi);
+    delete material;
+  }
+  Faces::iterator fi;
+  for (fi = _faces.begin(); fi != _faces.end(); ++fi) {
+    XFileFace *face = (*fi);
+    delete face;
+  }
+
+  _vertices.clear();
+  _normals.clear();
+  _materials.clear();
+  _faces.clear();
+
+  _unique_vertices.clear();
+  _unique_normals.clear();
+  _unique_materials.clear();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -59,7 +95,8 @@ XFileMesh::
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void XFileMesh::
 void XFileMesh::
 add_polygon(EggPolygon *egg_poly) {
 add_polygon(EggPolygon *egg_poly) {
-  XFileFace *face = new XFileFace(this, egg_poly);
+  XFileFace *face = new XFileFace;
+  face->set_from_egg(this, egg_poly);
   _faces.push_back(face);
   _faces.push_back(face);
 }
 }
 
 
@@ -73,7 +110,8 @@ add_polygon(EggPolygon *egg_poly) {
 int XFileMesh::
 int XFileMesh::
 add_vertex(EggVertex *egg_vertex, EggPrimitive *egg_prim) {
 add_vertex(EggVertex *egg_vertex, EggPrimitive *egg_prim) {
   int next_index = _vertices.size();
   int next_index = _vertices.size();
-  XFileVertex *vertex = new XFileVertex(egg_vertex, egg_prim);
+  XFileVertex *vertex = new XFileVertex;
+  vertex->set_from_egg(egg_vertex, egg_prim);
   if (vertex->_has_color) {
   if (vertex->_has_color) {
     _has_colors = true;
     _has_colors = true;
   }
   }
@@ -107,7 +145,8 @@ add_vertex(EggVertex *egg_vertex, EggPrimitive *egg_prim) {
 int XFileMesh::
 int XFileMesh::
 add_normal(EggVertex *egg_vertex, EggPrimitive *egg_prim) {
 add_normal(EggVertex *egg_vertex, EggPrimitive *egg_prim) {
   int next_index = _normals.size();
   int next_index = _normals.size();
-  XFileNormal *normal = new XFileNormal(egg_vertex, egg_prim);
+  XFileNormal *normal = new XFileNormal;
+  normal->set_from_egg(egg_vertex, egg_prim);
   if (normal->_has_normal) {
   if (normal->_has_normal) {
     _has_normals = true;
     _has_normals = true;
   }
   }
@@ -127,6 +166,156 @@ add_normal(EggVertex *egg_vertex, EggPrimitive *egg_prim) {
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: XFileMesh::add_material
+//       Access: Public
+//  Description: Creates a new XFileMaterial, if one does not already
+//               exist for the indicated material, and returns its
+//               index.
+////////////////////////////////////////////////////////////////////
+int XFileMesh::
+add_material(EggPrimitive *egg_prim) {
+  int next_index = _materials.size();
+  XFileMaterial *material = new XFileMaterial;
+  material->set_from_egg(egg_prim);
+  if (material->has_material()) {
+    _has_materials = true;
+  }
+
+  pair<UniqueMaterials::iterator, bool> result =
+    _unique_materials.insert(UniqueMaterials::value_type(material, next_index));
+
+  if (result.second) {
+    // Successfully added; this is a new material.
+    _materials.push_back(material);
+    return next_index;
+  } else {
+    // Not successfully added; there is already a material with these
+    // properties.  Return that one instead.
+    delete material;
+    return (*result.first).second;
+  }
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileMesh::add_vertex
+//       Access: Public
+//  Description: Adds the newly-created XFileVertex unequivocally to
+//               the mesh, returning its index number.  The XFileMesh
+//               object becomes the owner of the XFileVertex
+//               pointer, and will delete it when it destructs.
+////////////////////////////////////////////////////////////////////
+int XFileMesh::
+add_vertex(XFileVertex *vertex) {
+  int next_index = _vertices.size();
+  _unique_vertices.insert(UniqueVertices::value_type(vertex, next_index));
+  _vertices.push_back(vertex);
+  return next_index;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileMesh::add_normal
+//       Access: Public
+//  Description: Adds the newly-created XFileNormal unequivocally to
+//               the mesh, returning its index number.  The XFileMesh
+//               object becomes the owner of the XFileNormal
+//               pointer, and will delete it when it destructs.
+////////////////////////////////////////////////////////////////////
+int XFileMesh::
+add_normal(XFileNormal *normal) {
+  int next_index = _normals.size();
+  _unique_normals.insert(UniqueNormals::value_type(normal, next_index));
+  _normals.push_back(normal);
+  return next_index;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileMesh::add_material
+//       Access: Public
+//  Description: Adds the newly-created XFileMaterial unequivocally to
+//               the mesh, returning its index number.  The XFileMesh
+//               object becomes the owner of the XFileMaterial
+//               pointer, and will delete it when it destructs.
+////////////////////////////////////////////////////////////////////
+int XFileMesh::
+add_material(XFileMaterial *material) {
+  int next_index = _materials.size();
+  _unique_materials.insert(UniqueMaterials::value_type(material, next_index));
+  _materials.push_back(material);
+  return next_index;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileMesh::create_polygons
+//       Access: Public
+//  Description: Creates a slew of EggPolygons according to the faces
+//               in the mesh, and adds them to the indicated parent
+//               node.
+////////////////////////////////////////////////////////////////////
+bool XFileMesh::
+create_polygons(EggGroupNode *egg_parent,
+                EggTextureCollection &textures,
+                EggMaterialCollection &materials) {
+  EggVertexPool *vpool = new EggVertexPool(get_name());
+  egg_parent->add_child(vpool);
+  Faces::const_iterator fi;
+  for (fi = _faces.begin(); fi != _faces.end(); ++fi) {
+    XFileFace *face = (*fi);
+
+    EggPolygon *egg_poly = new EggPolygon;
+    egg_parent->add_child(egg_poly);
+
+    // Set up the vertices for the polygon.
+    XFileFace::Vertices::reverse_iterator vi;
+    for (vi = face->_vertices.rbegin(); vi != face->_vertices.rend(); ++vi) {
+      int vertex_index = (*vi)._vertex_index;
+      int normal_index = (*vi)._normal_index;
+      if (vertex_index < 0 || vertex_index >= (int)_vertices.size()) {
+        cerr << "Vertex index out of range in Mesh.\n";
+        return false;
+      }
+      XFileVertex *vertex = _vertices[vertex_index];
+      XFileNormal *normal = (XFileNormal *)NULL;
+
+      if (normal_index >= 0 && normal_index < (int)_normals.size()) {
+        normal = _normals[normal_index];
+      }
+
+      // Create a temporary EggVertex before adding it to the pool.
+      EggVertex temp_vtx;
+      temp_vtx.set_pos(LCAST(double, vertex->_point));
+      if (vertex->_has_color) {
+        temp_vtx.set_color(vertex->_color);
+      }
+      if (vertex->_has_uv) {
+        TexCoordd uv = LCAST(double, vertex->_uv);
+        // Windows draws the UV's upside-down.
+        uv[1] = 1.0 - uv[1];
+        temp_vtx.set_uv(uv);
+      }
+
+      if (normal != (XFileNormal *)NULL && normal->_has_normal) {
+        temp_vtx.set_normal(LCAST(double, normal->_normal));
+      }
+
+      // Now get a real EggVertex matching our template.
+      EggVertex *egg_vtx = vpool->create_unique_vertex(temp_vtx);
+      egg_poly->add_vertex(egg_vtx);
+    }
+
+    // And apply the material for the polygon.
+    int material_index = face->_material_index;
+    if (material_index >= 0 && material_index < (int)_materials.size()) {
+      XFileMaterial *material = _materials[material_index];
+      material->apply_to_egg(egg_poly, textures, materials);
+    }
+
+  }
+
+  return true;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: XFileMesh::has_normals
 //     Function: XFileMesh::has_normals
 //       Access: Public
 //       Access: Public
@@ -160,6 +349,40 @@ has_uvs() const {
   return _has_uvs;
   return _has_uvs;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: XFileMesh::has_materials
+//       Access: Public
+//  Description: Returns true if any of the faces added to this mesh
+//               used a real material, false otherwise.
+////////////////////////////////////////////////////////////////////
+bool XFileMesh::
+has_materials() const {
+  return _has_materials;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileMesh::get_num_materials
+//       Access: Public
+//  Description: Returns the number of distinct materials associated
+//               with the mesh.
+////////////////////////////////////////////////////////////////////
+int XFileMesh::
+get_num_materials() const {
+  return _materials.size();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileMesh::get_material
+//       Access: Public
+//  Description: Returns a pointer to the nth materials associated
+//               with the mesh.
+////////////////////////////////////////////////////////////////////
+XFileMaterial *XFileMesh::
+get_material(int n) const {
+  nassertr(n >= 0 && n < (int)_materials.size(), (XFileMaterial *)NULL);
+  return _materials[n];
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: XFileMesh::make_mesh_data
 //     Function: XFileMesh::make_mesh_data
 //       Access: Public
 //       Access: Public
@@ -274,3 +497,222 @@ make_uv_data(Datagram &raw_data) {
     raw_data.add_float32(uv[1]);
     raw_data.add_float32(uv[1]);
   }
   }
 }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileMesh::make_material_list_data
+//       Access: Public
+//  Description: Fills the datagram with the raw data for the DX
+//               MeshMaterialList template.
+////////////////////////////////////////////////////////////////////
+void XFileMesh::
+make_material_list_data(Datagram &raw_data) {
+  raw_data.clear();
+  raw_data.add_int32(_materials.size());
+  raw_data.add_int32(_faces.size());
+  Faces::const_iterator fi;
+  for (fi = _faces.begin(); fi != _faces.end(); ++fi) {
+    XFileFace *face = (*fi);
+    raw_data.add_int32(face->_material_index);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileMesh::read_mesh_data
+//       Access: Public
+//  Description: Fills the structure based on the raw data from the
+//               Mesh template.
+////////////////////////////////////////////////////////////////////
+bool XFileMesh::
+read_mesh_data(const Datagram &raw_data) {
+  DatagramIterator di(raw_data);
+
+  clear();
+
+  int i, j;
+  int num_vertices = di.get_int32();
+  for (i = 0; i < num_vertices; i++) {
+    XFileVertex *vertex = new XFileVertex;
+    vertex->_point[0] = di.get_float32();
+    vertex->_point[1] = di.get_float32();
+    vertex->_point[2] = di.get_float32();
+    add_vertex(vertex);
+  }
+
+  int num_faces = di.get_int32();
+  for (i = 0; i < num_faces; i++) {
+    XFileFace *face = new XFileFace;
+
+    num_vertices = di.get_int32();
+    for (j = 0; j < num_vertices; j++) {
+      XFileFace::Vertex vertex;
+      vertex._vertex_index = di.get_int32();
+      vertex._normal_index = -1;
+
+      face->_vertices.push_back(vertex);
+    }
+    _faces.push_back(face);
+  }
+
+  if (di.get_remaining_size() != 0) {
+    cerr << "Ignoring " << di.get_remaining_size() << " trailing Mesh.\n";
+  }
+
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileMesh::read_normal_data
+//       Access: Public
+//  Description: Fills the structure based on the raw data from the
+//               MeshNormals template.
+////////////////////////////////////////////////////////////////////
+bool XFileMesh::
+read_normal_data(const Datagram &raw_data) {
+  DatagramIterator di(raw_data);
+
+  int num_normals = di.get_int32();
+  int i;
+  for (i = 0; i < num_normals; i++) {
+    XFileNormal *normal = new XFileNormal;
+    normal->_normal[0] = di.get_float32();
+    normal->_normal[1] = di.get_float32();
+    normal->_normal[2] = di.get_float32();
+    normal->_has_normal = true;
+    add_normal(normal);
+  }
+
+  int num_faces = di.get_int32();
+
+  if (num_faces != _faces.size()) {
+    cerr << "Incorrect number of faces in MeshNormals.\n";
+    return false;
+  }
+
+  for (i = 0; i < num_faces; i++) {
+    XFileFace *face = _faces[i];
+    int num_vertices = di.get_int32();
+    if (num_vertices != face->_vertices.size()) {
+      cerr << "Incorrect number of vertices for face in MeshNormals.\n";
+      return false;
+    }
+    for (int j = 0; j < num_vertices; j++) {
+      face->_vertices[j]._normal_index = di.get_int32();
+    }
+  }
+
+  if (di.get_remaining_size() != 0) {
+    cerr << "Ignoring " << di.get_remaining_size()
+         << " trailing MeshNormals.\n";
+  }
+
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileMesh::read_color_data
+//       Access: Public
+//  Description: Fills the structure based on the raw data from the
+//               MeshVertexColors template.
+////////////////////////////////////////////////////////////////////
+bool XFileMesh::
+read_color_data(const Datagram &raw_data) {
+  DatagramIterator di(raw_data);
+
+  int num_colors = di.get_int32();
+  int i;
+  for (i = 0; i < num_colors; i++) {
+    int vertex_index = di.get_int32();
+    if (vertex_index < 0 || vertex_index >= _vertices.size()) {
+      cerr << "Vertex index out of range in MeshVertexColors.\n";
+      return false;
+    }
+    XFileVertex *vertex = _vertices[vertex_index];
+    vertex->_color[0] = di.get_float32();
+    vertex->_color[1] = di.get_float32();
+    vertex->_color[2] = di.get_float32();
+    vertex->_color[3] = di.get_float32();
+    vertex->_has_color = true;
+  }
+
+  if (di.get_remaining_size() != 0) {
+    cerr << "Ignoring " << di.get_remaining_size()
+         << " trailing MeshVertexColors.\n";
+  }
+
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileMesh::read_uv_data
+//       Access: Public
+//  Description: Fills the structure based on the raw data from the
+//               MeshTextureCoords template.
+////////////////////////////////////////////////////////////////////
+bool XFileMesh::
+read_uv_data(const Datagram &raw_data) {
+  DatagramIterator di(raw_data);
+
+  int num_vertices = di.get_int32();
+  if (num_vertices != _vertices.size()) {
+    cerr << "Wrong number of vertices in MeshTextureCoords.\n";
+    return false;
+  }
+
+  int i;
+  for (i = 0; i < num_vertices; i++) {
+    XFileVertex *vertex = _vertices[i];
+    vertex->_uv[0] = di.get_float32();
+    vertex->_uv[1] = di.get_float32();
+    vertex->_has_uv = true;
+  }
+
+  if (di.get_remaining_size() != 0) {
+    cerr << "Ignoring " << di.get_remaining_size()
+         << " trailing MeshTextureCoords.\n";
+  }
+
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileMesh::read_material_list_data
+//       Access: Public
+//  Description: Fills the structure based on the raw data from the
+//               MaterialList template.
+////////////////////////////////////////////////////////////////////
+bool XFileMesh::
+read_material_list_data(const Datagram &raw_data) {
+  DatagramIterator di(raw_data);
+
+  di.get_int32();  /* num_materials */
+  int num_faces = di.get_int32();
+
+  if (num_faces > _faces.size()) {
+    cerr << "Too many faces in MaterialList.\n";
+    return false;
+  }
+
+  int material_index = -1;
+  int i = 0;
+  while (i < num_faces) {
+    XFileFace *face = _faces[i];
+    material_index = di.get_int32();
+    face->_material_index = material_index;
+    i++;
+  }
+
+  // The rest of the faces get the same material index as the last
+  // one in the list.
+  while (i < (int)_faces.size()) {
+    XFileFace *face = _faces[i];
+    face->_material_index = material_index;
+    i++;
+  }
+
+  if (di.get_remaining_size() != 0) {
+    cerr << "Ignoring " << di.get_remaining_size()
+         << " trailing MeshMaterialList.\n";
+  }
+
+  return true;
+}

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

@@ -23,56 +23,88 @@
 #include "pvector.h"
 #include "pvector.h"
 #include "pmap.h"
 #include "pmap.h"
 #include "indirectCompareTo.h"
 #include "indirectCompareTo.h"
+#include "namable.h"
 
 
 class XFileMesh;
 class XFileMesh;
 class XFileVertex;
 class XFileVertex;
 class XFileNormal;
 class XFileNormal;
+class XFileMaterial;
 class XFileFace;
 class XFileFace;
+class EggGroupNode;
 class EggVertex;
 class EggVertex;
 class EggPolygon;
 class EggPolygon;
 class EggPrimitive;
 class EggPrimitive;
+class EggTextureCollection;
+class EggMaterialCollection;
 class Datagram;
 class Datagram;
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //       Class : XFileMesh
 //       Class : XFileMesh
 // Description : This is a collection of polygons; i.e. a polyset.
 // Description : This is a collection of polygons; i.e. a polyset.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-class XFileMesh {
+class XFileMesh : public Namable {
 public:
 public:
   XFileMesh();
   XFileMesh();
   ~XFileMesh();
   ~XFileMesh();
 
 
+  void clear();
+
   void add_polygon(EggPolygon *egg_poly);
   void add_polygon(EggPolygon *egg_poly);
   int add_vertex(EggVertex *egg_vertex, EggPrimitive *egg_prim);
   int add_vertex(EggVertex *egg_vertex, EggPrimitive *egg_prim);
   int add_normal(EggVertex *egg_vertex, EggPrimitive *egg_prim);
   int add_normal(EggVertex *egg_vertex, EggPrimitive *egg_prim);
+  int add_material(EggPrimitive *egg_prim);
+
+  int add_vertex(XFileVertex *vertex);
+  int add_normal(XFileNormal *normal);
+  int add_material(XFileMaterial *material);
+
+  bool create_polygons(EggGroupNode *egg_parent, 
+                       EggTextureCollection &textures,
+                       EggMaterialCollection &materials);
 
 
   bool has_normals() const;
   bool has_normals() const;
   bool has_colors() const;
   bool has_colors() const;
   bool has_uvs() const;
   bool has_uvs() const;
+  bool has_materials() const;
+
+  int get_num_materials() const;
+  XFileMaterial *get_material(int n) const;
 
 
   void make_mesh_data(Datagram &raw_data);
   void make_mesh_data(Datagram &raw_data);
   void make_normal_data(Datagram &raw_data);
   void make_normal_data(Datagram &raw_data);
   void make_color_data(Datagram &raw_data);
   void make_color_data(Datagram &raw_data);
   void make_uv_data(Datagram &raw_data);
   void make_uv_data(Datagram &raw_data);
+  void make_material_list_data(Datagram &raw_data);
+
+  bool read_mesh_data(const Datagram &raw_data);
+  bool read_normal_data(const Datagram &raw_data);
+  bool read_color_data(const Datagram &raw_data);
+  bool read_uv_data(const Datagram &raw_data);
+  bool read_material_list_data(const Datagram &raw_data);
 
 
 private:
 private:
   typedef pvector<XFileVertex *> Vertices;
   typedef pvector<XFileVertex *> Vertices;
   typedef pvector<XFileNormal *> Normals;
   typedef pvector<XFileNormal *> Normals;
+  typedef pvector<XFileMaterial *> Materials;
   typedef pvector<XFileFace *> Faces;
   typedef pvector<XFileFace *> Faces;
 
 
   Vertices _vertices;
   Vertices _vertices;
   Normals _normals;
   Normals _normals;
+  Materials _materials;
   Faces _faces;
   Faces _faces;
 
 
 private:
 private:
   typedef pmap<XFileVertex *, int, IndirectCompareTo<XFileVertex> > UniqueVertices;
   typedef pmap<XFileVertex *, int, IndirectCompareTo<XFileVertex> > UniqueVertices;
   typedef pmap<XFileNormal *, int, IndirectCompareTo<XFileNormal> > UniqueNormals;
   typedef pmap<XFileNormal *, int, IndirectCompareTo<XFileNormal> > UniqueNormals;
+  typedef pmap<XFileMaterial *, int, IndirectCompareTo<XFileMaterial> > UniqueMaterials;
   UniqueVertices _unique_vertices;
   UniqueVertices _unique_vertices;
   UniqueNormals _unique_normals;
   UniqueNormals _unique_normals;
+  UniqueMaterials _unique_materials;
 
 
   bool _has_normals;
   bool _has_normals;
   bool _has_colors;
   bool _has_colors;
   bool _has_uvs;
   bool _has_uvs;
+  bool _has_materials;
 };
 };
 
 
 #endif
 #endif

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

@@ -26,15 +26,24 @@
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 XFileNormal::
 XFileNormal::
-XFileNormal(EggVertex *egg_vertex, EggPrimitive *egg_prim) {
-  _has_normal = true;
+XFileNormal() {
+  _normal.set(0.0, 0.0, 0.0);
+  _has_normal = false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileNormal::set_from_egg
+//       Access: Public
+//  Description: Sets the structure up from the indicated egg data.
+////////////////////////////////////////////////////////////////////
+void XFileNormal::
+set_from_egg(EggVertex *egg_vertex, EggPrimitive *egg_prim) {
   if (egg_vertex->has_normal()) {
   if (egg_vertex->has_normal()) {
     _normal = LCAST(float, egg_vertex->get_normal());
     _normal = LCAST(float, egg_vertex->get_normal());
+    _has_normal = true;
   } else if (egg_prim->has_normal()) {
   } else if (egg_prim->has_normal()) {
     _normal = LCAST(float, egg_prim->get_normal());
     _normal = LCAST(float, egg_prim->get_normal());
-  } else {
-    _normal.set(0.0, 0.0, 0.0);
-    _has_normal = false;
+    _has_normal = true;
   }
   }
 }
 }
 
 

+ 2 - 1
pandatool/src/xfile/xFileNormal.h

@@ -34,7 +34,8 @@ class EggPrimitive;
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 class XFileNormal {
 class XFileNormal {
 public:
 public:
-  XFileNormal(EggVertex *egg_vertex, EggPrimitive *egg_prim);
+  XFileNormal();
+  void set_from_egg(EggVertex *egg_vertex, EggPrimitive *egg_prim);
   int compare_to(const XFileNormal &other) const;
   int compare_to(const XFileNormal &other) const;
 
 
   Normalf _normal;
   Normalf _normal;

+ 78 - 0
pandatool/src/xfile/xFileToEgg.cxx

@@ -0,0 +1,78 @@
+// Filename: xFileToEgg.cxx
+// Created by:  drose (21Jun01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "xFileToEgg.h"
+#include "xFileToEggConverter.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileToEgg::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+XFileToEgg::
+XFileToEgg() :
+  SomethingToEgg("DirectX", ".x")
+{
+  add_normals_options();
+  add_transform_options();
+  add_texture_path_options();
+  add_rel_dir_options();
+  add_search_path_options(false);
+
+  set_program_description
+    ("This program converts DirectX retained-mode (.x) files to egg.  This "
+     "is a simple file format that only supports basic polygons, materials, "
+     "and textures, in a hierarchy.");
+
+  redescribe_option
+    ("cs",
+     "Specify the coordinate system of the input " + _format_name +
+     " file.  Normally, this is y-up-left.");
+
+  _coordinate_system = CS_yup_left;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileToEgg::run
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+void XFileToEgg::
+run() {
+  _data.set_coordinate_system(_coordinate_system);
+
+  XFileToEggConverter converter;
+  converter.set_egg_data(&_data, false);
+  converter.set_texture_path_convert(_texture_path_convert, _make_rel_dir);
+
+  if (!converter.convert_file(_input_filename)) {
+    nout << "Unable to read " << _input_filename << "\n";
+    exit(1);
+  }
+
+  write_egg_file();
+  nout << "\n";
+}
+
+
+int main(int argc, char *argv[]) {
+  XFileToEgg prog;
+  prog.parse_command_line(argc, argv);
+  prog.run();
+  return 0;
+}

+ 41 - 0
pandatool/src/xfile/xFileToEgg.h

@@ -0,0 +1,41 @@
+// Filename: xFileToEgg.h
+// Created by:  drose (21Jun01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 XFILETOEGG_H
+#define XFILETOEGG_H
+
+#include "pandatoolbase.h"
+#include "somethingToEgg.h"
+#include "xFileToEggConverter.h"
+
+#include "dSearchPath.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : XFileToEgg
+// Description : A program to read a DirectX "x" file and generate an
+//               egg file.
+////////////////////////////////////////////////////////////////////
+class XFileToEgg : public SomethingToEgg {
+public:
+  XFileToEgg();
+
+  void run();
+};
+
+#endif
+

+ 713 - 0
pandatool/src/xfile/xFileToEggConverter.cxx

@@ -0,0 +1,713 @@
+// Filename: xFileToEggConverter.cxx
+// Created by:  drose (21Jun01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "xFileToEggConverter.h"
+#include "xFileMesh.h"
+#include "xFileMaterial.h"
+#include "eggData.h"
+#include "eggGroup.h"
+#include "datagram.h"
+
+// This must be included only in exactly one .cxx file, since
+// including defines the structure!
+#include <rmxftmpl.h>
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileToEggConverter::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+XFileToEggConverter::
+XFileToEggConverter() {
+  _dx_file = NULL;
+  _dx_file_enum = NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileToEggConverter::Copy Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+XFileToEggConverter::
+XFileToEggConverter(const XFileToEggConverter &copy) :
+  SomethingToEggConverter(copy)
+{
+  _dx_file = NULL;
+  _dx_file_enum = NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileToEggConverter::Destructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+XFileToEggConverter::
+~XFileToEggConverter() {
+  close();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileToEggConverter::make_copy
+//       Access: Public, Virtual
+//  Description: Allocates and returns a new copy of the converter.
+////////////////////////////////////////////////////////////////////
+SomethingToEggConverter *XFileToEggConverter::
+make_copy() {
+  return new XFileToEggConverter(*this);
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileToEggConverter::get_name
+//       Access: Public, Virtual
+//  Description: Returns the English name of the file type this
+//               converter supports.
+////////////////////////////////////////////////////////////////////
+string XFileToEggConverter::
+get_name() const {
+  return "DirectX";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileToEggConverter::get_extension
+//       Access: Public, Virtual
+//  Description: Returns the common extension of the file type this
+//               converter supports.
+////////////////////////////////////////////////////////////////////
+string XFileToEggConverter::
+get_extension() const {
+  return "x";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileToEggConverter::convert_file
+//       Access: Public, Virtual
+//  Description: Handles the reading of the input file and converting
+//               it to egg.  Returns true if successful, false
+//               otherwise.
+//
+//               This is designed to be as generic as possible,
+//               generally in support of run-time loading.
+//               Command-line converters may choose to use
+//               convert_flt() instead, as it provides more control.
+////////////////////////////////////////////////////////////////////
+bool XFileToEggConverter::
+convert_file(const Filename &filename) {
+  HRESULT hr;
+
+  close();
+  hr = DirectXFileCreate(&_dx_file);
+  if (hr != DXFILE_OK) {
+    nout << "Unable to create X interface.\n";
+    return false;
+  }
+
+  // Register our templates.
+  hr = _dx_file->RegisterTemplates(D3DRM_XTEMPLATES, D3DRM_XTEMPLATE_BYTES);
+  if (hr != DXFILE_OK) {
+    nout << "Unable to register templates.\n";
+    return false;
+  }
+
+  string os_file = filename.to_os_specific();
+  hr = _dx_file->CreateEnumObject
+    ((void *)os_file.c_str(), DXFILELOAD_FROMFILE, &_dx_file_enum);
+  if (hr != DXFILE_OK) {
+    nout << "Unable to open X file: " << os_file << "\n";
+    return false;
+  }
+
+  return get_toplevel();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileToEggConverter::close
+//       Access: Public
+//  Description: Finalizes and closes the file previously opened via
+//               convert_file().
+////////////////////////////////////////////////////////////////////
+void XFileToEggConverter::
+close() {
+  if (_dx_file != NULL) {
+    if (_dx_file_enum != NULL) {
+      _dx_file_enum->Release();
+      _dx_file_enum = NULL;
+    }
+    _dx_file->Release();
+    _dx_file = NULL;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileToEggConverter::get_toplevel
+//       Access: Private
+//  Description: Pulls off all of the top-level objects in the .x file
+//               and converts them, and their descendents, to the
+//               appropriate egg structures.
+////////////////////////////////////////////////////////////////////
+bool XFileToEggConverter::
+get_toplevel() {
+  HRESULT hr;
+  LPDIRECTXFILEDATA obj;
+
+  hr = _dx_file_enum->GetNextDataObject(&obj);
+  while (hr == DXFILE_OK) {
+    if (!convert_data_object(obj, _egg_data)) {
+      return false;
+    }
+    hr = _dx_file_enum->GetNextDataObject(&obj);
+  }
+
+  if (hr != DXFILEERR_NOMOREOBJECTS) {
+    cerr << "Error extracting top-level objects.\n";
+    return false;
+  }
+
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileToEggConverter::convert_object
+//       Access: Private
+//  Description: Converts the indicated object to the appropriate egg
+//               structures.
+////////////////////////////////////////////////////////////////////
+bool XFileToEggConverter::
+convert_object(LPDIRECTXFILEOBJECT obj, EggGroupNode *egg_parent) {
+  HRESULT hr;
+  LPDIRECTXFILEDATA data_obj;
+
+  // See if the object is a data object.
+  hr = obj->QueryInterface(IID_IDirectXFileData, (void **)&data_obj);
+  if (hr == DD_OK) {
+    // It is.
+    return convert_data_object(data_obj, egg_parent);
+  }
+
+  // It isn't.
+  cerr << "Ignoring object of unknown type: " << get_object_name(obj)
+       << "\n";
+  return true;
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileToEggConverter::convert_data_object
+//       Access: Private
+//  Description: Converts the indicated object to the appropriate egg
+//               structures.
+////////////////////////////////////////////////////////////////////
+bool XFileToEggConverter::
+convert_data_object(LPDIRECTXFILEDATA obj, EggGroupNode *egg_parent) {
+  HRESULT hr;
+
+  // Determine what type of data object we have.
+  const GUID *type;
+  hr = obj->GetType(&type);
+  if (hr != DXFILE_OK) {
+    cerr << "Unable to get type of template\n";
+    return false;
+  }
+
+  if (*type == TID_D3DRMFrame) {
+    if (!convert_frame(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";
+  }
+  
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileToEggConverter::convert_frame
+//       Access: Private
+//  Description: Converts the indicated frame to the appropriate egg
+//               structures.
+////////////////////////////////////////////////////////////////////
+bool XFileToEggConverter::
+convert_frame(LPDIRECTXFILEDATA obj, EggGroupNode *egg_parent) {
+  HRESULT hr;
+
+  string name = get_object_name(obj);
+  EggGroup *group = new EggGroup(name);
+  egg_parent->add_child(group);
+
+  // Now walk through the children of the frame.
+  LPDIRECTXFILEOBJECT child_obj;
+
+  hr = obj->GetNextObject(&child_obj);
+  while (hr == DXFILE_OK) {
+    if (!convert_object(child_obj, group)) {
+      return false;
+    }
+    hr = obj->GetNextObject(&child_obj);
+  }
+
+  if (hr != DXFILEERR_NOMOREOBJECTS) {
+    cerr << "Error extracting children of frame " << name << ".\n";
+    return false;
+  }
+
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileToEggConverter::convert_mesh
+//       Access: Private
+//  Description: Converts the indicated mesh to the appropriate egg
+//               structures.
+////////////////////////////////////////////////////////////////////
+bool XFileToEggConverter::
+convert_mesh(LPDIRECTXFILEDATA obj, EggGroupNode *egg_parent) {
+  HRESULT hr;
+
+  Datagram raw_data;
+  if (!get_data(obj, raw_data)) {
+    return false;
+  }
+
+  XFileMesh mesh;
+  mesh.set_name(get_object_name(obj));
+  if (!mesh.read_mesh_data(raw_data)) {
+    return false;
+  }
+
+  // Now process all the child objects of the mesh.
+  LPDIRECTXFILEOBJECT child_obj;
+
+  hr = obj->GetNextObject(&child_obj);
+  while (hr == DXFILE_OK) {
+    if (!convert_mesh_object(child_obj, mesh)) {
+      return false;
+    }
+    hr = obj->GetNextObject(&child_obj);
+  }
+
+  if (hr != DXFILEERR_NOMOREOBJECTS) {
+    cerr << "Error extracting children of mesh " << get_object_name(obj)
+         << ".\n";
+    return false;
+  }
+
+  if (!mesh.create_polygons(egg_parent, _textures, _materials)) {
+    return false;
+  }
+
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileToEggConverter::convert_mesh_object
+//       Access: Private
+//  Description: Converts the indicated object, a child of a Mesh, to
+//               the appropriate egg structures.
+////////////////////////////////////////////////////////////////////
+bool XFileToEggConverter::
+convert_mesh_object(LPDIRECTXFILEOBJECT obj, XFileMesh &mesh) {
+  HRESULT hr;
+  LPDIRECTXFILEDATA data_obj;
+
+  // See if the object is a data object.
+  hr = obj->QueryInterface(IID_IDirectXFileData, (void **)&data_obj);
+  if (hr == DD_OK) {
+    // It is.
+    return convert_mesh_data_object(data_obj, mesh);
+  }
+
+  // It isn't.
+  cerr << "Ignoring object of unknown type: " << get_object_name(obj)
+       << "\n";
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileToEggConverter::convert_mesh_data_object
+//       Access: Private
+//  Description: Converts the indicated data object, a child of a
+//               Mesh, to the appropriate egg structures.
+////////////////////////////////////////////////////////////////////
+bool XFileToEggConverter::
+convert_mesh_data_object(LPDIRECTXFILEDATA obj, XFileMesh &mesh) {
+  HRESULT hr;
+
+  // Determine what type of data object we have.
+  const GUID *type;
+  hr = obj->GetType(&type);
+  if (hr != DXFILE_OK) {
+    cerr << "Unable to get type of template\n";
+    return false;
+  }
+
+  if (*type == TID_D3DRMMeshNormals) {
+    if (!convert_mesh_normals(obj, mesh)) {
+      return false;
+    }
+
+  } else if (*type == TID_D3DRMMeshVertexColors) {
+    if (!convert_mesh_colors(obj, mesh)) {
+      return false;
+    }
+
+  } else if (*type == TID_D3DRMMeshTextureCoords) {
+    if (!convert_mesh_uvs(obj, mesh)) {
+      return false;
+    }
+
+  } else if (*type == TID_D3DRMMeshMaterialList) {
+    if (!convert_mesh_material_list(obj, mesh)) {
+      return false;
+    }
+
+  } else {
+    cerr << "Ignoring data object of unknown type: " << get_object_name(obj)
+         << "\n";
+  }
+  
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileToEggConverter::convert_mesh_normals
+//       Access: Private
+//  Description: Converts the indicated MeshNormals template
+//               object.
+////////////////////////////////////////////////////////////////////
+bool XFileToEggConverter::
+convert_mesh_normals(LPDIRECTXFILEDATA obj, XFileMesh &mesh) {
+  Datagram raw_data;
+  if (!get_data(obj, raw_data)) {
+    return false;
+  }
+
+  if (!mesh.read_normal_data(raw_data)) {
+    return false;
+  }
+
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileToEggConverter::convert_mesh_colors
+//       Access: Private
+//  Description: Converts the indicated MeshVertexColors template
+//               object.
+////////////////////////////////////////////////////////////////////
+bool XFileToEggConverter::
+convert_mesh_colors(LPDIRECTXFILEDATA obj, XFileMesh &mesh) {
+  Datagram raw_data;
+  if (!get_data(obj, raw_data)) {
+    return false;
+  }
+
+  if (!mesh.read_color_data(raw_data)) {
+    return false;
+  }
+
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileToEggConverter::convert_mesh_uvs
+//       Access: Private
+//  Description: Converts the indicated MeshTextureCoords template
+//               object.
+////////////////////////////////////////////////////////////////////
+bool XFileToEggConverter::
+convert_mesh_uvs(LPDIRECTXFILEDATA obj, XFileMesh &mesh) {
+  Datagram raw_data;
+  if (!get_data(obj, raw_data)) {
+    return false;
+  }
+
+  if (!mesh.read_uv_data(raw_data)) {
+    return false;
+  }
+
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileToEggConverter::convert_mesh_material_list
+//       Access: Private
+//  Description: Converts the indicated MeshMaterialList template
+//               object.
+////////////////////////////////////////////////////////////////////
+bool XFileToEggConverter::
+convert_mesh_material_list(LPDIRECTXFILEDATA obj, XFileMesh &mesh) {
+  HRESULT hr;
+
+  Datagram raw_data;
+  if (!get_data(obj, raw_data)) {
+    return false;
+  }
+
+  if (!mesh.read_material_list_data(raw_data)) {
+    return false;
+  }
+
+  // Now we need to process the children of the material list.  These
+  // will be the materials.
+  LPDIRECTXFILEOBJECT child_obj;
+
+  hr = obj->GetNextObject(&child_obj);
+  while (hr == DXFILE_OK) {
+    if (!convert_material_list_object(child_obj, mesh)) {
+      return false;
+    }
+    hr = obj->GetNextObject(&child_obj);
+  }
+
+  if (hr != DXFILEERR_NOMOREOBJECTS) {
+    cerr << "Error extracting children of MeshMaterialList "
+         << get_object_name(obj) << ".\n";
+    return false;
+  }
+
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileToEggConverter::convert_material_list_object
+//       Access: Private
+//  Description: Converts the indicated object, a child of a
+//               MeshMaterialList.
+////////////////////////////////////////////////////////////////////
+bool XFileToEggConverter::
+convert_material_list_object(LPDIRECTXFILEOBJECT obj, XFileMesh &mesh) {
+  HRESULT hr;
+  LPDIRECTXFILEDATA data_obj;
+
+  // See if the object is a data object.
+  hr = obj->QueryInterface(IID_IDirectXFileData, (void **)&data_obj);
+  if (hr == DD_OK) {
+    // It is.
+    return convert_material_list_data_object(data_obj, mesh);
+  }
+
+  // It isn't.
+  cerr << "Ignoring object of unknown type: " << get_object_name(obj)
+       << "\n";
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileToEggConverter::convert_material_list_data_object
+//       Access: Private
+//  Description: Converts the indicated data object, a child of a
+//               MeshMaterialList.
+////////////////////////////////////////////////////////////////////
+bool XFileToEggConverter::
+convert_material_list_data_object(LPDIRECTXFILEDATA obj, XFileMesh &mesh) {
+  HRESULT hr;
+
+  // Determine what type of data object we have.
+  const GUID *type;
+  hr = obj->GetType(&type);
+  if (hr != DXFILE_OK) {
+    cerr << "Unable to get type of template\n";
+    return false;
+  }
+
+  if (*type == TID_D3DRMMaterial) {
+    if (!convert_material(obj, mesh)) {
+      return false;
+    }
+  } else {
+    cerr << "Ignoring data object of unknown type: " << get_object_name(obj)
+         << "\n";
+  }
+  
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileToEggConverter::convert_material
+//       Access: Private
+//  Description: Converts the indicated Material template object.
+////////////////////////////////////////////////////////////////////
+bool XFileToEggConverter::
+convert_material(LPDIRECTXFILEDATA obj, XFileMesh &mesh) {
+  HRESULT hr;
+
+  Datagram raw_data;
+  if (!get_data(obj, raw_data)) {
+    return false;
+  }
+
+  XFileMaterial *material = new XFileMaterial;
+
+  if (!material->read_material_data(raw_data)) {
+    delete material;
+    return false;
+  }
+
+  mesh.add_material(material);
+
+  // Now we need to process the children of the material.  There
+  // should only be one, and it will be a texture.
+  LPDIRECTXFILEOBJECT child_obj;
+
+  hr = obj->GetNextObject(&child_obj);
+  while (hr == DXFILE_OK) {
+    if (!convert_material_object(child_obj, *material)) {
+      return false;
+    }
+    hr = obj->GetNextObject(&child_obj);
+  }
+
+  if (hr != DXFILEERR_NOMOREOBJECTS) {
+    cerr << "Error extracting children of Material " 
+         << get_object_name(obj) << ".\n";
+    return false;
+  }
+
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileToEggConverter::convert_material_object
+//       Access: Private
+//  Description: Converts the indicated object, a child of a
+//               Material.
+////////////////////////////////////////////////////////////////////
+bool XFileToEggConverter::
+convert_material_object(LPDIRECTXFILEOBJECT obj, XFileMaterial &material) {
+  HRESULT hr;
+  LPDIRECTXFILEDATA data_obj;
+
+  // See if the object is a data object.
+  hr = obj->QueryInterface(IID_IDirectXFileData, (void **)&data_obj);
+  if (hr == DD_OK) {
+    // It is.
+    return convert_material_data_object(data_obj, material);
+  }
+
+  // It isn't.
+  cerr << "Ignoring object of unknown type: " << get_object_name(obj)
+       << "\n";
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileToEggConverter::convert_material_data_object
+//       Access: Private
+//  Description: Converts the indicated data object, a child of a
+//               Material.
+////////////////////////////////////////////////////////////////////
+bool XFileToEggConverter::
+convert_material_data_object(LPDIRECTXFILEDATA obj, XFileMaterial &material) {
+  HRESULT hr;
+
+  // Determine what type of data object we have.
+  const GUID *type;
+  hr = obj->GetType(&type);
+  if (hr != DXFILE_OK) {
+    cerr << "Unable to get type of template\n";
+    return false;
+  }
+
+  if (*type == TID_D3DRMTextureFilename) {
+    if (!convert_texture(obj, material)) {
+      return false;
+    }
+  } else {
+    cerr << "Ignoring data object of unknown type: " << get_object_name(obj)
+         << "\n";
+  }
+  
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileToEggConverter::convert_texture
+//       Access: Private
+//  Description: Converts the indicated TextureFilename template object.
+////////////////////////////////////////////////////////////////////
+bool XFileToEggConverter::
+convert_texture(LPDIRECTXFILEDATA obj, XFileMaterial &material) {
+  Datagram raw_data;
+  if (!get_data(obj, raw_data)) {
+    return false;
+  }
+
+  if (!material.read_texture_data(raw_data)) {
+    return false;
+  }
+
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileToEggConverter::get_object_name
+//       Access: Private
+//  Description: Returns the name of the indicated object.
+////////////////////////////////////////////////////////////////////
+string XFileToEggConverter::
+get_object_name(LPDIRECTXFILEOBJECT obj) {
+  HRESULT hr;
+
+  DWORD length = 0;
+  obj->GetName(NULL, &length);
+  
+  if (length == 0) {
+    return string();
+  }
+
+  char *buffer = new char[length];
+  hr = obj->GetName(buffer, &length);
+
+  string result;
+  if (hr != DXFILE_OK) {
+    cerr << "Unable to get object name.\n";
+  } else {
+    result = buffer;
+  }
+
+  delete[] buffer;
+  return result;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileToEggConverter::get_data
+//       Access: Private
+//  Description: Extracts out the raw data for the indicated object.
+////////////////////////////////////////////////////////////////////
+bool XFileToEggConverter::
+get_data(LPDIRECTXFILEDATA obj, Datagram &raw_data) {
+  HRESULT hr;
+  DWORD length;
+  void *data;
+  hr = obj->GetData(NULL, &length, &data);
+  if (hr != DXFILE_OK) {
+    cerr << "Unable to get data for " << get_object_name(obj) << "\n";
+    return false;
+  }
+
+  raw_data.clear();
+  raw_data.append_data(data, length);
+
+  return true;
+}

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

@@ -0,0 +1,87 @@
+// Filename: xFileToEggConverter.h
+// Created by:  drose (21Jun01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 XFILETOEGGCONVERTER_H
+#define XFILETOEGGCONVERTER_H
+
+#include "pandatoolbase.h"
+#include "somethingToEggConverter.h"
+#include "eggTextureCollection.h"
+#include "eggMaterialCollection.h"
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <d3d.h>
+#include <dxfile.h>
+#include <rmxfguid.h>
+#undef WIN32_LEAN_AND_MEAN
+
+class EggGroupNode;
+class Datagram;
+class XFileMesh;
+class XFileMaterial;
+
+////////////////////////////////////////////////////////////////////
+//       Class : XFileToEggConverter
+// Description : 
+////////////////////////////////////////////////////////////////////
+class XFileToEggConverter : public SomethingToEggConverter {
+public:
+  XFileToEggConverter();
+  XFileToEggConverter(const XFileToEggConverter &copy);
+  ~XFileToEggConverter();
+
+  virtual SomethingToEggConverter *make_copy();
+
+  virtual string get_name() const;
+  virtual string get_extension() const;
+
+  virtual bool convert_file(const Filename &filename);
+  void close();
+
+private:
+  bool get_toplevel();
+  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_mesh(LPDIRECTXFILEDATA obj, EggGroupNode *egg_parent);
+
+  bool convert_mesh_object(LPDIRECTXFILEOBJECT obj, XFileMesh &mesh);
+  bool convert_mesh_data_object(LPDIRECTXFILEDATA obj, XFileMesh &mesh);
+  bool convert_mesh_normals(LPDIRECTXFILEDATA obj, XFileMesh &mesh);
+  bool convert_mesh_colors(LPDIRECTXFILEDATA obj, XFileMesh &mesh);
+  bool convert_mesh_uvs(LPDIRECTXFILEDATA obj, XFileMesh &mesh);
+  bool convert_mesh_material_list(LPDIRECTXFILEDATA obj, XFileMesh &mesh);
+  bool convert_material_list_object(LPDIRECTXFILEOBJECT obj, XFileMesh &mesh);
+  bool convert_material_list_data_object(LPDIRECTXFILEDATA obj, XFileMesh &mesh);
+  bool convert_material(LPDIRECTXFILEDATA obj, XFileMesh &mesh);
+  bool convert_material_object(LPDIRECTXFILEOBJECT obj, XFileMaterial &material);
+  bool convert_material_data_object(LPDIRECTXFILEDATA obj, XFileMaterial &material);
+  bool convert_texture(LPDIRECTXFILEDATA obj, XFileMaterial &material);
+
+  string get_object_name(LPDIRECTXFILEOBJECT obj);
+  bool get_data(LPDIRECTXFILEDATA obj, Datagram &raw_data);
+
+  LPDIRECTXFILE _dx_file;
+  LPDIRECTXFILEENUMOBJECT _dx_file_enum;
+
+  EggTextureCollection _textures;
+  EggMaterialCollection _materials;
+};
+
+#endif

+ 30 - 10
pandatool/src/xfile/xFileVertex.cxx

@@ -26,25 +26,45 @@
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 XFileVertex::
 XFileVertex::
-XFileVertex(EggVertex *egg_vertex, EggPrimitive *egg_prim) {
-  _has_color = true;
-  _has_uv = true;
+XFileVertex() {
+  _has_color = false;
+  _has_uv = false;
+  _point.set(0.0, 0.0, 0.0);
+  _uv.set(0.0, 0.0);
+  _color.set(1.0, 1.0, 1.0, 1.0);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileVertex::set_from_egg
+//       Access: Public
+//  Description: Sets the structure up from the indicated egg data.
+////////////////////////////////////////////////////////////////////
+void XFileVertex::
+set_from_egg(EggVertex *egg_vertex, EggPrimitive *egg_prim) {
   _point = LCAST(float, egg_vertex->get_pos3());
   _point = LCAST(float, egg_vertex->get_pos3());
 
 
   if (egg_vertex->has_uv()) {
   if (egg_vertex->has_uv()) {
-    _uv = LCAST(float, egg_vertex->get_uv());
-  } else {
-    _uv.set(0.0, 0.0);
-    _has_uv = false;
+    TexCoordd uv = egg_vertex->get_uv();
+    if (egg_prim->has_texture()) {
+      // Check if there's a texture matrix on the texture.
+      EggTexture *egg_tex = egg_prim->get_texture();
+      if (egg_tex->has_transform()) {
+        uv = uv * egg_tex->get_transform();
+      }
+    }
+
+    _uv[0] = uv[0];
+    // Windows draws the UV's upside-down.
+    _uv[1] = 1.0 - uv[1];
+    _has_uv = true;
   }
   }
 
 
   if (egg_vertex->has_color()) {
   if (egg_vertex->has_color()) {
     _color = egg_vertex->get_color();
     _color = egg_vertex->get_color();
+    _has_color = true;
   } else if (egg_prim->has_color()) {
   } else if (egg_prim->has_color()) {
     _color = egg_prim->get_color();
     _color = egg_prim->get_color();
-  } else {
-    _color.set(1.0, 1.0, 1.0, 1.0);
-    _has_color = false;
+    _has_color = true;
   }
   }
 }
 }
 
 

+ 2 - 1
pandatool/src/xfile/xFileVertex.h

@@ -32,7 +32,8 @@ class EggPrimitive;
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 class XFileVertex {
 class XFileVertex {
 public:
 public:
-  XFileVertex(EggVertex *egg_vertex, EggPrimitive *egg_poly);
+  XFileVertex();
+  void set_from_egg(EggVertex *egg_vertex, EggPrimitive *egg_poly);
   int compare_to(const XFileVertex &other) const;
   int compare_to(const XFileVertex &other) const;
 
 
   Vertexf _point;
   Vertexf _point;