Panda3D
|
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 }