Panda3D
 All Classes Functions Variables Enumerations
xFileNode.cxx
00001 // Filename: xFileNode.cxx
00002 // Created by:  drose (03Oct04)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "xFileNode.h"
00016 #include "windowsGuid.h"
00017 #include "xFile.h"
00018 #include "xLexerDefs.h"
00019 #include "xFileParseData.h"
00020 #include "xFile.h"
00021 #include "xFileDataNodeTemplate.h"
00022 #include "filename.h"
00023 #include "string_utils.h"
00024 
00025 TypeHandle XFileNode::_type_handle;
00026 
00027 ////////////////////////////////////////////////////////////////////
00028 //     Function: XFileNode::Constructor
00029 //       Access: Public
00030 //  Description:
00031 ////////////////////////////////////////////////////////////////////
00032 XFileNode::
00033 XFileNode(XFile *x_file, const string &name) :
00034   Namable(),
00035   _x_file(x_file)
00036 {
00037   if (x_file && x_file->_keep_names) {
00038     set_name(name);
00039   } else {
00040     set_name(make_nice_name(name));
00041   }
00042 }
00043 
00044 ////////////////////////////////////////////////////////////////////
00045 //     Function: XFileNode::Destructor
00046 //       Access: Public, Virtual
00047 //  Description:
00048 ////////////////////////////////////////////////////////////////////
00049 XFileNode::
00050 ~XFileNode() {
00051   clear();
00052 }
00053 
00054 ////////////////////////////////////////////////////////////////////
00055 //     Function: XFileNode::find_child
00056 //       Access: Public
00057 //  Description: Returns the child with the indicated name, if any, or
00058 //               NULL if none.
00059 ////////////////////////////////////////////////////////////////////
00060 XFileNode *XFileNode::
00061 find_child(const string &name) const {
00062   ChildrenByName::const_iterator ni;
00063   ni = _children_by_name.find(downcase(name));
00064   if (ni != _children_by_name.end()) {
00065     return get_child((*ni).second);
00066   }
00067 
00068   return NULL;
00069 }
00070 
00071 ////////////////////////////////////////////////////////////////////
00072 //     Function: XFileNode::find_child_index
00073 //       Access: Public
00074 //  Description: Returns the index number of the child with the
00075 //               indicated name, if any, or -1 if none.
00076 ////////////////////////////////////////////////////////////////////
00077 int XFileNode::
00078 find_child_index(const string &name) const {
00079   ChildrenByName::const_iterator ni;
00080   ni = _children_by_name.find(downcase(name));
00081   if (ni != _children_by_name.end()) {
00082     return (*ni).second;
00083   }
00084 
00085   return -1;
00086 }
00087 
00088 ////////////////////////////////////////////////////////////////////
00089 //     Function: XFileNode::find_child_index
00090 //       Access: Public
00091 //  Description: Returns the index number of the indicated child,
00092 //               or -1 if none.
00093 ////////////////////////////////////////////////////////////////////
00094 int XFileNode::
00095 find_child_index(const XFileNode *child) const {
00096   for (int i = 0; i < (int)_children.size(); i++) {
00097     if (_children[i] == child) {
00098       return i;
00099     }
00100   }
00101 
00102   return -1;
00103 }
00104 
00105 ////////////////////////////////////////////////////////////////////
00106 //     Function: XFileNode::find_descendent
00107 //       Access: Public
00108 //  Description: Returns the first child or descendent found with the
00109 //               indicated name after a depth-first search, if any, or
00110 //               NULL if none.
00111 ////////////////////////////////////////////////////////////////////
00112 XFileNode *XFileNode::
00113 find_descendent(const string &name) const {
00114   XFileNode *child = find_child(name);
00115   if (child != (XFileNode *)NULL) {
00116     return child;
00117   }
00118 
00119   Children::const_iterator ci;
00120   for (ci = _children.begin(); ci != _children.end(); ++ci) {
00121     XFileNode *child = (*ci)->find_descendent(name);
00122     if (child != (XFileNode *)NULL){ 
00123       return child;
00124     }
00125   }
00126 
00127   return NULL;
00128 }
00129 
00130 ////////////////////////////////////////////////////////////////////
00131 //     Function: XFileNode::has_guid
00132 //       Access: Public, Virtual
00133 //  Description: Returns true if this node has a GUID associated.
00134 ////////////////////////////////////////////////////////////////////
00135 bool XFileNode::
00136 has_guid() const {
00137   return false;
00138 }
00139 
00140 ////////////////////////////////////////////////////////////////////
00141 //     Function: XFileNode::get_guid
00142 //       Access: Public, Virtual
00143 //  Description: If has_guid() returned true, returns the particular
00144 //               GUID associated with this node.
00145 ////////////////////////////////////////////////////////////////////
00146 const WindowsGuid &XFileNode::
00147 get_guid() const {
00148   static WindowsGuid empty;
00149   return empty;
00150 }
00151 
00152 ////////////////////////////////////////////////////////////////////
00153 //     Function: XFileNode::is_template_def
00154 //       Access: Public, Virtual
00155 //  Description: Returns true if this node represents the definition
00156 //               of some template.  This is the template definition,
00157 //               not an actual data object that represents an instance
00158 //               of the template.  If the file strictly uses standard
00159 //               templates, the presence of template definitions is
00160 //               optional.
00161 //
00162 //               If this returns true, the node must be of type
00163 //               XFileTemplate.
00164 ////////////////////////////////////////////////////////////////////
00165 bool XFileNode::
00166 is_template_def() const {
00167   return false;
00168 }
00169 
00170 ////////////////////////////////////////////////////////////////////
00171 //     Function: XFileNode::is_reference
00172 //       Access: Public, Virtual
00173 //  Description: Returns true if this node represents an indirect
00174 //               reference to an object defined previously in the
00175 //               file.  References are generally transparent, so in
00176 //               most cases you never need to call this, unless you
00177 //               actually need to differentiate between references and
00178 //               instances; you can simply use the reference node as
00179 //               if it were itself the object it references.
00180 //
00181 //               If this returns true, the node must be of type
00182 //               XFileDataNodeReference.
00183 ////////////////////////////////////////////////////////////////////
00184 bool XFileNode::
00185 is_reference() const {
00186   return false;
00187 }
00188 
00189 ////////////////////////////////////////////////////////////////////
00190 //     Function: XFileNode::is_object
00191 //       Access: Public, Virtual
00192 //  Description: Returns true if this node represents a data object
00193 //               that is the instance of some template, or false
00194 //               otherwise.  This also returns true for references to
00195 //               objects (which are generally treated just like the
00196 //               objects themselves).
00197 //
00198 //               If this returns true, the node must be of type
00199 //               XFileDataNode (it is either an XFileDataNodeTemplate
00200 //               or an XFileDataNodeReference).
00201 ////////////////////////////////////////////////////////////////////
00202 bool XFileNode::
00203 is_object() const {
00204   return false;
00205 }
00206 
00207 ////////////////////////////////////////////////////////////////////
00208 //     Function: XFileNode::is_standard_object
00209 //       Access: Public, Virtual
00210 //  Description: Returns true if this node represents an instance of
00211 //               the standard template with the indicated name, or
00212 //               false otherwise.  This returns also returns true for
00213 //               references to standard objects.
00214 //
00215 //               If this returns true, the node must be of type
00216 //               XFileDataNode (it is either an XFileDataNodeTemplate
00217 //               or an XFileDataNodeReference).
00218 ////////////////////////////////////////////////////////////////////
00219 bool XFileNode::
00220 is_standard_object(const string &template_name) const {
00221   return false;
00222 }
00223 
00224 ////////////////////////////////////////////////////////////////////
00225 //     Function: XFileNode::add_child
00226 //       Access: Public
00227 //  Description: Adds the indicated node as a child of this node.
00228 ////////////////////////////////////////////////////////////////////
00229 void XFileNode::
00230 add_child(XFileNode *node) {
00231   if (node->has_name()) {
00232     _children_by_name[downcase(node->get_name())] = (int)_children.size();
00233   }
00234   if (node->has_guid()) {
00235     _x_file->_nodes_by_guid[node->get_guid()] = node;
00236   }
00237   if (node->is_of_type(XFileDataNode::get_class_type())) {
00238     _objects.push_back(DCAST(XFileDataNode, node));
00239   }
00240   _children.push_back(node);
00241 }
00242 
00243 ////////////////////////////////////////////////////////////////////
00244 //     Function: XFileNode::clear
00245 //       Access: Public, Virtual
00246 //  Description: Removes all children from the node, and otherwise
00247 //               resets it to its initial state.
00248 ////////////////////////////////////////////////////////////////////
00249 void XFileNode::
00250 clear() {
00251   _children.clear();
00252   _objects.clear();
00253   _children_by_name.clear();
00254 }
00255 
00256 ////////////////////////////////////////////////////////////////////
00257 //     Function: XFileNode::write_text
00258 //       Access: Public, Virtual
00259 //  Description: Writes a suitable representation of this node to an
00260 //               .x file in text mode.
00261 ////////////////////////////////////////////////////////////////////
00262 void XFileNode::
00263 write_text(ostream &out, int indent_level) const {
00264   Children::const_iterator ci;
00265   for (ci = _children.begin(); ci != _children.end(); ++ci) {
00266     (*ci)->write_text(out, indent_level);
00267   }
00268 }
00269 
00270 ////////////////////////////////////////////////////////////////////
00271 //     Function: XFileNode::repack_data
00272 //       Access: Public, Virtual
00273 //  Description: This is called on the template that defines an
00274 //               object, once the data for the object has been parsed.
00275 //               It is responsible for identifying which component of
00276 //               the template owns each data element, and packing the
00277 //               data elements appropriately back into the object.
00278 //
00279 //               It returns true on success, or false on an error
00280 //               (e.g. not enough data elements, mismatched data
00281 //               type).
00282 ////////////////////////////////////////////////////////////////////
00283 bool XFileNode::
00284 repack_data(XFileDataObject *object, 
00285             const XFileParseDataList &parse_data_list,
00286             XFileNode::PrevData &prev_data,
00287             size_t &index, size_t &sub_index) const {
00288   // This method should be specialized for data types that actually
00289   // consume a data element.  Here in the base class, it just walks
00290   // through its children, asking each one to pull off the appropriate
00291   // number of data elements.
00292 
00293   Children::const_iterator ci;
00294   for (ci = _children.begin(); ci != _children.end(); ++ci) {
00295     if (!(*ci)->repack_data(object, parse_data_list, 
00296                             prev_data, index, sub_index)) {
00297       return false;
00298     }
00299   }
00300 
00301   return true;
00302 }
00303 
00304 ////////////////////////////////////////////////////////////////////
00305 //     Function: XFileNode::fill_zero_data
00306 //       Access: Public, Virtual
00307 //  Description: This is similar to repack_data(), except it is used
00308 //               to fill the initial values for a newly-created
00309 //               template object to zero.
00310 ////////////////////////////////////////////////////////////////////
00311 bool XFileNode::
00312 fill_zero_data(XFileDataObject *object) const {
00313   Children::const_iterator ci;
00314   for (ci = _children.begin(); ci != _children.end(); ++ci) {
00315     if (!(*ci)->fill_zero_data(object)) {
00316       return false;
00317     }
00318   }
00319 
00320   return true;
00321 }
00322 
00323 ////////////////////////////////////////////////////////////////////
00324 //     Function: XFileNode::matches
00325 //       Access: Public, Virtual
00326 //  Description: Returns true if the node, particularly a template
00327 //               node, is structurally equivalent to the other node
00328 //               (which must be of the same type).  This checks data
00329 //               element types, but does not compare data element
00330 //               names.
00331 ////////////////////////////////////////////////////////////////////
00332 bool XFileNode::
00333 matches(const XFileNode *other) const {
00334   if (other->get_type() != get_type()) {
00335     return false;
00336   }
00337 
00338   if (other->get_num_children() != get_num_children()) {
00339     return false;
00340   }
00341 
00342   for (int i = 0; i < get_num_children(); i++) {
00343     if (!get_child(i)->matches(other->get_child(i))) {
00344       return false;
00345     }
00346   }
00347 
00348   return true;
00349 }
00350 
00351 ////////////////////////////////////////////////////////////////////
00352 //     Function: XFileNode::add_Mesh
00353 //       Access: Public
00354 //  Description: Creates a new Mesh instance, as a child of this node.
00355 ////////////////////////////////////////////////////////////////////
00356 XFileDataNode *XFileNode::
00357 add_Mesh(const string &name) {
00358   XFileTemplate *xtemplate = XFile::find_standard_template("Mesh");
00359   nassertr(xtemplate != (XFileTemplate *)NULL, NULL);
00360   XFileDataNodeTemplate *node =
00361     new XFileDataNodeTemplate(get_x_file(), name, xtemplate);
00362   add_child(node);
00363   node->zero_fill();
00364 
00365   return node;
00366 }
00367 
00368 ////////////////////////////////////////////////////////////////////
00369 //     Function: XFileNode::add_MeshNormals
00370 //       Access: Public
00371 //  Description: Creates a new MeshNormals instance, as a child of
00372 //               this node.
00373 ////////////////////////////////////////////////////////////////////
00374 XFileDataNode *XFileNode::
00375 add_MeshNormals(const string &name) {
00376   XFileTemplate *xtemplate = XFile::find_standard_template("MeshNormals");
00377   nassertr(xtemplate != (XFileTemplate *)NULL, NULL);
00378   XFileDataNodeTemplate *node =
00379     new XFileDataNodeTemplate(get_x_file(), name, xtemplate);
00380   add_child(node);
00381   node->zero_fill();
00382 
00383   return node;
00384 }
00385 
00386 ////////////////////////////////////////////////////////////////////
00387 //     Function: XFileNode::add_MeshVertexColors
00388 //       Access: Public
00389 //  Description: Creates a new MeshVertexColors instance, as a child of
00390 //               this node.
00391 ////////////////////////////////////////////////////////////////////
00392 XFileDataNode *XFileNode::
00393 add_MeshVertexColors(const string &name) {
00394   XFileTemplate *xtemplate = XFile::find_standard_template("MeshVertexColors");
00395   nassertr(xtemplate != (XFileTemplate *)NULL, NULL);
00396   XFileDataNodeTemplate *node =
00397     new XFileDataNodeTemplate(get_x_file(), name, xtemplate);
00398   add_child(node);
00399   node->zero_fill();
00400 
00401   return node;
00402 }
00403 
00404 ////////////////////////////////////////////////////////////////////
00405 //     Function: XFileNode::add_MeshTextureCoords
00406 //       Access: Public
00407 //  Description: Creates a new MeshTextureCoords instance, as a child of
00408 //               this node.
00409 ////////////////////////////////////////////////////////////////////
00410 XFileDataNode *XFileNode::
00411 add_MeshTextureCoords(const string &name) {
00412   XFileTemplate *xtemplate = XFile::find_standard_template("MeshTextureCoords");
00413   nassertr(xtemplate != (XFileTemplate *)NULL, NULL);
00414   XFileDataNodeTemplate *node =
00415     new XFileDataNodeTemplate(get_x_file(), name, xtemplate);
00416   add_child(node);
00417   node->zero_fill();
00418 
00419   return node;
00420 }
00421 
00422 ////////////////////////////////////////////////////////////////////
00423 //     Function: XFileNode::add_MeshMaterialList
00424 //       Access: Public
00425 //  Description: Creates a new MeshMaterialList instance, as a child of
00426 //               this node.
00427 ////////////////////////////////////////////////////////////////////
00428 XFileDataNode *XFileNode::
00429 add_MeshMaterialList(const string &name) {
00430   XFileTemplate *xtemplate = XFile::find_standard_template("MeshMaterialList");
00431   nassertr(xtemplate != (XFileTemplate *)NULL, NULL);
00432   XFileDataNodeTemplate *node =
00433     new XFileDataNodeTemplate(get_x_file(), name, xtemplate);
00434   add_child(node);
00435   node->zero_fill();
00436 
00437   return node;
00438 }
00439 
00440 ////////////////////////////////////////////////////////////////////
00441 //     Function: XFileNode::add_Material
00442 //       Access: Public
00443 //  Description: Creates a new Material instance, as a child of
00444 //               this node.
00445 ////////////////////////////////////////////////////////////////////
00446 XFileDataNode *XFileNode::
00447 add_Material(const string &name, const LColor &face_color,
00448              double power, const LRGBColor &specular_color,
00449              const LRGBColor &emissive_color) {
00450   XFileTemplate *xtemplate = XFile::find_standard_template("Material");
00451   nassertr(xtemplate != (XFileTemplate *)NULL, NULL);
00452   XFileDataNodeTemplate *node =
00453     new XFileDataNodeTemplate(get_x_file(), name, xtemplate);
00454   add_child(node);
00455   node->zero_fill();
00456 
00457   (*node)["faceColor"]["red"] = face_color[0];
00458   (*node)["faceColor"]["green"] = face_color[1];
00459   (*node)["faceColor"]["blue"] = face_color[2];
00460   (*node)["faceColor"]["alpha"] = face_color[3];
00461   (*node)["power"] = power;
00462   (*node)["specularColor"]["red"] = specular_color[0];
00463   (*node)["specularColor"]["green"] = specular_color[1];
00464   (*node)["specularColor"]["blue"] = specular_color[2];
00465   (*node)["emissiveColor"]["red"] = emissive_color[0];
00466   (*node)["emissiveColor"]["green"] = emissive_color[1];
00467   (*node)["emissiveColor"]["blue"] = emissive_color[2];
00468 
00469   return node;
00470 }
00471 
00472 ////////////////////////////////////////////////////////////////////
00473 //     Function: XFileNode::add_TextureFilename
00474 //       Access: Public
00475 //  Description: Creates a new TextureFilename instance, as a child of
00476 //               this node.
00477 ////////////////////////////////////////////////////////////////////
00478 XFileDataNode *XFileNode::
00479 add_TextureFilename(const string &name, const Filename &filename) {
00480   XFileTemplate *xtemplate = XFile::find_standard_template("TextureFilename");
00481   nassertr(xtemplate != (XFileTemplate *)NULL, NULL);
00482   XFileDataNodeTemplate *node =
00483     new XFileDataNodeTemplate(get_x_file(), name, xtemplate);
00484   add_child(node);
00485   node->zero_fill();
00486 
00487   (*node)["filename"] = filename.to_os_specific();
00488 
00489   return node;
00490 }
00491 
00492 ////////////////////////////////////////////////////////////////////
00493 //     Function: XFileNode::add_Frame
00494 //       Access: Public
00495 //  Description: Creates a new Frame instance, as a child of this
00496 //               node.
00497 ////////////////////////////////////////////////////////////////////
00498 XFileDataNode *XFileNode::
00499 add_Frame(const string &name) {
00500   XFileTemplate *xtemplate = XFile::find_standard_template("Frame");
00501   nassertr(xtemplate != (XFileTemplate *)NULL, NULL);
00502   XFileDataNodeTemplate *node =
00503     new XFileDataNodeTemplate(get_x_file(), name, xtemplate);
00504   add_child(node);
00505   node->zero_fill();
00506 
00507   return node;
00508 }
00509 
00510 ////////////////////////////////////////////////////////////////////
00511 //     Function: XFileNode::add_FrameTransformMatrix
00512 //       Access: Public
00513 //  Description: Creates a new FrameTransformMatrix instance, as a
00514 //               child of this node.
00515 ////////////////////////////////////////////////////////////////////
00516 XFileDataNode *XFileNode::
00517 add_FrameTransformMatrix(const LMatrix4d &mat) {
00518   XFileTemplate *xtemplate = 
00519     XFile::find_standard_template("FrameTransformMatrix");
00520   nassertr(xtemplate != (XFileTemplate *)NULL, NULL);
00521   XFileDataNodeTemplate *node = 
00522     new XFileDataNodeTemplate(get_x_file(), "", xtemplate);
00523   add_child(node);
00524   node->zero_fill();
00525 
00526   XFileDataObject &xmat = (*node)["frameMatrix"]["matrix"];
00527   xmat[0] = mat(0, 0);
00528   xmat[1] = mat(0, 1);
00529   xmat[2] = mat(0, 2);
00530   xmat[3] = mat(0, 3);
00531 
00532   xmat[4] = mat(1, 0);
00533   xmat[5] = mat(1, 1);
00534   xmat[6] = mat(1, 2);
00535   xmat[7] = mat(1, 3);
00536 
00537   xmat[8] = mat(2, 0);
00538   xmat[9] = mat(2, 1);
00539   xmat[10] = mat(2, 2);
00540   xmat[11] = mat(2, 3);
00541 
00542   xmat[12] = mat(3, 0);
00543   xmat[13] = mat(3, 1);
00544   xmat[14] = mat(3, 2);
00545   xmat[15] = mat(3, 3);
00546 
00547   return node;
00548 }
00549 
00550 ////////////////////////////////////////////////////////////////////
00551 //     Function: XFileNode::make_nice_name
00552 //       Access: Protected, Static
00553 //  Description: Transforms the indicated egg name to a name that is
00554 //               acceptable for a node in the X File format.
00555 ////////////////////////////////////////////////////////////////////
00556 string XFileNode::
00557 make_nice_name(const string &str) {
00558   string result;
00559 
00560   string::const_iterator si;
00561   for (si = str.begin(); si != str.end(); ++si) {
00562     if (isalnum(*si)) {
00563       result += (*si);
00564     } else {
00565       switch (*si) {
00566       case '-':
00567         result += (*si);
00568         break;
00569       default:
00570         result += "_";
00571       }
00572     }
00573   }
00574 
00575   if (str.empty() || isdigit(str[0])) {
00576     // If the name begins with a digit, or if it
00577     // is empty, then we must make it begin with
00578     // something else, like for instance an underscore.
00579     result = '_' + result;
00580   }
00581 
00582   return result;
00583 }
 All Classes Functions Variables Enumerations