Browse Source

robustify xfile some more

David Rose 21 years ago
parent
commit
99d7222df4

+ 19 - 1
pandatool/src/xfile/xFileMesh.cxx

@@ -33,7 +33,7 @@
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 XFileMesh::
 XFileMesh::
-XFileMesh() {
+XFileMesh(CoordinateSystem cs) : _cs(cs) {
   _has_normals = false;
   _has_normals = false;
   _has_colors = false;
   _has_colors = false;
   _has_uvs = false;
   _has_uvs = false;
@@ -260,6 +260,13 @@ add_material(XFileMaterial *material) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool XFileMesh::
 bool XFileMesh::
 create_polygons(EggGroupNode *egg_parent, XFileToEggConverter *converter) {
 create_polygons(EggGroupNode *egg_parent, XFileToEggConverter *converter) {
+  if (has_name()) {
+    // Put a named mesh within its own group.
+    EggGroup *egg_group = new EggGroup(get_name());
+    egg_parent->add_child(egg_group);
+    egg_parent = egg_group;
+  }
+
   EggVertexPool *vpool = new EggVertexPool(get_name());
   EggVertexPool *vpool = new EggVertexPool(get_name());
   egg_parent->add_child(vpool);
   egg_parent->add_child(vpool);
   Faces::const_iterator fi;
   Faces::const_iterator fi;
@@ -302,6 +309,10 @@ create_polygons(EggGroupNode *egg_parent, XFileToEggConverter *converter) {
         temp_vtx.set_normal(LCAST(double, normal->_normal));
         temp_vtx.set_normal(LCAST(double, normal->_normal));
       }
       }
 
 
+      // Transform the vertex into the appropriate (global) coordinate
+      // space.
+      temp_vtx.transform(egg_parent->get_node_to_vertex());
+
       // Now get a real EggVertex matching our template.
       // Now get a real EggVertex matching our template.
       EggVertex *egg_vtx = vpool->create_unique_vertex(temp_vtx);
       EggVertex *egg_vtx = vpool->create_unique_vertex(temp_vtx);
       egg_poly->add_vertex(egg_vtx);
       egg_poly->add_vertex(egg_vtx);
@@ -315,6 +326,13 @@ create_polygons(EggGroupNode *egg_parent, XFileToEggConverter *converter) {
     }
     }
   }
   }
 
 
+  if (!has_normals()) {
+    // If we don't have explicit normals, make some up, per the DX
+    // spec.  Since the DX spec doesn't mention anything about a
+    // crease angle, we should be as generous as possible.
+    egg_parent->recompute_vertex_normals(180.0, _cs);
+  }
+
   return true;
   return true;
 }
 }
 
 

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

@@ -24,6 +24,7 @@
 #include "pmap.h"
 #include "pmap.h"
 #include "indirectCompareTo.h"
 #include "indirectCompareTo.h"
 #include "namable.h"
 #include "namable.h"
+#include "coordinateSystem.h"
 
 
 class XFileMesh;
 class XFileMesh;
 class XFileVertex;
 class XFileVertex;
@@ -43,7 +44,7 @@ class Datagram;
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 class XFileMesh : public Namable {
 class XFileMesh : public Namable {
 public:
 public:
-  XFileMesh();
+  XFileMesh(CoordinateSystem cs = CS_yup_left);
   ~XFileMesh();
   ~XFileMesh();
 
 
   void clear();
   void clear();
@@ -86,6 +87,8 @@ private:
   typedef pvector<XFileMaterial *> Materials;
   typedef pvector<XFileMaterial *> Materials;
   typedef pvector<XFileFace *> Faces;
   typedef pvector<XFileFace *> Faces;
 
 
+  CoordinateSystem _cs;
+
   Vertices _vertices;
   Vertices _vertices;
   Normals _normals;
   Normals _normals;
   Materials _materials;
   Materials _materials;

+ 102 - 3
pandatool/src/xfile/xFileToEggConverter.cxx

@@ -195,9 +195,13 @@ get_toplevel() {
   HRESULT hr;
   HRESULT hr;
   LPDIRECTXFILEDATA obj;
   LPDIRECTXFILEDATA obj;
 
 
+  PT(EggGroup) egg_toplevel = new EggGroup;
+  bool any_frames = false;
+
   hr = _dx_file_enum->GetNextDataObject(&obj);
   hr = _dx_file_enum->GetNextDataObject(&obj);
   while (hr == DXFILE_OK) {
   while (hr == DXFILE_OK) {
-    if (!convert_data_object(obj, _egg_data)) {
+    if (!convert_toplevel_object(obj, _egg_data,
+                                 egg_toplevel, any_frames)) {
       return false;
       return false;
     }
     }
     hr = _dx_file_enum->GetNextDataObject(&obj);
     hr = _dx_file_enum->GetNextDataObject(&obj);
@@ -209,6 +213,71 @@ get_toplevel() {
     return false;
     return false;
   }
   }
 
 
+  if (!any_frames) {
+    // If the file contained no frames at all, then all of the meshes
+    // that appeared at the toplevel were meant to be directly
+    // included.
+    _egg_data->steal_children(*egg_toplevel);
+  }
+
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileToEggConverter::convert_toplevel_object
+//       Access: Private
+//  Description: Converts the indicated object, encountered outside of
+//               any Frames, to the appropriate egg structures.
+////////////////////////////////////////////////////////////////////
+bool XFileToEggConverter::
+convert_toplevel_object(LPDIRECTXFILEDATA obj, EggGroupNode *egg_parent,
+                        EggGroupNode *egg_toplevel, bool &any_frames) {
+  HRESULT hr;
+
+  // Determine what type of data object we have.
+  const GUID *type;
+  hr = obj->GetType(&type);
+  if (hr != DXFILE_OK) {
+    xfile_cat.error()
+      << "Unable to get type of template\n";
+    return false;
+  }
+
+  if (*type == mydef_TID_D3DRMHeader) {
+    // Quietly ignore headers.
+
+  } else if (*type == TID_D3DRMMaterial) {
+    // Quietly ignore toplevel materials.  These will presumably be
+    // referenced below.
+
+  } else if (*type == TID_D3DRMFrame) {
+    any_frames = true;
+    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) {
+    // Assume a Mesh at the toplevel is just present to define a
+    // reference that will be included below.  Convert it into the
+    // egg_toplevel group, where it will be ignored unless there are
+    // no frames at all in the file.
+    if (!convert_mesh(obj, egg_toplevel)) {
+      return false;
+    }
+
+  } else {
+    if (xfile_cat.is_debug()) {
+      xfile_cat.debug()
+        << "Ignoring toplevel object of unknown type: "
+        << get_object_name(obj) << "\n";
+    }
+  }
+  
   return true;
   return true;
 }
 }
 
 
@@ -222,6 +291,7 @@ bool XFileToEggConverter::
 convert_object(LPDIRECTXFILEOBJECT obj, EggGroupNode *egg_parent) {
 convert_object(LPDIRECTXFILEOBJECT obj, EggGroupNode *egg_parent) {
   HRESULT hr;
   HRESULT hr;
   LPDIRECTXFILEDATA data_obj;
   LPDIRECTXFILEDATA data_obj;
+  LPDIRECTXFILEDATAREFERENCE ref_obj;
 
 
   // See if the object is a data object.
   // See if the object is a data object.
   hr = obj->QueryInterface(IID_IDirectXFileData, (void **)&data_obj);
   hr = obj->QueryInterface(IID_IDirectXFileData, (void **)&data_obj);
@@ -230,6 +300,15 @@ convert_object(LPDIRECTXFILEOBJECT obj, EggGroupNode *egg_parent) {
     return convert_data_object(data_obj, egg_parent);
     return convert_data_object(data_obj, egg_parent);
   }
   }
 
 
+  // Or maybe it's a reference to a previous object.
+  hr = obj->QueryInterface(IID_IDirectXFileDataReference, (void **)&ref_obj);
+  if (hr == DD_OK) {
+    // It is.
+    if (ref_obj->Resolve(&data_obj) == DXFILE_OK) {
+      return convert_data_object(data_obj, egg_parent);
+    }
+  }
+
   // It isn't.
   // It isn't.
   if (xfile_cat.is_debug()) {
   if (xfile_cat.is_debug()) {
     xfile_cat.debug()
     xfile_cat.debug()
@@ -345,7 +424,7 @@ convert_transform(LPDIRECTXFILEDATA obj, EggGroupNode *egg_parent) {
   if (egg_parent->is_of_type(EggGroup::get_class_type())) {
   if (egg_parent->is_of_type(EggGroup::get_class_type())) {
     EggGroup *egg_group = DCAST(EggGroup, egg_parent);
     EggGroup *egg_group = DCAST(EggGroup, egg_parent);
     egg_group->set_transform(LCAST(double, mat));
     egg_group->set_transform(LCAST(double, mat));
-    egg_group->set_group_type(EggGroup::GT_instance);
+
   } else {
   } else {
     xfile_cat.error()
     xfile_cat.error()
       << "Transform " << get_object_name(obj)
       << "Transform " << get_object_name(obj)
@@ -370,7 +449,7 @@ convert_mesh(LPDIRECTXFILEDATA obj, EggGroupNode *egg_parent) {
     return false;
     return false;
   }
   }
 
 
-  XFileMesh mesh;
+  XFileMesh mesh(_egg_data->get_coordinate_system());
   mesh.set_name(get_object_name(obj));
   mesh.set_name(get_object_name(obj));
   if (!mesh.read_mesh_data(raw_data)) {
   if (!mesh.read_mesh_data(raw_data)) {
     return false;
     return false;
@@ -411,6 +490,7 @@ bool XFileToEggConverter::
 convert_mesh_object(LPDIRECTXFILEOBJECT obj, XFileMesh &mesh) {
 convert_mesh_object(LPDIRECTXFILEOBJECT obj, XFileMesh &mesh) {
   HRESULT hr;
   HRESULT hr;
   LPDIRECTXFILEDATA data_obj;
   LPDIRECTXFILEDATA data_obj;
+  LPDIRECTXFILEDATAREFERENCE ref_obj;
 
 
   // See if the object is a data object.
   // See if the object is a data object.
   hr = obj->QueryInterface(IID_IDirectXFileData, (void **)&data_obj);
   hr = obj->QueryInterface(IID_IDirectXFileData, (void **)&data_obj);
@@ -419,6 +499,15 @@ convert_mesh_object(LPDIRECTXFILEOBJECT obj, XFileMesh &mesh) {
     return convert_mesh_data_object(data_obj, mesh);
     return convert_mesh_data_object(data_obj, mesh);
   }
   }
 
 
+  // Or maybe it's a reference to a previous object.
+  hr = obj->QueryInterface(IID_IDirectXFileDataReference, (void **)&ref_obj);
+  if (hr == DD_OK) {
+    // It is.
+    if (ref_obj->Resolve(&data_obj) == DXFILE_OK) {
+      return convert_mesh_data_object(data_obj, mesh);
+    }
+  }
+
   // It isn't.
   // It isn't.
   if (xfile_cat.is_debug()) {
   if (xfile_cat.is_debug()) {
     xfile_cat.debug()
     xfile_cat.debug()
@@ -705,6 +794,7 @@ bool XFileToEggConverter::
 convert_material_object(LPDIRECTXFILEOBJECT obj, XFileMaterial &material) {
 convert_material_object(LPDIRECTXFILEOBJECT obj, XFileMaterial &material) {
   HRESULT hr;
   HRESULT hr;
   LPDIRECTXFILEDATA data_obj;
   LPDIRECTXFILEDATA data_obj;
+  LPDIRECTXFILEDATAREFERENCE ref_obj;
 
 
   // See if the object is a data object.
   // See if the object is a data object.
   hr = obj->QueryInterface(IID_IDirectXFileData, (void **)&data_obj);
   hr = obj->QueryInterface(IID_IDirectXFileData, (void **)&data_obj);
@@ -713,6 +803,15 @@ convert_material_object(LPDIRECTXFILEOBJECT obj, XFileMaterial &material) {
     return convert_material_data_object(data_obj, material);
     return convert_material_data_object(data_obj, material);
   }
   }
 
 
+  // Or maybe it's a reference to a previous object.
+  hr = obj->QueryInterface(IID_IDirectXFileDataReference, (void **)&ref_obj);
+  if (hr == DD_OK) {
+    // It is.
+    if (ref_obj->Resolve(&data_obj) == DXFILE_OK) {
+      return convert_material_data_object(data_obj, material);
+    }
+  }
+
   // It isn't.
   // It isn't.
   if (xfile_cat.is_debug()) {
   if (xfile_cat.is_debug()) {
     xfile_cat.debug()
     xfile_cat.debug()

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

@@ -61,6 +61,8 @@ public:
 
 
 private:
 private:
   bool get_toplevel();
   bool get_toplevel();
+  bool convert_toplevel_object(LPDIRECTXFILEDATA obj, EggGroupNode *egg_parent,
+                               EggGroupNode *egg_toplevel, bool &any_frames);
   bool convert_object(LPDIRECTXFILEOBJECT obj, EggGroupNode *egg_parent);
   bool convert_object(LPDIRECTXFILEOBJECT obj, EggGroupNode *egg_parent);
   bool convert_data_object(LPDIRECTXFILEDATA obj, EggGroupNode *egg_parent);
   bool convert_data_object(LPDIRECTXFILEDATA obj, EggGroupNode *egg_parent);
   bool convert_frame(LPDIRECTXFILEDATA obj, EggGroupNode *egg_parent);
   bool convert_frame(LPDIRECTXFILEDATA obj, EggGroupNode *egg_parent);