diff --git a/pandatool/src/xfile/xFile.cxx b/pandatool/src/xfile/xFile.cxx index 9b4d7a8c45..0b95428f6b 100644 --- a/pandatool/src/xfile/xFile.cxx +++ b/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 diff --git a/pandatool/src/xfile/xFile.h b/pandatool/src/xfile/xFile.h index 53830b2038..4bb8815814 100644 --- a/pandatool/src/xfile/xFile.h +++ b/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; diff --git a/pandatool/src/xfile/xFileDataDef.cxx b/pandatool/src/xfile/xFileDataDef.cxx index 895607b01e..97391b2693 100644 --- a/pandatool/src/xfile/xFileDataDef.cxx +++ b/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); } } diff --git a/pandatool/src/xfile/xFileDataDef.h b/pandatool/src/xfile/xFileDataDef.h index 375942895b..8374206171 100644 --- a/pandatool/src/xfile/xFileDataDef.h +++ b/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; diff --git a/pandatool/src/xfile/xFileDataNodeTemplate.cxx b/pandatool/src/xfile/xFileDataNodeTemplate.cxx index 175d9530f6..a19221d0ac 100644 --- a/pandatool/src/xfile/xFileDataNodeTemplate.cxx +++ b/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; } diff --git a/pandatool/src/xfile/xFileDataNodeTemplate.h b/pandatool/src/xfile/xFileDataNodeTemplate.h index 682386356a..0fc65c79d9 100644 --- a/pandatool/src/xfile/xFileDataNodeTemplate.h +++ b/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; diff --git a/pandatool/src/xfile/xFileDataObject.I b/pandatool/src/xfile/xFileDataObject.I index 23e117cf91..6a4346ab0a 100644 --- a/pandatool/src/xfile/xFileDataObject.I +++ b/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; } diff --git a/pandatool/src/xfile/xFileDataObject.cxx b/pandatool/src/xfile/xFileDataObject.cxx index d4a5d109dc..758eb6b317 100644 --- a/pandatool/src/xfile/xFileDataObject.cxx +++ b/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; } diff --git a/pandatool/src/xfile/xFileDataObject.h b/pandatool/src/xfile/xFileDataObject.h index 7708d3a2f0..6c44c4fe63 100644 --- a/pandatool/src/xfile/xFileDataObject.h +++ b/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; diff --git a/pandatool/src/xfile/xFileDataObjectArray.cxx b/pandatool/src/xfile/xFileDataObjectArray.cxx index 2b3ced9a78..4d840c725c 100644 --- a/pandatool/src/xfile/xFileDataObjectArray.cxx +++ b/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]; } diff --git a/pandatool/src/xfile/xFileDataObjectArray.h b/pandatool/src/xfile/xFileDataObjectArray.h index f61fd86e2c..c596728708 100644 --- a/pandatool/src/xfile/xFileDataObjectArray.h +++ b/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; diff --git a/pandatool/src/xfile/xFileDataObjectDouble.cxx b/pandatool/src/xfile/xFileDataObjectDouble.cxx index 51434692b0..415e2378df 100644 --- a/pandatool/src/xfile/xFileDataObjectDouble.cxx +++ b/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. diff --git a/pandatool/src/xfile/xFileDataObjectDouble.h b/pandatool/src/xfile/xFileDataObjectDouble.h index 412fe079e1..8f698a2ecf 100644 --- a/pandatool/src/xfile/xFileDataObjectDouble.h +++ b/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; diff --git a/pandatool/src/xfile/xFileDataObjectInteger.cxx b/pandatool/src/xfile/xFileDataObjectInteger.cxx index dc37422da3..b740872d8d 100644 --- a/pandatool/src/xfile/xFileDataObjectInteger.cxx +++ b/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); } diff --git a/pandatool/src/xfile/xFileDataObjectInteger.h b/pandatool/src/xfile/xFileDataObjectInteger.h index 081229d4f2..44d55b4d3c 100644 --- a/pandatool/src/xfile/xFileDataObjectInteger.h +++ b/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; diff --git a/pandatool/src/xfile/xFileDataObjectString.cxx b/pandatool/src/xfile/xFileDataObjectString.cxx index ded13fed90..0b95e56874 100644 --- a/pandatool/src/xfile/xFileDataObjectString.cxx +++ b/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; diff --git a/pandatool/src/xfile/xFileDataObjectString.h b/pandatool/src/xfile/xFileDataObjectString.h index 31c1ac6578..d22ac0ea94 100644 --- a/pandatool/src/xfile/xFileDataObjectString.h +++ b/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; diff --git a/pandatool/src/xfile/xFileNode.cxx b/pandatool/src/xfile/xFileNode.cxx index 51920ef413..0ee57245a0 100644 --- a/pandatool/src/xfile/xFileNode.cxx +++ b/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; +} diff --git a/pandatool/src/xfile/xFileNode.h b/pandatool/src/xfile/xFileNode.h index 6ec97a8de7..d5ebf28deb 100644 --- a/pandatool/src/xfile/xFileNode.h +++ b/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; diff --git a/pandatool/src/xfileegg/xFileMaker.cxx b/pandatool/src/xfileegg/xFileMaker.cxx index f3f1a5f1b2..5d5e6e3f1b 100644 --- a/pandatool/src/xfileegg/xFileMaker.cxx +++ b/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())); + x_frame->add_FrameTransformMatrix(egg_group->get_transform()); } - - if (!recurse_nodes(egg_group, obj)) { - obj->Release(); - return false; - } - - 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; } diff --git a/pandatool/src/xfileegg/xFileMaker.h b/pandatool/src/xfileegg/xFileMaker.h index 4f1e2fde35..ee050a22f1 100644 --- a/pandatool/src/xfileegg/xFileMaker.h +++ b/pandatool/src/xfileegg/xFileMaker.h @@ -24,13 +24,7 @@ #include "filename.h" #include "pmap.h" #include "luse.h" - -#define WIN32_LEAN_AND_MEAN -#include -#include -#include -#include -#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 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); - bool recurse_nodes(EggGroupNode *egg_node, LPDIRECTXFILEDATA dx_parent); + bool recurse_nodes(EggGroupNode *egg_node, XFileNode *x_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); + XFileMesh *get_mesh(XFileNode *x_parent); + bool finalize_mesh(XFileNode *x_parent, XFileMesh *mesh); - bool attach_and_release(LPDIRECTXFILEDATA obj, LPDIRECTXFILEDATA dx_parent); - - static string make_nice_name(const string &str); - - XFileMesh *get_mesh(LPDIRECTXFILEDATA dx_parent); - bool finalize_mesh(LPDIRECTXFILEDATA dx_parent); - - LPDIRECTXFILE _dx_file; - LPDIRECTXFILESAVEOBJECT _dx_file_save; + PT(XFile) _x_file; int _mesh_index; - typedef pmap Meshes; + typedef pmap Meshes; Meshes _meshes; }; diff --git a/pandatool/src/xfileegg/xFileMaterial.cxx b/pandatool/src/xfileegg/xFileMaterial.cxx index be454a332e..b0ac8ce231 100644 --- a/pandatool/src/xfileegg/xFileMaterial.cxx +++ b/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. +// Description: Creates a Material object for the material list. //////////////////////////////////////////////////////////////////// -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]); -} +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); -//////////////////////////////////////////////////////////////////// -// 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); - } + 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; } //////////////////////////////////////////////////////////////////// diff --git a/pandatool/src/xfileegg/xFileMaterial.h b/pandatool/src/xfileegg/xFileMaterial.h index 3718237c0c..3d15297213 100644 --- a/pandatool/src/xfileegg/xFileMaterial.h +++ b/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); diff --git a/pandatool/src/xfileegg/xFileMesh.cxx b/pandatool/src/xfileegg/xFileMesh.cxx index dd9afe2100..a582ce06d6 100644 --- a/pandatool/src/xfileegg/xFileMesh.cxx +++ b/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; } //////////////////////////////////////////////////////////////////// diff --git a/pandatool/src/xfileegg/xFileMesh.h b/pandatool/src/xfileegg/xFileMesh.h index 92a4d9522a..88f8330191 100644 --- a/pandatool/src/xfileegg/xFileMesh.h +++ b/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); diff --git a/pandatool/src/xfileprogs/eggToX.cxx b/pandatool/src/xfileprogs/eggToX.cxx index 99fa3d516e..24a7a88966 100644 --- a/pandatool/src/xfileprogs/eggToX.cxx +++ b/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); + } }