xFileNode.cxx 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582
  1. // Filename: xFileNode.cxx
  2. // Created by: drose (03Oct04)
  3. //
  4. ////////////////////////////////////////////////////////////////////
  5. //
  6. // PANDA 3D SOFTWARE
  7. // Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
  8. //
  9. // All use of this software is subject to the terms of the Panda 3d
  10. // Software license. You should have received a copy of this license
  11. // along with this source code; you will also find a current copy of
  12. // the license at http://etc.cmu.edu/panda3d/docs/license/ .
  13. //
  14. // To contact the maintainers of this program write to
  15. // [email protected] .
  16. //
  17. ////////////////////////////////////////////////////////////////////
  18. #include "xFileNode.h"
  19. #include "windowsGuid.h"
  20. #include "xFile.h"
  21. #include "xLexerDefs.h"
  22. #include "xFileParseData.h"
  23. #include "xFile.h"
  24. #include "xFileDataNodeTemplate.h"
  25. #include "filename.h"
  26. #include "string_utils.h"
  27. TypeHandle XFileNode::_type_handle;
  28. ////////////////////////////////////////////////////////////////////
  29. // Function: XFileNode::Constructor
  30. // Access: Public
  31. // Description:
  32. ////////////////////////////////////////////////////////////////////
  33. XFileNode::
  34. XFileNode(XFile *x_file, const string &name) :
  35. Namable(make_nice_name(name)),
  36. _x_file(x_file)
  37. {
  38. }
  39. ////////////////////////////////////////////////////////////////////
  40. // Function: XFileNode::Destructor
  41. // Access: Public, Virtual
  42. // Description:
  43. ////////////////////////////////////////////////////////////////////
  44. XFileNode::
  45. ~XFileNode() {
  46. clear();
  47. }
  48. ////////////////////////////////////////////////////////////////////
  49. // Function: XFileNode::find_child
  50. // Access: Public
  51. // Description: Returns the child with the indicated name, if any, or
  52. // NULL if none.
  53. ////////////////////////////////////////////////////////////////////
  54. XFileNode *XFileNode::
  55. find_child(const string &name) const {
  56. ChildrenByName::const_iterator ni;
  57. ni = _children_by_name.find(downcase(name));
  58. if (ni != _children_by_name.end()) {
  59. return get_child((*ni).second);
  60. }
  61. return NULL;
  62. }
  63. ////////////////////////////////////////////////////////////////////
  64. // Function: XFileNode::find_child_index
  65. // Access: Public
  66. // Description: Returns the index number of the child with the
  67. // indicated name, if any, or -1 if none.
  68. ////////////////////////////////////////////////////////////////////
  69. int XFileNode::
  70. find_child_index(const string &name) const {
  71. ChildrenByName::const_iterator ni;
  72. ni = _children_by_name.find(downcase(name));
  73. if (ni != _children_by_name.end()) {
  74. return (*ni).second;
  75. }
  76. return -1;
  77. }
  78. ////////////////////////////////////////////////////////////////////
  79. // Function: XFileNode::find_child_index
  80. // Access: Public
  81. // Description: Returns the index number of the indicated child,
  82. // or -1 if none.
  83. ////////////////////////////////////////////////////////////////////
  84. int XFileNode::
  85. find_child_index(const XFileNode *child) const {
  86. for (int i = 0; i < (int)_children.size(); i++) {
  87. if (_children[i] == child) {
  88. return i;
  89. }
  90. }
  91. return -1;
  92. }
  93. ////////////////////////////////////////////////////////////////////
  94. // Function: XFileNode::find_descendent
  95. // Access: Public
  96. // Description: Returns the first child or descendent found with the
  97. // indicated name after a depth-first search, if any, or
  98. // NULL if none.
  99. ////////////////////////////////////////////////////////////////////
  100. XFileNode *XFileNode::
  101. find_descendent(const string &name) const {
  102. XFileNode *child = find_child(name);
  103. if (child != (XFileNode *)NULL) {
  104. return child;
  105. }
  106. Children::const_iterator ci;
  107. for (ci = _children.begin(); ci != _children.end(); ++ci) {
  108. XFileNode *child = (*ci)->find_descendent(name);
  109. if (child != (XFileNode *)NULL){
  110. return child;
  111. }
  112. }
  113. return NULL;
  114. }
  115. ////////////////////////////////////////////////////////////////////
  116. // Function: XFileNode::has_guid
  117. // Access: Public, Virtual
  118. // Description: Returns true if this node has a GUID associated.
  119. ////////////////////////////////////////////////////////////////////
  120. bool XFileNode::
  121. has_guid() const {
  122. return false;
  123. }
  124. ////////////////////////////////////////////////////////////////////
  125. // Function: XFileNode::get_guid
  126. // Access: Public, Virtual
  127. // Description: If has_guid() returned true, returns the particular
  128. // GUID associated with this node.
  129. ////////////////////////////////////////////////////////////////////
  130. const WindowsGuid &XFileNode::
  131. get_guid() const {
  132. static WindowsGuid empty;
  133. return empty;
  134. }
  135. ////////////////////////////////////////////////////////////////////
  136. // Function: XFileNode::is_template_def
  137. // Access: Public, Virtual
  138. // Description: Returns true if this node represents the definition
  139. // of some template. This is the template definition,
  140. // not an actual data object that represents an instance
  141. // of the template. If the file strictly uses standard
  142. // templates, the presence of template definitions is
  143. // optional.
  144. //
  145. // If this returns true, the node must be of type
  146. // XFileTemplate.
  147. ////////////////////////////////////////////////////////////////////
  148. bool XFileNode::
  149. is_template_def() const {
  150. return false;
  151. }
  152. ////////////////////////////////////////////////////////////////////
  153. // Function: XFileNode::is_reference
  154. // Access: Public, Virtual
  155. // Description: Returns true if this node represents an indirect
  156. // reference to an object defined previously in the
  157. // file. References are generally transparent, so in
  158. // most cases you never need to call this, unless you
  159. // actually need to differentiate between references and
  160. // instances; you can simply use the reference node as
  161. // if it were itself the object it references.
  162. //
  163. // If this returns true, the node must be of type
  164. // XFileDataNodeReference.
  165. ////////////////////////////////////////////////////////////////////
  166. bool XFileNode::
  167. is_reference() const {
  168. return false;
  169. }
  170. ////////////////////////////////////////////////////////////////////
  171. // Function: XFileNode::is_object
  172. // Access: Public, Virtual
  173. // Description: Returns true if this node represents a data object
  174. // that is the instance of some template, or false
  175. // otherwise. This also returns true for references to
  176. // objects (which are generally treated just like the
  177. // objects themselves).
  178. //
  179. // If this returns true, the node must be of type
  180. // XFileDataNode (it is either an XFileDataNodeTemplate
  181. // or an XFileDataNodeReference).
  182. ////////////////////////////////////////////////////////////////////
  183. bool XFileNode::
  184. is_object() const {
  185. return false;
  186. }
  187. ////////////////////////////////////////////////////////////////////
  188. // Function: XFileNode::is_standard_object
  189. // Access: Public, Virtual
  190. // Description: Returns true if this node represents an instance of
  191. // the standard template with the indicated name, or
  192. // false otherwise. This returns also returns true for
  193. // references to standard objects.
  194. //
  195. // If this returns true, the node must be of type
  196. // XFileDataNode (it is either an XFileDataNodeTemplate
  197. // or an XFileDataNodeReference).
  198. ////////////////////////////////////////////////////////////////////
  199. bool XFileNode::
  200. is_standard_object(const string &template_name) const {
  201. return false;
  202. }
  203. ////////////////////////////////////////////////////////////////////
  204. // Function: XFileNode::add_child
  205. // Access: Public
  206. // Description: Adds the indicated node as a child of this node.
  207. ////////////////////////////////////////////////////////////////////
  208. void XFileNode::
  209. add_child(XFileNode *node) {
  210. if (node->has_name()) {
  211. _children_by_name[downcase(node->get_name())] = (int)_children.size();
  212. }
  213. if (node->has_guid()) {
  214. _x_file->_nodes_by_guid[node->get_guid()] = node;
  215. }
  216. if (node->is_of_type(XFileDataNode::get_class_type())) {
  217. _objects.push_back(DCAST(XFileDataNode, node));
  218. }
  219. _children.push_back(node);
  220. }
  221. ////////////////////////////////////////////////////////////////////
  222. // Function: XFileNode::clear
  223. // Access: Public, Virtual
  224. // Description: Removes all children from the node, and otherwise
  225. // resets it to its initial state.
  226. ////////////////////////////////////////////////////////////////////
  227. void XFileNode::
  228. clear() {
  229. _children.clear();
  230. _objects.clear();
  231. _children_by_name.clear();
  232. }
  233. ////////////////////////////////////////////////////////////////////
  234. // Function: XFileNode::write_text
  235. // Access: Public, Virtual
  236. // Description: Writes a suitable representation of this node to an
  237. // .x file in text mode.
  238. ////////////////////////////////////////////////////////////////////
  239. void XFileNode::
  240. write_text(ostream &out, int indent_level) const {
  241. Children::const_iterator ci;
  242. for (ci = _children.begin(); ci != _children.end(); ++ci) {
  243. (*ci)->write_text(out, indent_level);
  244. }
  245. }
  246. ////////////////////////////////////////////////////////////////////
  247. // Function: XFileNode::repack_data
  248. // Access: Public, Virtual
  249. // Description: This is called on the template that defines an
  250. // object, once the data for the object has been parsed.
  251. // It is responsible for identifying which component of
  252. // the template owns each data element, and packing the
  253. // data elements appropriately back into the object.
  254. //
  255. // It returns true on success, or false on an error
  256. // (e.g. not enough data elements, mismatched data
  257. // type).
  258. ////////////////////////////////////////////////////////////////////
  259. bool XFileNode::
  260. repack_data(XFileDataObject *object,
  261. const XFileParseDataList &parse_data_list,
  262. XFileNode::PrevData &prev_data,
  263. size_t &index, size_t &sub_index) const {
  264. // This method should be specialized for data types that actually
  265. // consume a data element. Here in the base class, it just walks
  266. // through its children, asking each one to pull off the appropriate
  267. // number of data elements.
  268. Children::const_iterator ci;
  269. for (ci = _children.begin(); ci != _children.end(); ++ci) {
  270. if (!(*ci)->repack_data(object, parse_data_list,
  271. prev_data, index, sub_index)) {
  272. return false;
  273. }
  274. }
  275. return true;
  276. }
  277. ////////////////////////////////////////////////////////////////////
  278. // Function: XFileNode::fill_zero_data
  279. // Access: Public, Virtual
  280. // Description: This is similar to repack_data(), except it is used
  281. // to fill the initial values for a newly-created
  282. // template object to zero.
  283. ////////////////////////////////////////////////////////////////////
  284. bool XFileNode::
  285. fill_zero_data(XFileDataObject *object) const {
  286. Children::const_iterator ci;
  287. for (ci = _children.begin(); ci != _children.end(); ++ci) {
  288. if (!(*ci)->fill_zero_data(object)) {
  289. return false;
  290. }
  291. }
  292. return true;
  293. }
  294. ////////////////////////////////////////////////////////////////////
  295. // Function: XFileNode::matches
  296. // Access: Public, Virtual
  297. // Description: Returns true if the node, particularly a template
  298. // node, is structurally equivalent to the other node
  299. // (which must be of the same type). This checks data
  300. // element types, but does not compare data element
  301. // names.
  302. ////////////////////////////////////////////////////////////////////
  303. bool XFileNode::
  304. matches(const XFileNode *other) const {
  305. if (other->get_type() != get_type()) {
  306. return false;
  307. }
  308. if (other->get_num_children() != get_num_children()) {
  309. return false;
  310. }
  311. for (int i = 0; i < get_num_children(); i++) {
  312. if (!get_child(i)->matches(other->get_child(i))) {
  313. return false;
  314. }
  315. }
  316. return true;
  317. }
  318. ////////////////////////////////////////////////////////////////////
  319. // Function: XFileNode::add_Mesh
  320. // Access: Public
  321. // Description: Creates a new Mesh instance, as a child of this node.
  322. ////////////////////////////////////////////////////////////////////
  323. XFileDataNode *XFileNode::
  324. add_Mesh(const string &name) {
  325. XFileTemplate *xtemplate = XFile::find_standard_template("Mesh");
  326. nassertr(xtemplate != (XFileTemplate *)NULL, NULL);
  327. XFileDataNodeTemplate *node =
  328. new XFileDataNodeTemplate(get_x_file(), name, xtemplate);
  329. add_child(node);
  330. node->zero_fill();
  331. return node;
  332. }
  333. ////////////////////////////////////////////////////////////////////
  334. // Function: XFileNode::add_MeshNormals
  335. // Access: Public
  336. // Description: Creates a new MeshNormals instance, as a child of
  337. // this node.
  338. ////////////////////////////////////////////////////////////////////
  339. XFileDataNode *XFileNode::
  340. add_MeshNormals(const string &name) {
  341. XFileTemplate *xtemplate = XFile::find_standard_template("MeshNormals");
  342. nassertr(xtemplate != (XFileTemplate *)NULL, NULL);
  343. XFileDataNodeTemplate *node =
  344. new XFileDataNodeTemplate(get_x_file(), name, xtemplate);
  345. add_child(node);
  346. node->zero_fill();
  347. return node;
  348. }
  349. ////////////////////////////////////////////////////////////////////
  350. // Function: XFileNode::add_MeshVertexColors
  351. // Access: Public
  352. // Description: Creates a new MeshVertexColors instance, as a child of
  353. // this node.
  354. ////////////////////////////////////////////////////////////////////
  355. XFileDataNode *XFileNode::
  356. add_MeshVertexColors(const string &name) {
  357. XFileTemplate *xtemplate = XFile::find_standard_template("MeshVertexColors");
  358. nassertr(xtemplate != (XFileTemplate *)NULL, NULL);
  359. XFileDataNodeTemplate *node =
  360. new XFileDataNodeTemplate(get_x_file(), name, xtemplate);
  361. add_child(node);
  362. node->zero_fill();
  363. return node;
  364. }
  365. ////////////////////////////////////////////////////////////////////
  366. // Function: XFileNode::add_MeshTextureCoords
  367. // Access: Public
  368. // Description: Creates a new MeshTextureCoords instance, as a child of
  369. // this node.
  370. ////////////////////////////////////////////////////////////////////
  371. XFileDataNode *XFileNode::
  372. add_MeshTextureCoords(const string &name) {
  373. XFileTemplate *xtemplate = XFile::find_standard_template("MeshTextureCoords");
  374. nassertr(xtemplate != (XFileTemplate *)NULL, NULL);
  375. XFileDataNodeTemplate *node =
  376. new XFileDataNodeTemplate(get_x_file(), name, xtemplate);
  377. add_child(node);
  378. node->zero_fill();
  379. return node;
  380. }
  381. ////////////////////////////////////////////////////////////////////
  382. // Function: XFileNode::add_MeshMaterialList
  383. // Access: Public
  384. // Description: Creates a new MeshMaterialList instance, as a child of
  385. // this node.
  386. ////////////////////////////////////////////////////////////////////
  387. XFileDataNode *XFileNode::
  388. add_MeshMaterialList(const string &name) {
  389. XFileTemplate *xtemplate = XFile::find_standard_template("MeshMaterialList");
  390. nassertr(xtemplate != (XFileTemplate *)NULL, NULL);
  391. XFileDataNodeTemplate *node =
  392. new XFileDataNodeTemplate(get_x_file(), name, xtemplate);
  393. add_child(node);
  394. node->zero_fill();
  395. return node;
  396. }
  397. ////////////////////////////////////////////////////////////////////
  398. // Function: XFileNode::add_Material
  399. // Access: Public
  400. // Description: Creates a new Material instance, as a child of
  401. // this node.
  402. ////////////////////////////////////////////////////////////////////
  403. XFileDataNode *XFileNode::
  404. add_Material(const string &name, const Colorf &face_color,
  405. double power, const RGBColorf &specular_color,
  406. const RGBColorf &emissive_color) {
  407. XFileTemplate *xtemplate = XFile::find_standard_template("Material");
  408. nassertr(xtemplate != (XFileTemplate *)NULL, NULL);
  409. XFileDataNodeTemplate *node =
  410. new XFileDataNodeTemplate(get_x_file(), name, xtemplate);
  411. add_child(node);
  412. node->zero_fill();
  413. (*node)["faceColor"]["red"] = face_color[0];
  414. (*node)["faceColor"]["green"] = face_color[1];
  415. (*node)["faceColor"]["blue"] = face_color[2];
  416. (*node)["faceColor"]["alpha"] = face_color[3];
  417. (*node)["power"] = power;
  418. (*node)["specularColor"]["red"] = specular_color[0];
  419. (*node)["specularColor"]["green"] = specular_color[1];
  420. (*node)["specularColor"]["blue"] = specular_color[2];
  421. (*node)["emissiveColor"]["red"] = emissive_color[0];
  422. (*node)["emissiveColor"]["green"] = emissive_color[1];
  423. (*node)["emissiveColor"]["blue"] = emissive_color[2];
  424. return node;
  425. }
  426. ////////////////////////////////////////////////////////////////////
  427. // Function: XFileNode::add_TextureFilename
  428. // Access: Public
  429. // Description: Creates a new TextureFilename instance, as a child of
  430. // this node.
  431. ////////////////////////////////////////////////////////////////////
  432. XFileDataNode *XFileNode::
  433. add_TextureFilename(const string &name, const Filename &filename) {
  434. XFileTemplate *xtemplate = XFile::find_standard_template("TextureFilename");
  435. nassertr(xtemplate != (XFileTemplate *)NULL, NULL);
  436. XFileDataNodeTemplate *node =
  437. new XFileDataNodeTemplate(get_x_file(), name, xtemplate);
  438. add_child(node);
  439. node->zero_fill();
  440. (*node)["filename"] = filename.to_os_specific();
  441. return node;
  442. }
  443. ////////////////////////////////////////////////////////////////////
  444. // Function: XFileNode::add_Frame
  445. // Access: Public
  446. // Description: Creates a new Frame instance, as a child of this
  447. // node.
  448. ////////////////////////////////////////////////////////////////////
  449. XFileDataNode *XFileNode::
  450. add_Frame(const string &name) {
  451. XFileTemplate *xtemplate = XFile::find_standard_template("Frame");
  452. nassertr(xtemplate != (XFileTemplate *)NULL, NULL);
  453. XFileDataNodeTemplate *node =
  454. new XFileDataNodeTemplate(get_x_file(), name, xtemplate);
  455. add_child(node);
  456. node->zero_fill();
  457. return node;
  458. }
  459. ////////////////////////////////////////////////////////////////////
  460. // Function: XFileNode::add_FrameTransformMatrix
  461. // Access: Public
  462. // Description: Creates a new FrameTransformMatrix instance, as a
  463. // child of this node.
  464. ////////////////////////////////////////////////////////////////////
  465. XFileDataNode *XFileNode::
  466. add_FrameTransformMatrix(const LMatrix4d &mat) {
  467. XFileTemplate *xtemplate =
  468. XFile::find_standard_template("FrameTransformMatrix");
  469. nassertr(xtemplate != (XFileTemplate *)NULL, NULL);
  470. XFileDataNodeTemplate *node =
  471. new XFileDataNodeTemplate(get_x_file(), "", xtemplate);
  472. add_child(node);
  473. node->zero_fill();
  474. XFileDataObject &xmat = (*node)["frameMatrix"]["matrix"];
  475. xmat[0] = mat(0, 0);
  476. xmat[1] = mat(0, 1);
  477. xmat[2] = mat(0, 2);
  478. xmat[3] = mat(0, 3);
  479. xmat[4] = mat(1, 0);
  480. xmat[5] = mat(1, 1);
  481. xmat[6] = mat(1, 2);
  482. xmat[7] = mat(1, 3);
  483. xmat[8] = mat(2, 0);
  484. xmat[9] = mat(2, 1);
  485. xmat[10] = mat(2, 2);
  486. xmat[11] = mat(2, 3);
  487. xmat[12] = mat(3, 0);
  488. xmat[13] = mat(3, 1);
  489. xmat[14] = mat(3, 2);
  490. xmat[15] = mat(3, 3);
  491. return node;
  492. }
  493. ////////////////////////////////////////////////////////////////////
  494. // Function: XFileNode::make_nice_name
  495. // Access: Protected, Static
  496. // Description: Transforms the indicated egg name to a name that is
  497. // acceptable for a node in the X File format.
  498. ////////////////////////////////////////////////////////////////////
  499. string XFileNode::
  500. make_nice_name(const string &str) {
  501. string result;
  502. string::const_iterator si;
  503. for (si = str.begin(); si != str.end(); ++si) {
  504. if (isalnum(*si)) {
  505. result += (*si);
  506. } else {
  507. switch (*si) {
  508. case '-':
  509. result += (*si);
  510. break;
  511. default:
  512. result += "_";
  513. }
  514. }
  515. }
  516. if (!str.empty() && isdigit(str[0])) {
  517. // If the name begins with a digit, we must make it begin with
  518. // something else, like for instance an underscore.
  519. result = '_' + result;
  520. }
  521. return result;
  522. }