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