Browse Source

egg2x now uses native parser

David Rose 21 years ago
parent
commit
bcbe9bb30c

+ 24 - 0
pandatool/src/xfile/xFile.cxx

@@ -244,6 +244,30 @@ find_template(const WindowsGuid &guid) const {
   return NULL;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: XFile::find_standard_template
+//       Access: Public, Static
+//  Description: Returns the standard template associated with the
+//               indicated name, if any, or NULL if none.
+////////////////////////////////////////////////////////////////////
+XFileTemplate *XFile::
+find_standard_template(const string &name) {
+  const XFile *standard_templates = get_standard_templates();
+  return standard_templates->find_template(name);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFile::find_standard_template
+//       Access: Public, Static
+//  Description: Returns the template associated with the indicated
+//               GUID, if any, or NULL if none.
+////////////////////////////////////////////////////////////////////
+XFileTemplate *XFile::
+find_standard_template(const WindowsGuid &guid) {
+  const XFile *standard_templates = get_standard_templates();
+  return standard_templates->find_template(guid);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: XFile::find_data_object
 //       Access: Public

+ 4 - 0
pandatool/src/xfile/xFile.h

@@ -21,6 +21,7 @@
 
 #include "pandatoolbase.h"
 #include "xFileNode.h"
+#include "xFileDataNode.h"
 #include "windowsGuid.h"
 #include "filename.h"
 #include "pmap.h"
@@ -51,6 +52,9 @@ public:
   XFileTemplate *find_template(const string &name) const;
   XFileTemplate *find_template(const WindowsGuid &guid) const;
 
+  static XFileTemplate *find_standard_template(const string &name);
+  static XFileTemplate *find_standard_template(const WindowsGuid &guid);
+
   XFileDataNodeTemplate *find_data_object(const string &name) const;
   XFileDataNodeTemplate *find_data_object(const WindowsGuid &guid) const;
 

+ 131 - 0
pandatool/src/xfile/xFileDataDef.cxx

@@ -208,6 +208,51 @@ repack_data(XFileDataObject *object,
                                 prev_data, index, sub_index);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: XFileDataDef::fill_zero_data
+//       Access: Public, Virtual
+//  Description: This is similar to repack_data(), except it is used
+//               to fill the initial values for a newly-created
+//               template object to zero.
+////////////////////////////////////////////////////////////////////
+bool XFileDataDef::
+fill_zero_data(XFileDataObject *object) const {
+  PT(XFileDataObject) data_value;
+
+  // What kind of data element are we expecting?
+  switch (_type) {
+  case T_word:
+  case T_dword:
+  case T_char:
+  case T_uchar:
+  case T_sword:
+  case T_sdword:
+    data_value = zero_fill_value(0, &XFileDataDef::zero_fill_integer_value);
+    break;
+
+  case T_float:
+  case T_double:
+    data_value = zero_fill_value(0, &XFileDataDef::zero_fill_double_value);
+    break;
+
+  case T_string:
+  case T_cstring:
+  case T_unicode:
+    data_value = zero_fill_value(0, &XFileDataDef::zero_fill_string_value);
+    break;
+
+  case T_template:
+    data_value = zero_fill_value(0, &XFileDataDef::zero_fill_template_value);
+    break;
+  }
+
+  if (data_value != (XFileDataObject *)NULL) {
+    object->add_element(data_value);
+  }
+
+  return XFileNode::fill_zero_data(object);
+}
+
 
 ////////////////////////////////////////////////////////////////////
 //     Function: XFileDataDef::unpack_integer_value
@@ -368,6 +413,92 @@ unpack_value(const XFileParseDataList &parse_data_list, int array_index,
         unpack_value(parse_data_list, array_index + 1,
                      prev_data, index, sub_index,
                      unpack_method);
+      if (array_element == (XFileDataObject *)NULL) {
+        return NULL;
+      }
+      data_value->add_element(array_element);
+    }
+  }
+
+  return data_value;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileDataDef::zero_fill_integer_value
+//       Access: Private
+//  Description: Returns a newly-allocated zero integer value.
+////////////////////////////////////////////////////////////////////
+PT(XFileDataObject) XFileDataDef::
+zero_fill_integer_value() const {
+  return new XFileDataObjectInteger(this, 0);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileDataDef::zero_fill_double_value
+//       Access: Private
+//  Description: Returns a newly-allocated zero floating-point value.
+////////////////////////////////////////////////////////////////////
+PT(XFileDataObject) XFileDataDef::
+zero_fill_double_value() const {
+  return new XFileDataObjectDouble(this, 0.0);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileDataDef::zero_fill_string_value
+//       Access: Private
+//  Description: Returns a newly-allocated empty string value.
+////////////////////////////////////////////////////////////////////
+PT(XFileDataObject) XFileDataDef::
+zero_fill_string_value() const {
+  return new XFileDataObjectString(this, "");
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileDataDef::zero_fill_template_value
+//       Access: Private
+//  Description: Returns a newly-allocated zero-filled nested template
+//               value.
+////////////////////////////////////////////////////////////////////
+PT(XFileDataObject) XFileDataDef::
+zero_fill_template_value() const {
+  PT(XFileDataObject) data_value = 
+    new XFileDataNodeTemplate(get_x_file(), get_name(), _template);
+  if (!_template->fill_zero_data(data_value)) {
+    return NULL;
+  }
+
+  return data_value;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileDataDef::zero_fill_value
+//       Access: Private
+//  Description: Creates a zero-valued element for the next sequential
+//               value, of the type returned by the zero_fill_method.
+//               If the value is a fixed-size array type, zero-fills
+//               all the elements of the array.
+////////////////////////////////////////////////////////////////////
+PT(XFileDataObject) XFileDataDef::
+zero_fill_value(int array_index, 
+                XFileDataDef::ZeroFillMethod zero_fill_method) const {
+  PT(XFileDataObject) data_value;
+  
+  if (array_index == (int)_array_def.size()) {
+    data_value = (this->*zero_fill_method)();
+
+  } else {
+    data_value = new XFileDataObjectArray(this);
+    int array_size = 0;
+    if (_array_def[array_index].is_fixed_size()) {
+      array_size = _array_def[array_index].get_fixed_size();
+    }
+
+    for (int i = 0; i < array_size; i++) {
+      PT(XFileDataObject) array_element = 
+        zero_fill_value(array_index + 1, zero_fill_method);
+      if (array_element == (XFileDataObject *)NULL) {
+        return NULL;
+      }
       data_value->add_element(array_element);
     }
   }

+ 11 - 0
pandatool/src/xfile/xFileDataDef.h

@@ -73,11 +73,15 @@ public:
                            PrevData &prev_data,
                            size_t &index, size_t &sub_index) const;
 
+  virtual bool fill_zero_data(XFileDataObject *object) const;
+
 private:
   typedef PT(XFileDataObject) 
     (XFileDataDef::*UnpackMethod)(const XFileParseDataList &parse_data_list, 
                                   const PrevData &prev_data,
                                   size_t &index, size_t &sub_index) const;
+  typedef PT(XFileDataObject) 
+    (XFileDataDef::*ZeroFillMethod)() const;
 
   PT(XFileDataObject) 
     unpack_integer_value(const XFileParseDataList &parse_data_list,
@@ -101,6 +105,13 @@ private:
                  const PrevData &prev_data,
                  size_t &index, size_t &sub_index,
                  UnpackMethod unpack_method) const;
+
+  PT(XFileDataObject) zero_fill_integer_value() const;
+  PT(XFileDataObject) zero_fill_double_value() const;
+  PT(XFileDataObject) zero_fill_string_value() const;
+  PT(XFileDataObject) zero_fill_template_value() const;
+  PT(XFileDataObject) 
+    zero_fill_value(int array_index, ZeroFillMethod zero_fill_method) const;
     
 private:
   Type _type;

+ 22 - 7
pandatool/src/xfile/xFileDataNodeTemplate.cxx

@@ -20,6 +20,7 @@
 #include "indent.h"
 #include "xFileParseData.h"
 #include "xLexerDefs.h"
+#include "config_xfile.h"
 
 TypeHandle XFileDataNodeTemplate::_type_handle;
 
@@ -35,6 +36,17 @@ XFileDataNodeTemplate(XFile *x_file, const string &name,
 {
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: XFileDataNodeTemplate::zero_fill
+//       Access: Public
+//  Description: Fills the data node with zero-valued elements
+//               appropriate to the template.
+////////////////////////////////////////////////////////////////////
+void XFileDataNodeTemplate::
+zero_fill() {
+  _template->fill_zero_data(this);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: XFileDataNodeTemplate::is_complex_object
 //       Access: Public, Virtual
@@ -155,9 +167,9 @@ write_text(ostream &out, int indent_level) const {
   }
   out << " {\n";
 
-  int num_elements = get_num_elements();
-  for (int i = 0; i < num_elements; i++) {
-    get_element(i)->write_data(out, indent_level + 2, ";");
+  NestedElements::const_iterator ni;
+  for (ni = _nested_elements.begin(); ni != _nested_elements.end(); ++ni) {
+    (*ni)->write_data(out, indent_level + 2, ";");
   }
 
   XFileNode::write_text(out, indent_level + 2);
@@ -233,8 +245,8 @@ get_num_elements() const {
 //  Description: Returns the nth nested data element within the
 //               object.
 ////////////////////////////////////////////////////////////////////
-const XFileDataObject *XFileDataNodeTemplate::
-get_element(int n) const {
+XFileDataObject *XFileDataNodeTemplate::
+get_element(int n) {
   nassertr(n >= 0 && n < (int)_nested_elements.size(), NULL);
   return _nested_elements[n];
 }
@@ -245,11 +257,14 @@ get_element(int n) const {
 //  Description: Returns the nested data element within the
 //               object that has the indicated name.
 ////////////////////////////////////////////////////////////////////
-const XFileDataObject *XFileDataNodeTemplate::
-get_element(const string &name) const {
+XFileDataObject *XFileDataNodeTemplate::
+get_element(const string &name) {
   int child_index = _template->find_child_index(name);
   if (child_index >= 0) {
     return get_element(child_index);
   }
+  xfile_cat.warning()
+    << "\"" << name << "\" not a member of " << _template->get_name()
+    << "\n";
   return NULL;
 }

+ 3 - 2
pandatool/src/xfile/xFileDataNodeTemplate.h

@@ -39,6 +39,7 @@ class XFileDataNodeTemplate : public XFileDataNode {
 public:
   XFileDataNodeTemplate(XFile *x_file, const string &name,
                         XFileTemplate *xtemplate);
+  void zero_fill();
 
   virtual bool is_complex_object() const;
 
@@ -55,8 +56,8 @@ public:
 
 protected:
   virtual int get_num_elements() const;
-  virtual const XFileDataObject *get_element(int n) const;
-  virtual const XFileDataObject *get_element(const string &name) const;
+  virtual XFileDataObject *get_element(int n);
+  virtual XFileDataObject *get_element(const string &name);
 
 private:
   XFileParseDataList _parse_data_list;

+ 77 - 48
pandatool/src/xfile/xFileDataObject.I

@@ -39,18 +39,55 @@ get_data_def() const {
   return _data_def;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: XFileDataObject::operator = (int)
+//       Access: Public
+//  Description: Stores the indicated integer value into the object,
+//               if it makes sense to do so.  It is an error to call
+//               this on an object that cannot accept an integer value.
+////////////////////////////////////////////////////////////////////
+INLINE void XFileDataObject::
+operator = (int int_value) {
+  set_int_value(int_value);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileDataObject::operator = (double)
+//       Access: Public
+//  Description: Stores the indicated floating-point value into the
+//               object, if it makes sense to do so.  It is an error
+//               to call this on an object that cannot accept a
+//               floating-point value.
+////////////////////////////////////////////////////////////////////
+INLINE void XFileDataObject::
+operator = (double double_value) {
+  set_double_value(double_value);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileDataObject::operator = (string)
+//       Access: Public
+//  Description: Stores the indicated string value into the
+//               object, if it makes sense to do so.  It is an error
+//               to call this on an object that cannot accept a
+//               string value.
+////////////////////////////////////////////////////////////////////
+INLINE void XFileDataObject::
+operator = (const string &string_value) {
+  set_string_value(string_value);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: XFileDataObject::i
 //       Access: Public
 //  Description: Unambiguously returns the object's representation as
 //               an integer, or 0 if the object has no integer
-//               representation.  See also the typecast operators, and
-//               get_data_def() to determine what kind of
-//               representation this object has.
+//               representation.  See also get_data_def() to determine
+//               what kind of representation this object has.
 ////////////////////////////////////////////////////////////////////
 INLINE int XFileDataObject::
 i() const {
-  return as_integer_value();
+  return get_int_value();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -58,13 +95,12 @@ i() const {
 //       Access: Public
 //  Description: Unambiguously returns the object's representation as
 //               a double, or 0.0 if the object has no double
-//               representation.  See also the typecast operators, and
-//               get_data_def() to determine what kind of
-//               representation this object has.
+//               representation.  See also get_data_def() to determine
+//               what kind of representation this object has.
 ////////////////////////////////////////////////////////////////////
 INLINE double XFileDataObject::
 d() const {
-  return as_double_value();
+  return get_double_value();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -72,47 +108,12 @@ d() const {
 //       Access: Public
 //  Description: Unambiguously returns the object's representation as
 //               a string, or empty string if the object has no string
-//               representation.  See also the typecast operators, and
-//               get_data_def() to determine what kind of
-//               representation this object has.
+//               representation.  See also get_data_def() to determine
+//               what kind of representation this object has.
 ////////////////////////////////////////////////////////////////////
 INLINE string XFileDataObject::
 s() const {
-  return as_string_value();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: XFileDataObject::int typecast operator
-//       Access: Public
-//  Description: Returns the object's representation as an integer, or
-//               0 if the object has no integer representation.
-////////////////////////////////////////////////////////////////////
-INLINE XFileDataObject::
-operator int () const {
-  return as_integer_value();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: XFileDataObject::double typecast operator
-//       Access: Public
-//  Description: Returns the object's representation as a double, or
-//               0.0 if the object has no integer representation.
-////////////////////////////////////////////////////////////////////
-INLINE XFileDataObject::
-operator double () const {
-  return as_double_value();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: XFileDataObject::string typecast operator
-//       Access: Public
-//  Description: Returns the object's representation as a string, or
-//               empty string if the object has no string
-//               representation.
-////////////////////////////////////////////////////////////////////
-INLINE XFileDataObject::
-operator string () const {
-  return as_string_value();
+  return get_string_value();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -135,7 +136,7 @@ size() const {
 ////////////////////////////////////////////////////////////////////
 INLINE const XFileDataObject &XFileDataObject::
 operator [] (int n) const {
-  const XFileDataObject *element = get_element(n);
+  const XFileDataObject *element = ((XFileDataObject *)this)->get_element(n);
   nassertr(element != (XFileDataObject *)NULL, *this);
   return *element;
 }
@@ -149,7 +150,35 @@ operator [] (int n) const {
 ////////////////////////////////////////////////////////////////////
 INLINE const XFileDataObject &XFileDataObject::
 operator [] (const string &name) const {
-  const XFileDataObject *element = get_element(name);
+  const XFileDataObject *element = ((XFileDataObject *)this)->get_element(name);
+  nassertr(element != (XFileDataObject *)NULL, *this);
+  return *element;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileDataObject::operator [] (int)
+//       Access: Public
+//  Description: Returns the nth nested object within this object.
+//               Call get_num_children() to determine the number of
+//               nested objects.
+////////////////////////////////////////////////////////////////////
+INLINE XFileDataObject &XFileDataObject::
+operator [] (int n) {
+  XFileDataObject *element = get_element(n);
+  nassertr(element != (XFileDataObject *)NULL, *this);
+  return *element;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileDataObject::operator [] (string)
+//       Access: Public
+//  Description: Returns the named nested object within this object.
+//               It is an error if the named object does not exist.
+//               Call find_child() instead if there is any doubt.
+////////////////////////////////////////////////////////////////////
+INLINE XFileDataObject &XFileDataObject::
+operator [] (const string &name) {
+  XFileDataObject *element = get_element(name);
   nassertr(element != (XFileDataObject *)NULL, *this);
   return *element;
 }

+ 188 - 10
pandatool/src/xfile/xFileDataObject.cxx

@@ -17,6 +17,13 @@
 ////////////////////////////////////////////////////////////////////
 
 #include "xFileDataObject.h"
+#include "xFileTemplate.h"
+#include "xFile.h"
+#include "xFileDataNodeTemplate.h"
+#include "xFileDataObjectInteger.h"
+#include "xFileDataObjectDouble.h"
+#include "xFileDataObjectString.h"
+#include "config_xfile.h"
 #include "indent.h"
 
 TypeHandle XFileDataObject::_type_handle;
@@ -42,6 +49,135 @@ is_complex_object() const {
   return false;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: XFileDataObject::add_int
+//       Access: Public
+//  Description: Appends a new integer value to the data object, if it
+//               makes sense to do so.  Normally, this is valid only
+//               for a DataObjectArray, or in certain special cases for
+//               a DataNodeTemplate.
+////////////////////////////////////////////////////////////////////
+XFileDataObject &XFileDataObject::
+add_int(int int_value) {
+  XFileDataObject *object = 
+    new XFileDataObjectInteger(get_data_def(), int_value);
+  add_element(object);
+  return *object;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileDataObject::add_double
+//       Access: Public
+//  Description: Appends a new floating-point value to the data
+//               object, if it makes sense to do so.  Normally, this
+//               is valid only for a DataObjectArray, or in certain
+//               special cases for a DataNodeTemplate.
+////////////////////////////////////////////////////////////////////
+XFileDataObject &XFileDataObject::
+add_double(double double_value) {
+  XFileDataObject *object = 
+    new XFileDataObjectDouble(get_data_def(), double_value);
+  add_element(object);
+  return *object;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileDataObject::add_string
+//       Access: Public
+//  Description: Appends a new string value to the data object, if it
+//               makes sense to do so.  Normally, this is valid only
+//               for a DataObjectArray, or in certain special cases for
+//               a DataNodeTemplate.
+////////////////////////////////////////////////////////////////////
+XFileDataObject &XFileDataObject::
+add_string(const string &string_value) {
+  XFileDataObject *object = 
+    new XFileDataObjectString(get_data_def(), string_value);
+  add_element(object);
+  return *object;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileDataObject::add_Vector
+//       Access: Public
+//  Description: Appends a new Vector instance.
+////////////////////////////////////////////////////////////////////
+XFileDataObject &XFileDataObject::
+add_Vector(XFile *x_file, const LVecBase3d &vector) {
+  XFileTemplate *xtemplate = XFile::find_standard_template("Vector");
+  nassertr(xtemplate != (XFileTemplate *)NULL, *this);
+  XFileDataNodeTemplate *node = 
+    new XFileDataNodeTemplate(x_file, "", xtemplate);
+  add_element(node);
+  node->zero_fill();
+
+  (*node)["x"] = vector[0];
+  (*node)["y"] = vector[1];
+  (*node)["z"] = vector[2];
+
+  return *node;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileDataObject::add_MeshFace
+//       Access: Public
+//  Description: Appends a new MeshFace instance.
+////////////////////////////////////////////////////////////////////
+XFileDataObject &XFileDataObject::
+add_MeshFace(XFile *x_file) {
+  XFileTemplate *xtemplate = XFile::find_standard_template("MeshFace");
+  nassertr(xtemplate != (XFileTemplate *)NULL, *this);
+  XFileDataNodeTemplate *node = 
+    new XFileDataNodeTemplate(x_file, "", xtemplate);
+  add_element(node);
+  node->zero_fill();
+
+  return *node;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileDataObject::add_IndexedColor
+//       Access: Public
+//  Description: Appends a new IndexedColor instance.
+////////////////////////////////////////////////////////////////////
+XFileDataObject &XFileDataObject::
+add_IndexedColor(XFile *x_file, int index, const Colorf &color) {
+  XFileTemplate *xtemplate = XFile::find_standard_template("IndexedColor");
+  nassertr(xtemplate != (XFileTemplate *)NULL, *this);
+  XFileDataNodeTemplate *node = 
+    new XFileDataNodeTemplate(x_file, "", xtemplate);
+  add_element(node);
+  node->zero_fill();
+
+  (*node)["index"] = index;
+  (*node)["indexColor"]["red"] = color[0];
+  (*node)["indexColor"]["green"] = color[1];
+  (*node)["indexColor"]["blue"] = color[2];
+  (*node)["indexColor"]["alpha"] = color[3];
+
+  return *node;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileDataObject::add_Coords2d
+//       Access: Public
+//  Description: Appends a new Coords2d instance.
+////////////////////////////////////////////////////////////////////
+XFileDataObject &XFileDataObject::
+add_Coords2d(XFile *x_file, const LVecBase2d &coords) {
+  XFileTemplate *xtemplate = XFile::find_standard_template("Coords2d");
+  nassertr(xtemplate != (XFileTemplate *)NULL, *this);
+  XFileDataNodeTemplate *node = 
+    new XFileDataNodeTemplate(x_file, "", xtemplate);
+  add_element(node);
+  node->zero_fill();
+
+  (*node)["u"] = coords[0];
+  (*node)["v"] = coords[1];
+
+  return *node;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: XFileDataObject::add_element
 //       Access: Public, Virtual
@@ -79,35 +215,71 @@ write_data(ostream &out, int indent_level, const char *) const {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: XFileDataObject::as_integer_value
+//     Function: XFileDataObject::set_int_value
+//       Access: Protected, Virtual
+//  Description: Sets the object's value as an integer, if this is
+//               legal.
+////////////////////////////////////////////////////////////////////
+void XFileDataObject::
+set_int_value(int int_value) {
+  xfile_cat.error()
+    << get_type() << " does not support integer values.\n";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileDataObject::set_double_value
+//       Access: Protected, Virtual
+//  Description: Sets the object's value as a floating-point number,
+//               if this is legal.
+////////////////////////////////////////////////////////////////////
+void XFileDataObject::
+set_double_value(double double_value) {
+  xfile_cat.error()
+    << get_type() << " does not support floating-point values.\n";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileDataObject::set_string_value
+//       Access: Protected, Virtual
+//  Description: Sets the object's value as a string, if this is
+//               legal.
+////////////////////////////////////////////////////////////////////
+void XFileDataObject::
+set_string_value(const string &string_value) {
+  xfile_cat.error()
+    << get_type() << " does not support stringeger values.\n";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileDataObject::get_int_value
 //       Access: Protected, Virtual
 //  Description: Returns the object's representation as an integer, if
 //               it has one.
 ////////////////////////////////////////////////////////////////////
 int XFileDataObject::
-as_integer_value() const {
+get_int_value() const {
   return 0;
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: XFileDataObject::as_double_value
+//     Function: XFileDataObject::get_double_value
 //       Access: Protected, Virtual
 //  Description: Returns the object's representation as a double, if
 //               it has one.
 ////////////////////////////////////////////////////////////////////
 double XFileDataObject::
-as_double_value() const {
+get_double_value() const {
   return 0.0;
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: XFileDataObject::as_string_value
+//     Function: XFileDataObject::get_string_value
 //       Access: Protected, Virtual
 //  Description: Returns the object's representation as a string, if
 //               it has one.
 ////////////////////////////////////////////////////////////////////
 string XFileDataObject::
-as_string_value() const {
+get_string_value() const {
   return string();
 }
 
@@ -129,8 +301,11 @@ get_num_elements() const {
 //  Description: Returns the nth nested data element within the
 //               object.
 ////////////////////////////////////////////////////////////////////
-const XFileDataObject *XFileDataObject::
-get_element(int n) const {
+XFileDataObject *XFileDataObject::
+get_element(int n) {
+  xfile_cat.warning()
+    << "Looking for [" << n << "] within data object of type " 
+    << get_type() << ", does not support nested objects.\n";
   return NULL;
 }
 
@@ -140,7 +315,10 @@ get_element(int n) const {
 //  Description: Returns the nested data element within the
 //               object that has the indicated name.
 ////////////////////////////////////////////////////////////////////
-const XFileDataObject *XFileDataObject::
-get_element(const string &name) const {
+XFileDataObject *XFileDataObject::
+get_element(const string &name) {
+  xfile_cat.warning()
+    << "Looking for [\"" << name << "\"] within data object of type " 
+    << get_type() << ", does not support nested objects.\n";
   return NULL;
 }

+ 35 - 8
pandatool/src/xfile/xFileDataObject.h

@@ -23,7 +23,9 @@
 #include "referenceCount.h"
 #include "pointerTo.h"
 #include "dcast.h"
+#include "luse.h"
 
+class XFile;
 class XFileDataDef;
 
 ////////////////////////////////////////////////////////////////////
@@ -41,17 +43,38 @@ public:
 
   virtual bool is_complex_object() const;
 
+  INLINE void operator = (int int_value);
+  INLINE void operator = (double double_value);
+  INLINE void operator = (const string &string_value);
+
   INLINE int i() const;
   INLINE double d() const;
   INLINE string s() const;
-  INLINE operator int () const;
-  INLINE operator double () const;
-  INLINE operator string () const;
 
   INLINE int size() const;
   INLINE const XFileDataObject &operator [] (int n) const;
   INLINE const XFileDataObject &operator [] (const string &name) const;
 
+  INLINE XFileDataObject &operator [] (int n);
+  INLINE XFileDataObject &operator [] (const string &name);
+
+  // The following methods can be used to add elements of a specific
+  // type to a complex object, e.g. an array or a template object.
+
+  XFileDataObject &add_int(int int_value);
+  XFileDataObject &add_double(double double_value);
+  XFileDataObject &add_string(const string &string_value);
+
+  // The following methods can be used to add elements of a specific
+  // type, based on one of the standard templates.
+
+  XFileDataObject &add_Vector(XFile *x_file, const LVecBase3d &vector);
+  XFileDataObject &add_MeshFace(XFile *x_file);
+  XFileDataObject &add_IndexedColor(XFile *x_file, int index, 
+                                    const Colorf &color);
+  XFileDataObject &add_Coords2d(XFile *x_file, const LVecBase2d &coords);
+
+public:
   virtual bool add_element(XFileDataObject *element);
 
   virtual void output_data(ostream &out) const;
@@ -59,13 +82,17 @@ public:
                           const char *separator) const;
 
 protected:
-  virtual int as_integer_value() const;
-  virtual double as_double_value() const;
-  virtual string as_string_value() const;
+  virtual void set_int_value(int int_value);
+  virtual void set_double_value(double double_value);
+  virtual void set_string_value(const string &string_value);
+
+  virtual int get_int_value() const;
+  virtual double get_double_value() const;
+  virtual string get_string_value() const;
 
   virtual int get_num_elements() const;
-  virtual const XFileDataObject *get_element(int n) const;
-  virtual const XFileDataObject *get_element(const string &name) const;
+  virtual XFileDataObject *get_element(int n);
+  virtual XFileDataObject *get_element(const string &name);
 
   const XFileDataDef *_data_def;
 

+ 2 - 2
pandatool/src/xfile/xFileDataObjectArray.cxx

@@ -116,8 +116,8 @@ get_num_elements() const {
 //  Description: Returns the nth nested data element within the
 //               object.
 ////////////////////////////////////////////////////////////////////
-const XFileDataObject *XFileDataObjectArray::
-get_element(int n) const {
+XFileDataObject *XFileDataObjectArray::
+get_element(int n) {
   nassertr(n >= 0 && n < (int)_nested_elements.size(), NULL);
   return _nested_elements[n];
 }

+ 1 - 1
pandatool/src/xfile/xFileDataObjectArray.h

@@ -39,7 +39,7 @@ public:
 
 protected:
   virtual int get_num_elements() const;
-  virtual const XFileDataObject *get_element(int n) const;
+  virtual XFileDataObject *get_element(int n);
 
 private:
   typedef pvector< PT(XFileDataObject) > NestedElements;

+ 30 - 8
pandatool/src/xfile/xFileDataObjectDouble.cxx

@@ -42,7 +42,7 @@ XFileDataObjectDouble(const XFileDataDef *data_def, double value) :
 ////////////////////////////////////////////////////////////////////
 void XFileDataObjectDouble::
 output_data(ostream &out) const {
-  out << as_string_value();
+  out << get_string_value();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -54,39 +54,61 @@ output_data(ostream &out) const {
 void XFileDataObjectDouble::
 write_data(ostream &out, int indent_level, const char *separator) const {
   indent(out, indent_level)
-    << as_string_value() << separator << "\n";
+    << get_string_value() << separator << "\n";
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: XFileDataObjectDouble::as_integer_value
+//     Function: XFileDataObjectDouble::set_int_value
+//       Access: Protected, Virtual
+//  Description: Sets the object's value as an integer, if this is
+//               legal.
+////////////////////////////////////////////////////////////////////
+void XFileDataObjectDouble::
+set_int_value(int int_value) {
+  _value = (double)int_value;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileDataObjectDouble::set_double_value
+//       Access: Protected, Virtual
+//  Description: Sets the object's value as a floating-point number,
+//               if this is legal.
+////////////////////////////////////////////////////////////////////
+void XFileDataObjectDouble::
+set_double_value(double double_value) {
+  _value = double_value;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileDataObjectDouble::get_int_value
 //       Access: Protected, Virtual
 //  Description: Returns the object's representation as an integer, if
 //               it has one.
 ////////////////////////////////////////////////////////////////////
 int XFileDataObjectDouble::
-as_integer_value() const {
+get_int_value() const {
   return (int)_value;
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: XFileDataObjectDouble::as_double_value
+//     Function: XFileDataObjectDouble::get_double_value
 //       Access: Protected, Virtual
 //  Description: Returns the object's representation as a double, if
 //               it has one.
 ////////////////////////////////////////////////////////////////////
 double XFileDataObjectDouble::
-as_double_value() const {
+get_double_value() const {
   return _value;
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: XFileDataObjectDouble::as_string_value
+//     Function: XFileDataObjectDouble::get_string_value
 //       Access: Protected, Virtual
 //  Description: Returns the object's representation as a string, if
 //               it has one.
 ////////////////////////////////////////////////////////////////////
 string XFileDataObjectDouble::
-as_string_value() const {
+get_string_value() const {
   // It's important to format with a decimal point, even if the value
   // is integral, since the DirectX .x reader differentiates betweens
   // doubles and integers on parsing.

+ 6 - 3
pandatool/src/xfile/xFileDataObjectDouble.h

@@ -37,9 +37,12 @@ public:
                           const char *separator) const;
 
 protected:
-  virtual int as_integer_value() const;
-  virtual double as_double_value() const;
-  virtual string as_string_value() const;
+  virtual void set_int_value(int int_value);
+  virtual void set_double_value(double double_value);
+
+  virtual int get_int_value() const;
+  virtual double get_double_value() const;
+  virtual string get_string_value() const;
 
 private:
   double _value;

+ 17 - 6
pandatool/src/xfile/xFileDataObjectInteger.cxx

@@ -58,34 +58,45 @@ write_data(ostream &out, int indent_level, const char *separator) const {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: XFileDataObjectInteger::as_integer_value
+//     Function: XFileDataObjectInt::set_int_value
+//       Access: Protected, Virtual
+//  Description: Sets the object's value as an integer, if this is
+//               legal.
+////////////////////////////////////////////////////////////////////
+void XFileDataObjectInteger::
+set_int_value(int int_value) {
+  _value = int_value;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileDataObjectInteger::get_int_value
 //       Access: Protected, Virtual
 //  Description: Returns the object's representation as an integer, if
 //               it has one.
 ////////////////////////////////////////////////////////////////////
 int XFileDataObjectInteger::
-as_integer_value() const {
+get_int_value() const {
   return _value;
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: XFileDataObjectInteger::as_double_value
+//     Function: XFileDataObjectInteger::get_double_value
 //       Access: Protected, Virtual
 //  Description: Returns the object's representation as a double, if
 //               it has one.
 ////////////////////////////////////////////////////////////////////
 double XFileDataObjectInteger::
-as_double_value() const {
+get_double_value() const {
   return _value;
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: XFileDataObjectInteger::as_string_value
+//     Function: XFileDataObjectInteger::get_string_value
 //       Access: Protected, Virtual
 //  Description: Returns the object's representation as a string, if
 //               it has one.
 ////////////////////////////////////////////////////////////////////
 string XFileDataObjectInteger::
-as_string_value() const {
+get_string_value() const {
   return format_string(_value);
 }

+ 5 - 3
pandatool/src/xfile/xFileDataObjectInteger.h

@@ -37,9 +37,11 @@ public:
                           const char *separator) const;
 
 protected:
-  virtual int as_integer_value() const;
-  virtual double as_double_value() const;
-  virtual string as_string_value() const;
+  virtual void set_int_value(int int_value);
+
+  virtual int get_int_value() const;
+  virtual double get_double_value() const;
+  virtual string get_string_value() const;
 
 private:
   int _value;

+ 14 - 2
pandatool/src/xfile/xFileDataObjectString.cxx

@@ -59,13 +59,24 @@ write_data(ostream &out, int indent_level, const char *separator) const {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: XFileDataObjectString::as_string_value
+//     Function: XFileDataObjectString::set_string_value
+//       Access: Protected, Virtual
+//  Description: Sets the object's value as a string, if this is
+//               legal.
+////////////////////////////////////////////////////////////////////
+void XFileDataObjectString::
+set_string_value(const string &string_value) {
+  _value = string_value;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileDataObjectString::get_string_value
 //       Access: Protected, Virtual
 //  Description: Returns the object's representation as a string, if
 //               it has one.
 ////////////////////////////////////////////////////////////////////
 string XFileDataObjectString::
-as_string_value() const {
+get_string_value() const {
   return _value;
 }
 
@@ -95,6 +106,7 @@ enquote_string(ostream &out) const {
       break;
 
     case '"':
+    case '\\':
       out << '\\' << (*si);
       break;
 

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

@@ -37,7 +37,8 @@ public:
                           const char *separator) const;
 
 protected:
-  virtual string as_string_value() const;
+  virtual void set_string_value(const string &string_value);
+  virtual string get_string_value() const;
 
 private:
   void enquote_string(ostream &out) const;

+ 250 - 1
pandatool/src/xfile/xFileNode.cxx

@@ -21,6 +21,9 @@
 #include "xFile.h"
 #include "xLexerDefs.h"
 #include "xFileParseData.h"
+#include "xFile.h"
+#include "xFileDataNodeTemplate.h"
+#include "filename.h"
 
 TypeHandle XFileNode::_type_handle;
 
@@ -31,7 +34,7 @@ TypeHandle XFileNode::_type_handle;
 ////////////////////////////////////////////////////////////////////
 XFileNode::
 XFileNode(XFile *x_file, const string &name) :
-  Namable(name),
+  Namable(make_nice_name(name)),
   _x_file(x_file)
 {
 }
@@ -202,3 +205,249 @@ repack_data(XFileDataObject *object,
 
   return true;
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileNode::fill_zero_data
+//       Access: Public, Virtual
+//  Description: This is similar to repack_data(), except it is used
+//               to fill the initial values for a newly-created
+//               template object to zero.
+////////////////////////////////////////////////////////////////////
+bool XFileNode::
+fill_zero_data(XFileDataObject *object) const {
+  Children::const_iterator ci;
+  for (ci = _children.begin(); ci != _children.end(); ++ci) {
+    if (!(*ci)->fill_zero_data(object)) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileNode::add_Mesh
+//       Access: Public
+//  Description: Creates a new Mesh instance, as a child of this node.
+////////////////////////////////////////////////////////////////////
+XFileDataNode *XFileNode::
+add_Mesh(const string &name) {
+  XFileTemplate *xtemplate = XFile::find_standard_template("Mesh");
+  nassertr(xtemplate != (XFileTemplate *)NULL, NULL);
+  XFileDataNodeTemplate *node =
+    new XFileDataNodeTemplate(get_x_file(), name, xtemplate);
+  add_child(node);
+  node->zero_fill();
+
+  return node;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileNode::add_MeshNormals
+//       Access: Public
+//  Description: Creates a new MeshNormals instance, as a child of
+//               this node.
+////////////////////////////////////////////////////////////////////
+XFileDataNode *XFileNode::
+add_MeshNormals(const string &name) {
+  XFileTemplate *xtemplate = XFile::find_standard_template("MeshNormals");
+  nassertr(xtemplate != (XFileTemplate *)NULL, NULL);
+  XFileDataNodeTemplate *node =
+    new XFileDataNodeTemplate(get_x_file(), name, xtemplate);
+  add_child(node);
+  node->zero_fill();
+
+  return node;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileNode::add_MeshVertexColors
+//       Access: Public
+//  Description: Creates a new MeshVertexColors instance, as a child of
+//               this node.
+////////////////////////////////////////////////////////////////////
+XFileDataNode *XFileNode::
+add_MeshVertexColors(const string &name) {
+  XFileTemplate *xtemplate = XFile::find_standard_template("MeshVertexColors");
+  nassertr(xtemplate != (XFileTemplate *)NULL, NULL);
+  XFileDataNodeTemplate *node =
+    new XFileDataNodeTemplate(get_x_file(), name, xtemplate);
+  add_child(node);
+  node->zero_fill();
+
+  return node;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileNode::add_MeshTextureCoords
+//       Access: Public
+//  Description: Creates a new MeshTextureCoords instance, as a child of
+//               this node.
+////////////////////////////////////////////////////////////////////
+XFileDataNode *XFileNode::
+add_MeshTextureCoords(const string &name) {
+  XFileTemplate *xtemplate = XFile::find_standard_template("MeshTextureCoords");
+  nassertr(xtemplate != (XFileTemplate *)NULL, NULL);
+  XFileDataNodeTemplate *node =
+    new XFileDataNodeTemplate(get_x_file(), name, xtemplate);
+  add_child(node);
+  node->zero_fill();
+
+  return node;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileNode::add_MeshMaterialList
+//       Access: Public
+//  Description: Creates a new MeshMaterialList instance, as a child of
+//               this node.
+////////////////////////////////////////////////////////////////////
+XFileDataNode *XFileNode::
+add_MeshMaterialList(const string &name) {
+  XFileTemplate *xtemplate = XFile::find_standard_template("MeshMaterialList");
+  nassertr(xtemplate != (XFileTemplate *)NULL, NULL);
+  XFileDataNodeTemplate *node =
+    new XFileDataNodeTemplate(get_x_file(), name, xtemplate);
+  add_child(node);
+  node->zero_fill();
+
+  return node;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileNode::add_Material
+//       Access: Public
+//  Description: Creates a new Material instance, as a child of
+//               this node.
+////////////////////////////////////////////////////////////////////
+XFileDataNode *XFileNode::
+add_Material(const string &name, const Colorf &face_color,
+             double power, const RGBColorf &specular_color,
+             const RGBColorf &emissive_color) {
+  XFileTemplate *xtemplate = XFile::find_standard_template("Material");
+  nassertr(xtemplate != (XFileTemplate *)NULL, NULL);
+  XFileDataNodeTemplate *node =
+    new XFileDataNodeTemplate(get_x_file(), name, xtemplate);
+  add_child(node);
+  node->zero_fill();
+
+  (*node)["faceColor"]["red"] = face_color[0];
+  (*node)["faceColor"]["green"] = face_color[1];
+  (*node)["faceColor"]["blue"] = face_color[2];
+  (*node)["faceColor"]["alpha"] = face_color[3];
+  (*node)["power"] = power;
+  (*node)["specularColor"]["red"] = specular_color[0];
+  (*node)["specularColor"]["green"] = specular_color[1];
+  (*node)["specularColor"]["blue"] = specular_color[2];
+  (*node)["emissiveColor"]["red"] = emissive_color[0];
+  (*node)["emissiveColor"]["green"] = emissive_color[1];
+  (*node)["emissiveColor"]["blue"] = emissive_color[2];
+
+  return node;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileNode::add_TextureFilename
+//       Access: Public
+//  Description: Creates a new TextureFilename instance, as a child of
+//               this node.
+////////////////////////////////////////////////////////////////////
+XFileDataNode *XFileNode::
+add_TextureFilename(const string &name, const Filename &filename) {
+  XFileTemplate *xtemplate = XFile::find_standard_template("TextureFilename");
+  nassertr(xtemplate != (XFileTemplate *)NULL, NULL);
+  XFileDataNodeTemplate *node =
+    new XFileDataNodeTemplate(get_x_file(), name, xtemplate);
+  add_child(node);
+  node->zero_fill();
+
+  (*node)["filename"] = filename.to_os_specific();
+
+  return node;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileNode::add_Frame
+//       Access: Public
+//  Description: Creates a new Frame instance, as a child of this
+//               node.
+////////////////////////////////////////////////////////////////////
+XFileDataNode *XFileNode::
+add_Frame(const string &name) {
+  XFileTemplate *xtemplate = XFile::find_standard_template("Frame");
+  nassertr(xtemplate != (XFileTemplate *)NULL, NULL);
+  XFileDataNodeTemplate *node =
+    new XFileDataNodeTemplate(get_x_file(), name, xtemplate);
+  add_child(node);
+  node->zero_fill();
+
+  return node;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileNode::add_FrameTransformMatrix
+//       Access: Public
+//  Description: Creates a new FrameTransformMatrix instance, as a
+//               child of this node.
+////////////////////////////////////////////////////////////////////
+XFileDataNode *XFileNode::
+add_FrameTransformMatrix(const LMatrix4d &mat) {
+  XFileTemplate *xtemplate = 
+    XFile::find_standard_template("FrameTransformMatrix");
+  nassertr(xtemplate != (XFileTemplate *)NULL, NULL);
+  XFileDataNodeTemplate *node = 
+    new XFileDataNodeTemplate(get_x_file(), "", xtemplate);
+  add_child(node);
+  node->zero_fill();
+
+  XFileDataObject &xmat = (*node)["frameMatrix"]["matrix"];
+  xmat[0] = mat(0, 0);
+  xmat[1] = mat(0, 1);
+  xmat[2] = mat(0, 2);
+  xmat[3] = mat(0, 3);
+
+  xmat[4] = mat(1, 0);
+  xmat[5] = mat(1, 1);
+  xmat[6] = mat(1, 2);
+  xmat[7] = mat(1, 3);
+
+  xmat[8] = mat(2, 0);
+  xmat[9] = mat(2, 1);
+  xmat[10] = mat(2, 2);
+  xmat[11] = mat(2, 3);
+
+  xmat[12] = mat(3, 0);
+  xmat[13] = mat(3, 1);
+  xmat[14] = mat(3, 2);
+  xmat[15] = mat(3, 3);
+
+  return node;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileNode::make_nice_name
+//       Access: Protected, Static
+//  Description: Transforms the indicated egg name to a name that is
+//               acceptable for a node in the X File format.
+////////////////////////////////////////////////////////////////////
+string XFileNode::
+make_nice_name(const string &str) {
+  string result;
+
+  string::const_iterator si;
+  for (si = str.begin(); si != str.end(); ++si) {
+    if (isalnum(*si)) {
+      result += *si;
+    } else {
+      result += "_";
+    }
+  }
+
+  if (!str.empty() && isdigit(str[0])) {
+    // If the name begins with a digit, we must make it begin with
+    // something else, like for instance an underscore.
+    result = '_' + result;
+  }
+
+  return result;
+}

+ 31 - 0
pandatool/src/xfile/xFileNode.h

@@ -27,12 +27,15 @@
 #include "notify.h"
 #include "pvector.h"
 #include "pmap.h"
+#include "luse.h"
 
 class XFile;
 class WindowsGuid;
 class XFileParseDataList;
 class XFileDataDef;
 class XFileDataObject;
+class XFileDataNode;
+class Filename;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : XFileNode
@@ -68,6 +71,34 @@ public:
                            PrevData &prev_data,
                            size_t &index, size_t &sub_index) const;
 
+  virtual bool fill_zero_data(XFileDataObject *object) const;
+
+
+  // The following methods can be used to create instances of the
+  // standard template objects.  These definitions match those defined
+  // in standardTemplates.x in this directory (and compiled into the
+  // executable).
+  /*
+  PT(XFileNode) make_Header(int major, int minor, int flags);
+  PT(XFileNode) make_Vector(const LVecBase3d &vector);
+  PT(XFileNode) make_MeshFace(int num_vertex_indices, const int *vertex_indices);
+  */
+  XFileDataNode *add_Mesh(const string &name);
+  XFileDataNode *add_MeshNormals(const string &name);
+  XFileDataNode *add_MeshVertexColors(const string &name);
+  XFileDataNode *add_MeshTextureCoords(const string &name);
+  XFileDataNode *add_MeshMaterialList(const string &name);
+  XFileDataNode *add_Material(const string &name, const Colorf &face_color,
+                              double power, const RGBColorf &specular_color,
+                              const RGBColorf &emissive_color);
+  XFileDataNode *add_TextureFilename(const string &name, 
+                                     const Filename &filename);
+  XFileDataNode *add_Frame(const string &name);
+  XFileDataNode *add_FrameTransformMatrix(const LMatrix4d &mat);
+
+protected:
+  static string make_nice_name(const string &str);
+
 protected:
   XFile *_x_file;
   

+ 49 - 371
pandatool/src/xfileegg/xFileMaker.cxx

@@ -43,9 +43,8 @@
 ////////////////////////////////////////////////////////////////////
 XFileMaker::
 XFileMaker() {
-  _dx_file = NULL;
-  _dx_file_save = NULL;
   _mesh_index = 0;
+  _x_file = new XFile;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -55,152 +54,24 @@ XFileMaker() {
 ////////////////////////////////////////////////////////////////////
 XFileMaker::
 ~XFileMaker() {
-  close();
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: XFileMaker::open
+//     Function: XFileMaker::write
 //       Access: Public
-//  Description: Opens the indicated filename for writing, and writes
-//               the .x header information; returns true on success,
-//               false otherwise.
+//  Description: Writes the .x file data to the indicated filename;
+//               returns true on success, false otherwise.
 ////////////////////////////////////////////////////////////////////
 bool XFileMaker::
-open(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_xtemplates_length);
-  if (hr != DXFILE_OK) {
-    nout << "Unable to register templates.\n";
-    return false;
-  }
-
-  string os_file = filename.to_os_specific();
-  hr = _dx_file->CreateSaveObject(os_file.c_str(), DXFILEFORMAT_TEXT,
-                                  &_dx_file_save);
-  if (hr != DXFILE_OK) {
-    nout << "Unable to open X file: " << os_file << "\n";
-    return false;
-  }
-
-  // Save the templates we will use.
-  static const GUID *temps[] = {
-    &mydef_TID_D3DRMHeader,
-    &TID_D3DRMCoords2d,
-    &TID_D3DRMVector,
-    &TID_D3DRMColorRGBA,
-    &TID_D3DRMColorRGB,
-    &TID_D3DRMIndexedColor,
-    &TID_D3DRMTextureFilename,
-    &TID_D3DRMMatrix4x4,
-    &TID_D3DRMMaterial,
-    &TID_D3DRMMeshFace,
-    &TID_D3DRMMesh,
-    &TID_D3DRMMeshNormals,
-    &TID_D3DRMMeshTextureCoords,
-    &TID_D3DRMMeshMaterialList,
-    &TID_D3DRMFrameTransformMatrix,
-    &TID_D3DRMFrame,
-
-    /*
-      This is the complete list I extracted out of the Windows header
-      files.
-
-    &TID_D3DRMInfo,
-    &TID_D3DRMMesh,
-    &TID_D3DRMVector,
-    &TID_D3DRMMeshFace,
-    &TID_D3DRMMaterial,
-    &TID_D3DRMMaterialArray,
-    &TID_D3DRMFrame,
-    &TID_D3DRMFrameTransformMatrix,
-    &TID_D3DRMMeshMaterialList,
-    &TID_D3DRMMeshTextureCoords,
-    &TID_D3DRMMeshNormals,
-    &TID_D3DRMCoords2d,
-    &TID_D3DRMMatrix4x4,
-    &TID_D3DRMAnimation,
-    &TID_D3DRMAnimationSet,
-    &TID_D3DRMAnimationKey,
-    &TID_D3DRMFloatKeys,
-    &TID_D3DRMMaterialAmbientColor,
-    &TID_D3DRMMaterialDiffuseColor,
-    &TID_D3DRMMaterialSpecularColor,
-    &TID_D3DRMMaterialEmissiveColor,
-    &TID_D3DRMMaterialPower,
-    &TID_D3DRMColorRGBA,
-    &TID_D3DRMColorRGB,
-    &TID_D3DRMGuid,
-    &TID_D3DRMTextureFilename,
-    &TID_D3DRMTextureReference,
-    &TID_D3DRMIndexedColor,
-    &TID_D3DRMMeshVertexColors,
-    &TID_D3DRMMaterialWrap,
-    &TID_D3DRMBoolean,
-    &TID_D3DRMMeshFaceWraps,
-    &TID_D3DRMBoolean2d,
-    &TID_D3DRMTimedFloatKeys,
-    &TID_D3DRMAnimationOptions,
-    &TID_D3DRMFramePosition,
-    &TID_D3DRMFrameVelocity,
-    &TID_D3DRMFrameRotation,
-    &TID_D3DRMLight,
-    &TID_D3DRMCamera,
-    &TID_D3DRMAppData,
-    &TID_D3DRMLightUmbra,
-    &TID_D3DRMLightRange,
-    &TID_D3DRMLightPenumbra,
-    &TID_D3DRMLightAttenuation,
-    &TID_D3DRMInlineData,
-    &TID_D3DRMUrl,
-    &TID_D3DRMProgressiveMesh,
-    &TID_D3DRMExternalVisual,
-    &TID_D3DRMStringProperty, 
-    &TID_D3DRMPropertyBag, 
-    &TID_D3DRMRightHanded, 
-    */
-  };
-  static const int num_temps = sizeof(temps) / sizeof(temps[0]);
-  hr = _dx_file_save->SaveTemplates(num_temps, temps);
-  if (hr != DXFILE_OK) {
-    nout << "Unable to save templates.\n";
-    return false;
-  }
-
-  return true;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: XFileMaker::close
-//       Access: Public
-//  Description: Finalizes and closes the file previously opened via
-//               open().
-////////////////////////////////////////////////////////////////////
-void XFileMaker::
-close() {
-  if (_dx_file != NULL) {
-    if (_dx_file_save != NULL) {
-      _dx_file_save->Release();
-      _dx_file_save = NULL;
-    }
-    _dx_file->Release();
-    _dx_file = NULL;
-  }
+write(const Filename &filename) {
+  return _x_file->write(filename);
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: XFileMaker::add_tree
 //       Access: Public
 //  Description: Adds the egg tree rooted at the indicated node to the
-//               DX structure.  This may be somewhat destructive of
+//               X structure.  This may be somewhat destructive of
 //               the egg tree.  Returns true on success, false on
 //               failure.
 ////////////////////////////////////////////////////////////////////
@@ -213,16 +84,19 @@ add_tree(EggData &egg_data) {
   int num_bins = pmaker.make_bins(&egg_data);
 
   // And now we're ready to traverse the egg hierarchy.
-  if (!recurse_nodes(&egg_data, NULL)) {
+  if (!recurse_nodes(&egg_data, _x_file)) {
     return false;
   }
 
-  // Make sure we finalize any meshes in the root.
-  if (!finalize_mesh(NULL)) {
-    return false;
+  // Create X structures for all of the meshes we built up.
+  Meshes::iterator mi;
+  for (mi = _meshes.begin(); mi != _meshes.end(); ++mi) {
+    if (!finalize_mesh((*mi).first, (*mi).second)) {
+      return false;
+    }
   }
+  _meshes.clear();
 
-  nassertr(_meshes.empty(), false);
   return true;
 }
 
@@ -233,37 +107,29 @@ add_tree(EggData &egg_data) {
 //               it is supported.
 ////////////////////////////////////////////////////////////////////
 bool XFileMaker::
-add_node(EggNode *egg_node, LPDIRECTXFILEDATA dx_parent) {
+add_node(EggNode *egg_node, XFileNode *x_parent) {
   if (egg_node->is_of_type(EggBin::get_class_type())) {
-    return add_bin(DCAST(EggBin, egg_node), dx_parent);
+    return add_bin(DCAST(EggBin, egg_node), x_parent);
 
   } else if (egg_node->is_of_type(EggGroup::get_class_type())) {
-    return add_group(DCAST(EggGroup, egg_node), dx_parent);
+    return add_group(DCAST(EggGroup, egg_node), x_parent);
 
   } else if (egg_node->is_of_type(EggGroupNode::get_class_type())) {
     // A grouping node of some kind.
     EggGroupNode *egg_group = DCAST(EggGroupNode, egg_node);
-    LPDIRECTXFILEDATA obj;
 
     if (xfile_one_mesh) {
       // Don't create any additional frames representing the egg
       // hierarchy.
-      if (!recurse_nodes(egg_group, dx_parent)) {
+      if (!recurse_nodes(egg_group, x_parent)) {
         return false;
       }
 
     } else {
-      // Create a frame for each EggGroup.
-      if (!create_frame(obj, egg_group->get_name())) {
-        return false;
-      }
-    
-      if (!recurse_nodes(egg_group, obj)) {
-        obj->Release();
-        return false;
-      }
-      
-      if (!attach_and_release(obj, dx_parent)) {
+      // Create a Frame for each EggGroup.
+      XFileDataNode *x_frame = x_parent->add_Frame(egg_group->get_name());
+
+      if (!recurse_nodes(egg_group, x_frame)) {
         return false;
       }
     }
@@ -281,32 +147,24 @@ add_node(EggNode *egg_node, LPDIRECTXFILEDATA dx_parent) {
 //  Description: Adds a frame for the indicated group node.
 ////////////////////////////////////////////////////////////////////
 bool XFileMaker::
-add_group(EggGroup *egg_group, LPDIRECTXFILEDATA dx_parent) {
+add_group(EggGroup *egg_group, XFileNode *x_parent) {
   if (xfile_one_mesh) {
     // Don't create any additional frames representing the egg
     // hierarchy.
-    if (!recurse_nodes(egg_group, dx_parent)) {
+    if (!recurse_nodes(egg_group, x_parent)) {
       return false;
     }
 
   } else {
     // Create a frame for each EggGroup.
-    LPDIRECTXFILEDATA obj;
-    if (!create_frame(obj, egg_group->get_name())) {
-      return false;
-    }
+    XFileDataNode *x_frame = x_parent->add_Frame(egg_group->get_name());
 
     // 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;
+      x_frame->add_FrameTransformMatrix(egg_group->get_transform());
     }
-    
-    if (!attach_and_release(obj, dx_parent)) {
+
+    if (!recurse_nodes(egg_group, x_frame)) {
       return false;
     }
   }
@@ -321,10 +179,10 @@ add_group(EggGroup *egg_group, LPDIRECTXFILEDATA dx_parent) {
 //               the indicated bin node.
 ////////////////////////////////////////////////////////////////////
 bool XFileMaker::
-add_bin(EggBin *egg_bin, LPDIRECTXFILEDATA dx_parent) {
+add_bin(EggBin *egg_bin, XFileNode *x_parent) {
   switch (egg_bin->get_bin_number()) {
   case EggPolysetMaker::BN_polyset:
-    return add_polyset(egg_bin, dx_parent);
+    return add_polyset(egg_bin, x_parent);
   }
 
   xfile_cat.error()
@@ -339,11 +197,11 @@ add_bin(EggBin *egg_bin, LPDIRECTXFILEDATA dx_parent) {
 //               polygons within the indicated bin.
 ////////////////////////////////////////////////////////////////////
 bool XFileMaker::
-add_polyset(EggBin *egg_bin, LPDIRECTXFILEDATA dx_parent) {
+add_polyset(EggBin *egg_bin, XFileNode *x_parent) {
   // Make sure that all our polygons are reasonable.
   egg_bin->remove_invalid_primitives();
 
-  XFileMesh *mesh = get_mesh(dx_parent);
+  XFileMesh *mesh = get_mesh(x_parent);
 
   EggGroupNode::iterator ci;
   for (ci = egg_bin->begin(); ci != egg_bin->end(); ++ci) {
@@ -364,11 +222,11 @@ add_polyset(EggBin *egg_bin, LPDIRECTXFILEDATA dx_parent) {
 //               the indicated DX object.
 ////////////////////////////////////////////////////////////////////
 bool XFileMaker::
-recurse_nodes(EggGroupNode *egg_node, LPDIRECTXFILEDATA dx_parent) {
+recurse_nodes(EggGroupNode *egg_node, XFileNode *x_parent) {
   EggGroupNode::iterator ci;
   for (ci = egg_node->begin(); ci != egg_node->end(); ++ci) {
-    EggNode *node = (*ci);
-    if (!add_node(node, dx_parent)) {
+    EggNode *child = (*ci);
+    if (!add_node(child, x_parent)) {
       return false;
     }
   }
@@ -376,152 +234,24 @@ recurse_nodes(EggGroupNode *egg_node, LPDIRECTXFILEDATA dx_parent) {
   return true;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: XFileMaker::create_object
-//       Access: Private
-//  Description: Creates a DX data object.
-////////////////////////////////////////////////////////////////////
-bool XFileMaker::
-create_object(LPDIRECTXFILEDATA &obj, REFGUID template_id,
-              const string &name, const Datagram &dg) {
-  HRESULT hr;
-
-  string nice_name = make_nice_name(name);
-
-  int data_size = dg.get_length();
-  void *data_pointer = (void *)dg.get_data();
-
-  if (data_size == 0) {
-    data_pointer = (void *)NULL;
-  }
-
-  hr = _dx_file_save->CreateDataObject
-    (template_id, nice_name.c_str(), NULL, 
-     data_size, data_pointer, &obj);
-
-  if (hr != DXFILE_OK) {
-    nout << "Unable to create data object for " << name << "\n";
-    return false;
-  }
-  return true;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: XFileMaker::create_frame
-//       Access: Private
-//  Description: Creates a "frame" object with the indicated name.
-////////////////////////////////////////////////////////////////////
-bool XFileMaker::
-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
-//  Description: Assigns the indicated X data object to the indicated
-//               parent, and releases the pointer.
-////////////////////////////////////////////////////////////////////
-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);
-    if (hr != DXFILE_OK) {
-      nout << "Unable to save data object\n";
-      obj->Release();
-      return false;
-    }
-  } else {
-    // Got a parent; it's a child of the indicated object.
-    hr = dx_parent->AddDataObject(obj);
-    if (hr != DXFILE_OK) {
-      nout << "Unable to save data object\n";
-      obj->Release();
-      return false;
-    }
-  }
-
-  obj->Release();
-  return true;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: XFileMaker::make_nice_name
-//       Access: Private, Static
-//  Description: Transforms the indicated egg name to a name that is
-//               acceptable to the DirectX format.
-////////////////////////////////////////////////////////////////////
-string XFileMaker::
-make_nice_name(const string &str) {
-  string result;
-
-  string::const_iterator si;
-  for (si = str.begin(); si != str.end(); ++si) {
-    if (isalnum(*si)) {
-      result += *si;
-    } else {
-      result += "_";
-    }
-  }
-
-  if (!str.empty() && isdigit(str[0])) {
-    // If the name begins with a digit, we must make it begin with
-    // something else, like for instance an underscore.
-    result = '_' + result;
-  }
-
-  return result;
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: XFileMaker::get_mesh
 //       Access: Private
 //  Description: Returns a suitable XFileMesh object for creating
-//               meshes within the indicated dx_parent object.
+//               meshes within the indicated x_parent object.
 ////////////////////////////////////////////////////////////////////
 XFileMesh *XFileMaker::
-get_mesh(LPDIRECTXFILEDATA dx_parent) {
-  Meshes::iterator mi = _meshes.find(dx_parent);
+get_mesh(XFileNode *x_parent) {
+  Meshes::iterator mi = _meshes.find(x_parent);
   if (mi != _meshes.end()) {
-    // We've already started working on this dx_parent before; use the
+    // We've already started working on this x_parent before; use the
     // same mesh object.
     return (*mi).second;
   }
 
-  // We haven't seen this dx_parent before; create a new mesh object.
+  // We haven't seen this x_parent before; create a new mesh object.
   XFileMesh *mesh = new XFileMesh;
-  _meshes.insert(Meshes::value_type(dx_parent, mesh));
+  _meshes.insert(Meshes::value_type(x_parent, mesh));
   return mesh;
 }
 
@@ -529,72 +259,19 @@ get_mesh(LPDIRECTXFILEDATA dx_parent) {
 ////////////////////////////////////////////////////////////////////
 //     Function: XFileMaker::finalize_mesh
 //       Access: Private
-//  Description: Creates the actual DX mesh object corresponding to
-//               the indicated dx_parent object.
+//  Description: Creates the actual X structures corresponding to
+//               the indicated XFileMesh 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);
-
+finalize_mesh(XFileNode *x_parent, XFileMesh *mesh) {
   // 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;
-    }
-  }
+  mesh->make_x_mesh(x_parent, mesh_index);
 
+  /*
   if (mesh->has_materials()) {
     // Tack on material definitions.
     LPDIRECTXFILEDATA xmaterial_list;
@@ -643,8 +320,9 @@ finalize_mesh(LPDIRECTXFILEDATA dx_parent) {
     }
   }
 
-  if (!attach_and_release(xobj, dx_parent)) {
+  if (!attach_and_release(xobj, x_parent)) {
     return false;
   }
+  */
   return true;
 }

+ 11 - 28
pandatool/src/xfileegg/xFileMaker.h

@@ -24,13 +24,7 @@
 #include "filename.h"
 #include "pmap.h"
 #include "luse.h"
-
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#include <d3dx.h>
-#include <dxfile.h>
-#include <rmxfguid.h>
-#undef WIN32_LEAN_AND_MEAN
+#include "xFile.h"
 
 class EggNode;
 class EggGroupNode;
@@ -51,37 +45,26 @@ public:
   XFileMaker();
   ~XFileMaker();
 
-  bool open(const Filename &filename);
-  void close();
+  bool write(const Filename &filename);
 
   bool add_tree(EggData &egg_data);
 
 private:
-  bool add_node(EggNode *egg_node, LPDIRECTXFILEDATA dx_parent);
-  bool add_group(EggGroup *egg_group, LPDIRECTXFILEDATA dx_parent);
-  bool add_bin(EggBin *egg_bin, LPDIRECTXFILEDATA dx_parent);
-  bool add_polyset(EggBin *egg_bin, LPDIRECTXFILEDATA dx_parent);
-
-  bool recurse_nodes(EggGroupNode *egg_node, LPDIRECTXFILEDATA dx_parent);
-
-  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);
+  bool add_node(EggNode *egg_node, XFileNode *x_parent);
+  bool add_group(EggGroup *egg_group, XFileNode *x_parent);
+  bool add_bin(EggBin *egg_bin, XFileNode *x_parent);
+  bool add_polyset(EggBin *egg_bin, XFileNode *x_parent);
 
-  static string make_nice_name(const string &str);
+  bool recurse_nodes(EggGroupNode *egg_node, XFileNode *x_parent);
 
-  XFileMesh *get_mesh(LPDIRECTXFILEDATA dx_parent);
-  bool finalize_mesh(LPDIRECTXFILEDATA dx_parent);
+  XFileMesh *get_mesh(XFileNode *x_parent);
+  bool finalize_mesh(XFileNode *x_parent, XFileMesh *mesh);
 
-  LPDIRECTXFILE _dx_file;
-  LPDIRECTXFILESAVEOBJECT _dx_file_save;
+  PT(XFile) _x_file;
 
   int _mesh_index;
 
-  typedef pmap<LPDIRECTXFILEDATA, XFileMesh *> Meshes;
+  typedef pmap<XFileNode *, XFileMesh *> Meshes;
   Meshes _meshes;
 };
 

+ 14 - 54
pandatool/src/xfileegg/xFileMaterial.cxx

@@ -180,63 +180,23 @@ has_texture() const {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: XFileMaterial::make_material_data
+//     Function: XFileMaterial::make_x_material
 //       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();
-
-  // Convert the filename to an appropriate form for the X file.
-  string os_filename = _texture.to_os_specific();
-  // Now we have to double up the backslashes.
-  string filename;
-  for (string::const_iterator pi = os_filename.begin();
-       pi != os_filename.end();
-       ++pi) {
-    if ((*pi) == '\\') {
-      filename += '\\';
-      filename += '\\';
-    } else {
-      filename += (*pi);
-    }
+//  Description: Creates a Material object for the material list.
+////////////////////////////////////////////////////////////////////
+XFileDataNode *XFileMaterial::
+make_x_material(XFileNode *x_meshMaterials, const string &suffix) {
+  XFileDataNode *x_material = 
+    x_meshMaterials->add_Material("material" + suffix,
+                                  _face_color, _power,
+                                  _specular_color, _emissive_color);
+
+  if (has_texture()) {
+    XFileDataNode *x_texture = 
+      x_material->add_TextureFilename("texture" + suffix, _texture);
   }
 
-  // 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.
-  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);
+  return x_material;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 3 - 3
pandatool/src/xfileegg/xFileMaterial.h

@@ -26,6 +26,8 @@
 class EggPrimitive;
 class Datagram;
 class XFileToEggConverter;
+class XFileNode;
+class XFileDataNode;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : XFileMaterial
@@ -45,9 +47,7 @@ public:
   bool has_material() const;
   bool has_texture() const;
 
-  void make_material_data(Datagram &raw_data);
-  void make_texture_data(Datagram &raw_data);
-
+  XFileDataNode *make_x_material(XFileNode *x_meshMaterials, const string &suffix);
   bool read_material_data(const Datagram &raw_data);
   bool read_texture_data(const Datagram &raw_data);
 

+ 112 - 63
pandatool/src/xfileegg/xFileMesh.cxx

@@ -21,8 +21,9 @@
 #include "xFileVertex.h"
 #include "xFileNormal.h"
 #include "xFileMaterial.h"
+#include "xFileDataNode.h"
 #include "config_xfile.h"
-
+#include "string_utils.h"
 #include "eggVertexPool.h"
 #include "eggVertex.h"
 #include "eggPolygon.h"
@@ -473,136 +474,184 @@ get_material(int n) const {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: XFileMesh::make_mesh_data
+//     Function: XFileMesh::make_x_mesh
 //       Access: Public
-//  Description: Fills the datagram with the raw data for the DX
-//               Mesh template.
+//  Description: Creates an X structure corresponding to the mesh.
 ////////////////////////////////////////////////////////////////////
-void XFileMesh::
-make_mesh_data(Datagram &raw_data) {
-  raw_data.clear();
-  raw_data.add_int32(_vertices.size());
-  
+XFileDataNode *XFileMesh::
+make_x_mesh(XFileNode *x_parent, const string &suffix) {
+  XFileDataNode *x_mesh = x_parent->add_Mesh("mesh" + suffix);
+
+  // First, fill in the table of vertices.
+  XFileDataObject &x_vertices = (*x_mesh)["vertices"];
+
   Vertices::const_iterator vi;
   for (vi = _vertices.begin(); vi != _vertices.end(); ++vi) {
     XFileVertex *vertex = (*vi);
-    const Vertexf &point = vertex->_point;
-    raw_data.add_float32(point[0]);
-    raw_data.add_float32(point[1]);
-    raw_data.add_float32(point[2]);
+    x_vertices.add_Vector(x_mesh->get_x_file(), LCAST(double, vertex->_point));
   }
+  (*x_mesh)["nVertices"] = x_vertices.size();
 
-  raw_data.add_int32(_faces.size());
+  // Then, create the list of faces that index into the above vertices.
+  XFileDataObject &x_faces = (*x_mesh)["faces"];
   Faces::const_iterator fi;
   for (fi = _faces.begin(); fi != _faces.end(); ++fi) {
     XFileFace *face = (*fi);
 
-    raw_data.add_int32(face->_vertices.size());
+    XFileDataObject &x_mesh_face = x_faces.add_MeshFace(x_mesh->get_x_file());
+    XFileDataObject &x_faceVertexIndices = x_mesh_face["faceVertexIndices"];
     XFileFace::Vertices::const_iterator fvi;
     for (fvi = face->_vertices.begin();
          fvi != face->_vertices.end();
          ++fvi) {
-      raw_data.add_int32((*fvi)._vertex_index);
+      x_faceVertexIndices.add_int((*fvi)._vertex_index);
     }
+    x_mesh_face["nFaceVertexIndices"] = x_faceVertexIndices.size();
+  }
+  (*x_mesh)["nFaces"] = x_faces.size();
+
+  // Now, add in any supplemental data.
+
+  if (has_normals()) {
+    // Tack on normals.
+    make_x_normals(x_mesh, suffix);
+  }
+  if (has_colors()) {
+    // Tack on colors.
+    make_x_colors(x_mesh, suffix);
   }
+  if (has_uvs()) {
+    // Tack on uvs.
+    make_x_uvs(x_mesh, suffix);
+  }
+  if (has_materials()) {
+    // Tack on materials.
+    make_x_material_list(x_mesh, suffix);
+  }
+
+  return x_mesh;
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: XFileMesh::make_normal_data
+//     Function: XFileMesh::make_x_normals
 //       Access: Public
-//  Description: Fills the datagram with the raw data for the DX
-//               MeshNormals template.
+//  Description: Creates a MeshNormals table for the mesh.
 ////////////////////////////////////////////////////////////////////
-void XFileMesh::
-make_normal_data(Datagram &raw_data) {
-  raw_data.clear();
-  raw_data.add_int32(_normals.size());
-  
+XFileDataNode *XFileMesh::
+make_x_normals(XFileNode *x_mesh, const string &suffix) {
+  XFileDataNode *x_meshNormals = x_mesh->add_MeshNormals("norms" + suffix);
+
+  XFileDataObject &x_normals = (*x_meshNormals)["normals"];
+
   Normals::const_iterator ni;
   for (ni = _normals.begin(); ni != _normals.end(); ++ni) {
     XFileNormal *normal = (*ni);
-    const Normalf &norm = normal->_normal;
-    raw_data.add_float32(norm[0]);
-    raw_data.add_float32(norm[1]);
-    raw_data.add_float32(norm[2]);
+    x_normals.add_Vector(x_mesh->get_x_file(), LCAST(double, normal->_normal));
   }
+  (*x_meshNormals)["nNormals"] = x_normals.size();
 
-  raw_data.add_int32(_faces.size());
+  // Then, create the list of faces that index into the above normals.
+  XFileDataObject &x_faces = (*x_meshNormals)["faceNormals"];
   Faces::const_iterator fi;
   for (fi = _faces.begin(); fi != _faces.end(); ++fi) {
     XFileFace *face = (*fi);
 
-    raw_data.add_int32(face->_vertices.size());
+    XFileDataObject &x_normals_face = x_faces.add_MeshFace(x_mesh->get_x_file());
+    XFileDataObject &x_faceVertexIndices = x_normals_face["faceVertexIndices"];
     XFileFace::Vertices::const_iterator fvi;
     for (fvi = face->_vertices.begin();
          fvi != face->_vertices.end();
          ++fvi) {
-      raw_data.add_int32((*fvi)._normal_index);
+      x_faceVertexIndices.add_int((*fvi)._normal_index);
     }
+    x_normals_face["nFaceVertexIndices"] = x_faceVertexIndices.size();
   }
+  (*x_meshNormals)["nFaceNormals"] = x_faces.size();
+
+  return x_meshNormals;
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: XFileMesh::make_color_data
+//     Function: XFileMesh::make_x_colors
 //       Access: Public
-//  Description: Fills the datagram with the raw data for the DX
-//               MeshVertexColors template.
+//  Description: Creates a MeshVertexColors table for the mesh.
 ////////////////////////////////////////////////////////////////////
-void XFileMesh::
-make_color_data(Datagram &raw_data) {
-  raw_data.clear();
-  raw_data.add_int32(_vertices.size());
-  
+XFileDataNode *XFileMesh::
+make_x_colors(XFileNode *x_mesh, const string &suffix) {
+  XFileDataNode *x_meshColors = x_mesh->add_MeshVertexColors("colors" + suffix);
+
+  XFileDataObject &x_colors = (*x_meshColors)["vertexColors"];
+
   Vertices::const_iterator vi;
   int i = 0;
   for (vi = _vertices.begin(); vi != _vertices.end(); ++vi) {
     XFileVertex *vertex = (*vi);
     const Colorf &color = vertex->_color;
-    raw_data.add_int32(i);
-    raw_data.add_float32(color[0]);
-    raw_data.add_float32(color[1]);
-    raw_data.add_float32(color[2]);
-    raw_data.add_float32(color[3]);
+    x_colors.add_IndexedColor(x_mesh->get_x_file(), i, color);
     i++;
   }
+
+  (*x_meshColors)["nVertexColors"] = x_colors.size();
+  
+  return x_meshColors;
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: XFileMesh::make_uv_data
+//     Function: XFileMesh::make_x_uvs
 //       Access: Public
-//  Description: Fills the datagram with the raw data for the DX
-//               MeshTextureCoords template.
+//  Description: Creates a MeshTextureCoords table for the mesh.
 ////////////////////////////////////////////////////////////////////
-void XFileMesh::
-make_uv_data(Datagram &raw_data) {
-  raw_data.clear();
-  raw_data.add_int32(_vertices.size());
+XFileDataNode *XFileMesh::
+make_x_uvs(XFileNode *x_mesh, const string &suffix) {
+  XFileDataNode *x_meshUvs = x_mesh->add_MeshTextureCoords("uvs" + suffix);
+
+  XFileDataObject &x_uvs = (*x_meshUvs)["textureCoords"];
   
   Vertices::const_iterator vi;
   for (vi = _vertices.begin(); vi != _vertices.end(); ++vi) {
     XFileVertex *vertex = (*vi);
-    const TexCoordf &uv = vertex->_uv;
-    raw_data.add_float32(uv[0]);
-    raw_data.add_float32(uv[1]);
+    x_uvs.add_Coords2d(x_mesh->get_x_file(), LCAST(double, vertex->_uv));
   }
+
+  (*x_meshUvs)["nTextureCoords"] = x_uvs.size();
+
+  return x_meshUvs;
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: XFileMesh::make_material_list_data
+//     Function: XFileMesh::make_x_material_list
 //       Access: Public
-//  Description: Fills the datagram with the raw data for the DX
-//               MeshMaterialList template.
+//  Description: Creates a MeshMaterialList table for the mesh.
 ////////////////////////////////////////////////////////////////////
-void XFileMesh::
-make_material_list_data(Datagram &raw_data) {
-  raw_data.clear();
-  raw_data.add_int32(_materials.size());
-  raw_data.add_int32(_faces.size());
+XFileDataNode *XFileMesh::
+make_x_material_list(XFileNode *x_mesh, const string &suffix) {
+  XFileDataNode *x_meshMaterials = 
+    x_mesh->add_MeshMaterialList("materials" + suffix);
+
+  // First, build up the list of faces the reference the materials.
+  XFileDataObject &x_indexes = (*x_meshMaterials)["faceIndexes"];
+
   Faces::const_iterator fi;
   for (fi = _faces.begin(); fi != _faces.end(); ++fi) {
     XFileFace *face = (*fi);
-    raw_data.add_int32(face->_material_index);
+    x_indexes.add_int(face->_material_index);
+  }
+
+  (*x_meshMaterials)["nFaceIndexes"] = x_indexes.size();
+
+  // Now, build up the list of materials themselves.  Each material is
+  // a child of the MeshMaterialList node, rather than an element of
+  // an array.
+  for (size_t i = 0; i < _materials.size(); i++) {
+    XFileMaterial *material = _materials[i];
+
+    material->make_x_material(x_meshMaterials,
+                              suffix + "_" + format_string(i));
   }
+
+  (*x_meshMaterials)["nMaterials"] = (int)_materials.size();
+
+  return x_meshMaterials;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 7 - 5
pandatool/src/xfileegg/xFileMesh.h

@@ -26,12 +26,14 @@
 #include "namable.h"
 #include "coordinateSystem.h"
 
+class XFileNode;
 class XFileMesh;
 class XFileVertex;
 class XFileNormal;
 class XFileMaterial;
 class XFileFace;
 class XFileToEggConverter;
+class XFileDataNode;
 class EggGroupNode;
 class EggVertex;
 class EggPolygon;
@@ -70,11 +72,11 @@ public:
   int get_num_materials() const;
   XFileMaterial *get_material(int n) const;
 
-  void make_mesh_data(Datagram &raw_data);
-  void make_normal_data(Datagram &raw_data);
-  void make_color_data(Datagram &raw_data);
-  void make_uv_data(Datagram &raw_data);
-  void make_material_list_data(Datagram &raw_data);
+  XFileDataNode *make_x_mesh(XFileNode *x_parent, const string &suffix);
+  XFileDataNode *make_x_normals(XFileNode *x_mesh, const string &suffix);
+  XFileDataNode *make_x_colors(XFileNode *x_mesh, const string &suffix);
+  XFileDataNode *make_x_uvs(XFileNode *x_mesh, const string &suffix);
+  XFileDataNode *make_x_material_list(XFileNode *x_mesh, const string &suffix);
 
   bool read_mesh_data(const Datagram &raw_data);
   bool read_normal_data(const Datagram &raw_data);

+ 4 - 6
pandatool/src/xfileprogs/eggToX.cxx

@@ -60,11 +60,6 @@ EggToX() : EggToSomething("DirectX", ".x", true, false) {
 ////////////////////////////////////////////////////////////////////
 void EggToX::
 run() {
-  if (!_x.open(get_output_filename())) {
-    nout << "Unable to open " << get_output_filename() << " for output.\n";
-    exit(1);
-  }
-
   if (!do_reader_options()) {
     exit(1);
   }
@@ -74,7 +69,10 @@ run() {
     exit(1);
   }
 
-  _x.close();
+  if (!_x.write(get_output_filename())) {
+    nout << "Unable to write " << get_output_filename() << ".\n";
+    exit(1);
+  }
 }