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  */
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  */
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  */
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  */
143 is_template_def() const {
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  */
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  */
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  */
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  */
191 add_child(XFileNode *node) {
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  */
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  */
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  */
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  */
261 fill_zero_data(XFileDataObject *object) const {
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  */
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  */
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 }
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:39
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
A base class for all things which can have a name.
Definition: namable.h:26
bool has_name() const
Returns true if the Namable has a nonempty name set, false if the name is empty.
Definition: namable.I:44
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition: typedObject.I:28
This is an implementation of the Windows GUID object, used everywhere as a world-unique identifier fo...
Definition: windowsGuid.h:26
This is a node which contains all of the data elements defined by a template.
void zero_fill()
Fills the data node with zero-valued elements appropriate to the template.
This is an abstract base class for an XFileNode which is also an XFileDataObject.
Definition: xFileDataNode.h:33
The abstract base class for a number of different types of data elements that may be stored in the X ...
A single node of an X file.
Definition: xFileNode.h:40
virtual bool has_guid() const
Returns true if this node has a GUID associated.
Definition: xFileNode.cxx:120
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_Frame(const std::string &name)
Creates a new Frame instance, as a child of this node.
Definition: xFileNode.cxx:421
XFileDataNode * add_MeshTextureCoords(const std::string &name)
Creates a new MeshTextureCoords instance, as a child of this node.
Definition: xFileNode.cxx:345
virtual const WindowsGuid & get_guid() const
If has_guid() returned true, returns the particular GUID associated with this node.
Definition: xFileNode.cxx:129
int get_num_children() const
Returns the list of children of this node.
Definition: xFileNode.I:37
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
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
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_TextureFilename(const std::string &name, const Filename &filename)
Creates a new TextureFilename instance, as a child of this node.
Definition: xFileNode.cxx:404
virtual bool is_template_def() const
Returns true if this node represents the definition of some template.
Definition: xFileNode.cxx:143
XFileDataNode * add_MeshVertexColors(const std::string &name)
Creates a new MeshVertexColors instance, as a child of this node.
Definition: xFileNode.cxx:330
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
void add_child(XFileNode *node)
Adds the indicated node as a child of this node.
Definition: xFileNode.cxx:191
XFileDataNode * add_MeshNormals(const std::string &name)
Creates a new MeshNormals instance, as a child of this node.
Definition: xFileNode.cxx:315
XFileDataNode * add_FrameTransformMatrix(const LMatrix4d &mat)
Creates a new FrameTransformMatrix instance, as a child of this node.
Definition: xFileNode.cxx:436
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
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
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
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
XFileDataNode * add_MeshMaterialList(const std::string &name)
Creates a new MeshMaterialList instance, as a child of this node.
Definition: xFileNode.cxx:360
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
XFileNode * get_child(int n) const
Returns the nth child of this node.
Definition: xFileNode.I:46
XFileDataNode * add_Mesh(const std::string &name)
Creates a new Mesh instance, as a child of this node.
Definition: xFileNode.cxx:300
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
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
A container for a pvector of the above objects.
A template definition in the X file.
Definition: xFileTemplate.h:27
This represents the complete contents of an X file (file.x) in memory.
Definition: xFile.h:32
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
This is our own Panda specialization on the default STL map.
Definition: pmap.h:49
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
string downcase(const string &s)
Returns the input string with all uppercase letters converted to lowercase.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.