Panda3D
eggGroupNode.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 eggGroupNode.cxx
10  * @author drose
11  * @date 1999-01-16
12  */
13 
14 #include "eggGroupNode.h"
15 #include "eggGroup.h"
16 #include "eggCoordinateSystem.h"
17 #include "eggData.h"
18 #include "eggFilenameNode.h"
19 #include "eggExternalReference.h"
20 #include "eggPrimitive.h"
21 #include "eggPoint.h"
22 #include "eggPolygon.h"
23 #include "eggCompositePrimitive.h"
24 #include "eggMesher.h"
25 #include "eggVertexPool.h"
26 #include "eggVertex.h"
27 #include "eggTextureCollection.h"
28 #include "eggMaterialCollection.h"
29 #include "epvector.h"
30 #include "pt_EggTexture.h"
31 #include "pt_EggMaterial.h"
32 #include "config_egg.h"
33 
34 #include "dSearchPath.h"
35 #include "virtualFileSystem.h"
36 #include "deg_2_rad.h"
37 #include "dcast.h"
38 #include "bamCacheRecord.h"
39 
40 #include <algorithm>
41 
42 using std::string;
43 
44 TypeHandle EggGroupNode::_type_handle;
45 
46 
47 /**
48  *
49  */
50 EggGroupNode::
51 EggGroupNode(const EggGroupNode &copy) : EggNode(copy) {
52  if (!copy.empty()) {
53  egg_cat.warning()
54  << "The EggGroupNode copy constructor does not copy children!\n";
55  }
56 }
57 
58 /**
59  *
60  */
61 EggGroupNode &EggGroupNode::
62 operator =(const EggGroupNode &copy) {
63  if (!copy.empty()) {
64  egg_cat.warning()
65  << "The EggGroupNode copy assignment does not copy children!\n";
66  }
67  EggNode::operator =(copy);
68  return *this;
69 }
70 
71 /**
72  *
73  */
74 EggGroupNode::
75 ~EggGroupNode() {
76 }
77 
78 
79 /**
80  * Writes the group and all of its children to the indicated output stream in
81  * Egg format.
82  */
83 void EggGroupNode::
84 write(std::ostream &out, int indent_level) const {
85  iterator i;
86 
87  // Since joints tend to reference vertex pools, which sometimes appear later
88  // in the file, and since generally non-joints don't reference joints, we
89  // try to maximize our chance of writing out a one-pass readable egg file by
90  // writing joints at the end of the list of children of a particular node.
91 
92  for (i = begin(); i != end(); ++i) {
93  PT(EggNode) child = (*i);
94  if (!child->is_joint()) {
95  child->write(out, indent_level);
96  }
97  }
98 
99  for (i = begin(); i != end(); ++i) {
100  PT(EggNode) child = (*i);
101  if (child->is_joint()) {
102  child->write(out, indent_level);
103  }
104  }
105 }
106 
107 /**
108  *
109  */
110 EggGroupNode::iterator EggGroupNode::
111 begin() const {
112  return _children.begin();
113 }
114 
115 /**
116  *
117  */
118 EggGroupNode::iterator EggGroupNode::
119 end() const {
120  return _children.end();
121 }
122 
123 /**
124  *
125  */
126 EggGroupNode::reverse_iterator EggGroupNode::
127 rbegin() const {
128  return _children.rbegin();
129 }
130 
131 /**
132  *
133  */
134 EggGroupNode::reverse_iterator EggGroupNode::
135 rend() const {
136  return _children.rend();
137 }
138 
139 /**
140  *
141  */
142 EggGroupNode::iterator EggGroupNode::
143 insert(iterator position, PT(EggNode) x) {
144  prepare_add_child(x);
145  return _children.insert((Children::iterator &)position, x);
146 }
147 
148 /**
149  *
150  */
151 EggGroupNode::iterator EggGroupNode::
152 erase(iterator position) {
153  prepare_remove_child(*position);
154  return _children.erase((Children::iterator &)position);
155 }
156 
157 /**
158  *
159  */
160 EggGroupNode::iterator EggGroupNode::
161 erase(iterator first, iterator last) {
162  iterator i;
163  for (i = first; i != last; ++i) {
164  prepare_remove_child(*i);
165  }
166  return _children.erase((Children::iterator &)first,
167  (Children::iterator &)last);
168 }
169 
170 /**
171  * Replaces the node at the indicated position with the indicated node. It is
172  * an error to call this with an invalid position iterator (e.g. end()).
173  */
174 void EggGroupNode::
175 replace(iterator position, PT(EggNode) x) {
176  nassertv(position != end());
177 
178  prepare_remove_child(*position);
179  prepare_add_child(x);
180  *(Children::iterator &)position = x;
181 }
182 
183 /**
184  *
185  */
186 bool EggGroupNode::
187 empty() const {
188  return _children.empty();
189 }
190 
191 /**
192  *
193  */
194 EggGroupNode::size_type EggGroupNode::
195 size() const {
196  return _children.size();
197 }
198 
199 /**
200  *
201  */
202 void EggGroupNode::
203 clear() {
204  erase(begin(), end());
205 }
206 
207 /**
208  * Returns the first child in the group's list of children, or NULL if the
209  * list of children is empty. Can be used with get_next_child() to return the
210  * complete list of children without using the iterator class; however, this
211  * is non-thread-safe, and so is not recommended except for languages other
212  * than C++ which cannot use the iterators.
213  */
216  _gnc_iterator = begin();
217  return get_next_child();
218 }
219 
220 /**
221  * Returns the next child in the group's list of children since the last call
222  * to get_first_child() or get_next_child(), or NULL if the last child has
223  * been returned. Can be used with get_first_child() to return the complete
224  * list of children without using the iterator class; however, this is non-
225  * thread-safe, and so is not recommended except for languages other than C++
226  * which cannot use the iterators.
227  *
228  * It is an error to call this without previously calling get_first_child().
229  */
232  if (_gnc_iterator != end()) {
233  return *_gnc_iterator++;
234  }
235  return nullptr;
236 }
237 
238 /**
239  * Adds the indicated child to the group and returns it. If the child node is
240  * already a child of some other node, removes it first.
241  */
245  PT(EggNode) ptnode = node;
246  if (node->_parent != nullptr) {
247  node->_parent->remove_child(node);
248  }
249  prepare_add_child(node);
250  _children.push_back(node);
251  return node;
252 }
253 
254 /**
255  * Removes the indicated child node from the group and returns it. If the
256  * child was not already in the group, does nothing and returns NULL.
257  */
258 PT(EggNode) EggGroupNode::
259 remove_child(EggNode *node) {
260  PT(EggNode) ptnode = node;
261  iterator i = find(begin(), end(), ptnode);
262  if (i == end()) {
263  return PT(EggNode)();
264  } else {
265  // erase() calls prepare_remove_child().
266  erase(i);
267  return ptnode;
268  }
269 }
270 
271 
272 /**
273  * Moves all the children from the other node to this one. This is especially
274  * useful because the group node copy assignment operator does not copy
275  * children.
276  */
277 void EggGroupNode::
279  Children::iterator ci;
280  for (ci = other._children.begin();
281  ci != other._children.end();
282  ++ci) {
283  other.prepare_remove_child(*ci);
284  prepare_add_child(*ci);
285  }
286 
287  _children.splice(_children.end(), other._children);
288 }
289 
290 /**
291  * Returns the child of this node whose name is the indicated string, or NULL
292  * if there is no child of this node by that name. Does not search
293  * recursively.
294  */
296 find_child(const string &name) const {
297  Children::const_iterator ci;
298  for (ci = _children.begin(); ci != _children.end(); ++ci) {
299  EggNode *child = (*ci);
300  if (child->get_name() == name) {
301  return child;
302  }
303  }
304 
305  return nullptr;
306 }
307 
308 /**
309  * Returns true if any nodes at this level and below include a reference to a
310  * file via an absolute pathname, or false if all references are relative.
311  */
312 bool EggGroupNode::
314  Children::const_iterator ci;
315  for (ci = _children.begin();
316  ci != _children.end();
317  ++ci) {
318  EggNode *child = *ci;
319  if (child->is_of_type(EggTexture::get_class_type())) {
320  EggTexture *tex = DCAST(EggTexture, child);
321  if (!tex->get_filename().is_local()) {
322  if (egg_cat.is_debug()) {
323  egg_cat.debug()
324  << "Absolute pathname: " << tex->get_filename()
325  << "\n";
326  }
327  return true;
328  }
329 
330  if (tex->has_alpha_filename()) {
331  if (!tex->get_alpha_filename().is_local()) {
332  if (egg_cat.is_debug()) {
333  egg_cat.debug()
334  << "Absolute pathname: " << tex->get_alpha_filename()
335  << "\n";
336  }
337  return true;
338  }
339  }
340 
341  } else if (child->is_of_type(EggFilenameNode::get_class_type())) {
342  EggFilenameNode *fnode = DCAST(EggFilenameNode, child);
343  if (!fnode->get_filename().is_local()) {
344  if (egg_cat.is_debug()) {
345  egg_cat.debug()
346  << "Absolute pathname: " << fnode->get_filename()
347  << "\n";
348  }
349  return true;
350  }
351 
352  } else if (child->is_of_type(EggGroupNode::get_class_type())) {
353  if (DCAST(EggGroupNode, child)->has_absolute_pathnames()) {
354  return true;
355  }
356  }
357  }
358 
359  return false;
360 }
361 
362 /**
363  * Walks the tree and attempts to resolve any filenames encountered. This
364  * looks up filenames along the specified search path; it does not
365  * automatically search the model_path for missing files.
366  */
367 void EggGroupNode::
368 resolve_filenames(const DSearchPath &searchpath) {
370 
371  Children::iterator ci;
372  for (ci = _children.begin();
373  ci != _children.end();
374  ++ci) {
375  EggNode *child = *ci;
376  if (child->is_of_type(EggTexture::get_class_type())) {
377  EggTexture *tex = DCAST(EggTexture, child);
378  Filename tex_filename = tex->get_filename();
379  vfs->resolve_filename(tex_filename, searchpath);
380  tex->set_filename(tex_filename);
381 
382  if (tex->has_alpha_filename()) {
383  Filename alpha_filename = tex->get_alpha_filename();
384  vfs->resolve_filename(alpha_filename, searchpath);
385  tex->set_alpha_filename(alpha_filename);
386  }
387 
388  } else if (child->is_of_type(EggFilenameNode::get_class_type())) {
389  EggFilenameNode *fnode = DCAST(EggFilenameNode, child);
390  Filename filename = fnode->get_filename();
391  vfs->resolve_filename(filename, searchpath, fnode->get_default_extension());
392  fnode->set_filename(filename);
393 
394  } else if (child->is_of_type(EggGroupNode::get_class_type())) {
395  DCAST(EggGroupNode, child)->resolve_filenames(searchpath);
396  }
397  }
398 }
399 
400 /**
401  * Similar to resolve_filenames, but each non-absolute filename encountered is
402  * arbitrarily taken to be in the indicated directory, whether or not the so-
403  * named filename exists.
404  */
405 void EggGroupNode::
406 force_filenames(const Filename &directory) {
407  Children::iterator ci;
408  for (ci = _children.begin();
409  ci != _children.end();
410  ++ci) {
411  EggNode *child = *ci;
412  if (child->is_of_type(EggTexture::get_class_type())) {
413  EggTexture *tex = DCAST(EggTexture, child);
414  Filename tex_filename = tex->get_filename();
415  if (tex_filename.is_local()) {
416  tex->set_filename(Filename(directory, tex_filename));
417  }
418 
419  if (tex->has_alpha_filename()) {
420  Filename alpha_filename = tex->get_alpha_filename();
421  if (alpha_filename.is_local()) {
422  tex->set_alpha_filename(Filename(directory, alpha_filename));
423  }
424  }
425 
426  } else if (child->is_of_type(EggFilenameNode::get_class_type())) {
427  EggFilenameNode *fnode = DCAST(EggFilenameNode, child);
428  Filename filename = fnode->get_filename();
429  if (filename.is_local()) {
430  fnode->set_filename(Filename(directory, filename));
431  }
432 
433  } else if (child->is_of_type(EggGroupNode::get_class_type())) {
434  DCAST(EggGroupNode, child)->force_filenames(directory);
435  }
436  }
437 }
438 
439 /**
440  * Reverses the vertex ordering of all polygons defined at this node and
441  * below. Does not change the surface normals, if any.
442  */
443 void EggGroupNode::
445  Children::iterator ci;
446  for (ci = _children.begin();
447  ci != _children.end();
448  ++ci) {
449  EggNode *child = *ci;
450  if (child->is_of_type(EggPrimitive::get_class_type())) {
451  EggPrimitive *prim = DCAST(EggPrimitive, child);
452  prim->reverse_vertex_ordering();
453 
454  } else if (child->is_of_type(EggGroupNode::get_class_type())) {
455  DCAST(EggGroupNode, child)->reverse_vertex_ordering();
456  }
457  }
458 }
459 
460 /**
461  * Recomputes all the vertex normals for polygon geometry at this group node
462  * and below so that they accurately reflect the vertex positions. A shared
463  * edge between two polygons (even in different groups) is considered smooth
464  * if the angle between the two edges is less than threshold degrees.
465  *
466  * This function also removes degenerate polygons that do not have enough
467  * vertices to define a normal. It does not affect normals for other kinds of
468  * primitives like Nurbs or Points.
469  *
470  * This function does not remove or adjust vertices in the vertex pool; it
471  * only adds new vertices with the correct normals. Thus, it is a good idea
472  * to call remove_unused_vertices() after calling this.
473  */
474 void EggGroupNode::
475 recompute_vertex_normals(double threshold, CoordinateSystem cs) {
476  // First, collect all the vertices together with their shared polygons.
477  NVertexCollection collection;
478  r_collect_vertex_normals(collection, threshold, cs);
479 
480  // Now bust them into separate groups according to the edge threshold. Two
481  // polygons that share a vertex belong in the same group only if the angle
482  // between their normals is within the threshold.
483 
484  double cos_angle = cos(deg_2_rad(threshold));
485 
486  NVertexCollection::iterator ci;
487  for (ci = collection.begin(); ci != collection.end(); ++ci) {
488  NVertexGroup &group = (*ci).second;
489 
490  // Here's a group of polygons that share a vertex. Build up a new group
491  // that consists of just the first polygon and all the ones that are
492  // within threshold degrees from it.
493  NVertexGroup::iterator gi;
494  gi = group.begin();
495  while (gi != group.end()) {
496  const NVertexReference &base_ref = (*gi);
497  NVertexGroup new_group;
498  NVertexGroup leftover_group;
499  new_group.push_back(base_ref);
500  ++gi;
501 
502  while (gi != group.end()) {
503  const NVertexReference &ref = (*gi);
504  double dot = base_ref._normal.dot(ref._normal);
505  if (dot > cos_angle) {
506  // These polygons are close enough to the same angle.
507  new_group.push_back(ref);
508  } else {
509  // These polygons are not.
510  leftover_group.push_back(ref);
511  }
512  ++gi;
513  }
514 
515  // Now new_group is a collection of connected polygons and the vertices
516  // that connect them. Smooth these vertices.
517  do_compute_vertex_normals(new_group);
518 
519  // And reset the group of remaining polygons.
520  group.swap(leftover_group);
521  gi = group.begin();
522  }
523  }
524 }
525 
526 /**
527  * Recomputes all the polygon normals for polygon geometry at this group node
528  * and below so that they accurately reflect the vertex positions. Normals
529  * are removed from the vertices and defined only on polygons, giving the
530  * geometry a faceted appearance.
531  *
532  * This function also removes degenerate polygons that do not have enough
533  * vertices to define a normal. It does not affect normals for other kinds of
534  * primitives like Nurbs or Points.
535  *
536  * This function does not remove or adjust vertices in the vertex pool; it
537  * only adds new vertices with the normals removed. Thus, it is a good idea
538  * to call remove_unused_vertices() after calling this.
539  */
540 void EggGroupNode::
541 recompute_polygon_normals(CoordinateSystem cs) {
542  Children::iterator ci, cnext;
543  ci = _children.begin();
544  while (ci != _children.end()) {
545  cnext = ci;
546  ++cnext;
547  EggNode *child = *ci;
548 
549  if (child->is_of_type(EggPolygon::get_class_type())) {
550  EggPolygon *polygon = DCAST(EggPolygon, child);
551 
552  if (!polygon->recompute_polygon_normal(cs)) {
553  // The polygon is degenerate. Remove it.
554  prepare_remove_child(child);
555  _children.erase(ci);
556 
557  } else {
558  // Remove the normal from each polygon vertex.
559  size_t num_vertices = polygon->size();
560  for (size_t i = 0; i < num_vertices; i++) {
561  EggVertex *vertex = polygon->get_vertex(i);
562  EggVertexPool *pool = vertex->get_pool();
563 
564  if (vertex->has_normal()) {
565  EggVertex new_vertex(*vertex);
566  new_vertex.clear_normal();
567  EggVertex *unique = pool->create_unique_vertex(new_vertex);
568  unique->copy_grefs_from(*vertex);
569 
570  polygon->set_vertex(i, unique);
571  }
572  }
573  }
574 
575  } else if (child->is_of_type(EggGroupNode::get_class_type())) {
576  DCAST(EggGroupNode, child)->recompute_polygon_normals(cs);
577  }
578 
579  ci = cnext;
580  }
581 }
582 
583 /**
584  * Removes all normals from primitives, and the vertices they reference, at
585  * this node and below.
586  *
587  * This function does not remove or adjust vertices in the vertex pool; it
588  * only adds new vertices with the normal removed. Thus, it is a good idea to
589  * call remove_unused_vertices() after calling this.
590  */
591 void EggGroupNode::
593  Children::iterator ci;
594  for (ci = _children.begin(); ci != _children.end(); ++ci) {
595  EggNode *child = *ci;
596 
597  if (child->is_of_type(EggPrimitive::get_class_type())) {
598  EggPrimitive *prim = DCAST(EggPrimitive, child);
599  prim->clear_normal();
600 
601  // Remove the normal from each prim vertex.
602  size_t num_vertices = prim->size();
603  for (size_t i = 0; i < num_vertices; i++) {
604  EggVertex *vertex = prim->get_vertex(i);
605  EggVertexPool *pool = vertex->get_pool();
606 
607  if (vertex->has_normal()) {
608  EggVertex new_vertex(*vertex);
609  new_vertex.clear_normal();
610  EggVertex *unique = pool->create_unique_vertex(new_vertex);
611  unique->copy_grefs_from(*vertex);
612 
613  prim->set_vertex(i, unique);
614  }
615  }
616 
617  } else if (child->is_of_type(EggGroupNode::get_class_type())) {
618  DCAST(EggGroupNode, child)->strip_normals();
619  }
620  }
621 }
622 
623 /**
624  * This function recomputes the tangent and binormal for the named texture
625  * coordinate set for all vertices at this level and below. Use the empty
626  * string for the default texture coordinate set.
627  *
628  * It is necessary for each vertex to already have a normal (or at least a
629  * polygon normal), as well as a texture coordinate in the named texture
630  * coordinate set, before calling this function. You might precede this with
631  * recompute_vertex_normals() to ensure that the normals exist.
632  *
633  * Like recompute_vertex_normals(), this function does not remove or adjust
634  * vertices in the vertex pool; it only adds new vertices with the new
635  * tangents and binormals computed. Thus, it is a good idea to call
636  * remove_unused_vertices() after calling this.
637  */
638 bool EggGroupNode::
640  // First, collect all the vertices together with their shared polygons.
641  TBNVertexCollection collection;
642  r_collect_tangent_binormal(uv_name, collection);
643 
644  // Now compute the tangent and binormal separately for each common group of
645  // vertices.
646  TBNVertexCollection::const_iterator ci;
647  for (ci = collection.begin(); ci != collection.end(); ++ci) {
648  const TBNVertexValue &value = (*ci).first;
649  const TBNVertexGroup &group = (*ci).second;
650 
651  do_compute_tangent_binormal(value, group);
652  }
653 
654  return true;
655 }
656 
657 /**
658  * This function recomputes the tangent and binormal for the named texture
659  * coordinate sets. Returns true if anything was done.
660  */
661 bool EggGroupNode::
662 recompute_tangent_binormal(const vector_string &names) {
663  bool changed = false;
664 
665  for (vector_string::const_iterator si = names.begin();
666  si != names.end();
667  ++si) {
668  GlobPattern uv_name(*si);
669  nout << "Computing tangent and binormal for \"" << uv_name << "\"\n";
671  changed = true;
672  }
673 
674  return changed;
675 }
676 
677 /**
678  * This function recomputes the tangent and binormal for any texture
679  * coordinate set that affects a normal map. Returns true if anything was
680  * done.
681  */
682 bool EggGroupNode::
684  vector_string names;
686  EggTextureCollection::iterator eti;
687  texs.find_used_textures(this);
688  for (eti = texs.begin(); eti != texs.end(); eti++) {
689  EggTexture *eggtex = (*eti);
690  if ((eggtex->get_env_type() == EggTexture::ET_normal)||
691  (eggtex->get_env_type() == EggTexture::ET_normal_height)||
692  (eggtex->get_env_type() == EggTexture::ET_normal_gloss)) {
693  string uv = eggtex->get_uv_name();
694  vector_string::iterator it = find(names.begin(), names.end(), uv);
695  if (it == names.end()) {
696  names.push_back(uv);
697  }
698  }
699  }
700  return recompute_tangent_binormal(names);
701 }
702 
703 /**
704  * Replace all higher-order polygons at this point in the scene graph and
705  * below with triangles. Returns the total number of new triangles produced,
706  * less degenerate polygons removed.
707  *
708  * If flags contains T_polygon and T_convex, both concave and convex polygons
709  * will be subdivided into triangles; with only T_polygon, only concave
710  * polygons will be subdivided, and convex polygons will be largely unchanged.
711  */
712 int EggGroupNode::
714  int num_produced = 0;
715 
716  Children children_copy = _children;
717 
718  Children::iterator ci;
719  for (ci = children_copy.begin();
720  ci != children_copy.end();
721  ++ci) {
722  EggNode *child = (*ci);
723 
724  if (child->is_of_type(EggPolygon::get_class_type())) {
725  if ((flags & T_polygon) != 0) {
726  EggPolygon *poly = DCAST(EggPolygon, child);
727  poly->triangulate_in_place((flags & T_convex) != 0);
728  }
729 
730  } else if (child->is_of_type(EggCompositePrimitive::get_class_type())) {
731  if ((flags & T_composite) != 0) {
732  EggCompositePrimitive *comp = DCAST(EggCompositePrimitive, child);
733  comp->triangulate_in_place();
734  }
735 
736  } else if (child->is_of_type(EggGroupNode::get_class_type())) {
737  if ((flags & T_recurse) != 0) {
738  num_produced += DCAST(EggGroupNode, child)->triangulate_polygons(flags);
739  }
740  }
741  }
742 
743  num_produced += std::max(0, (int)(_children.size() - children_copy.size()));
744  return num_produced;
745 }
746 
747 /**
748  * Combine triangles together into triangle strips, at this group and below.
749  */
750 void EggGroupNode::
751 mesh_triangles(int flags) {
752  EggMesher mesher;
753  mesher.mesh(this, (flags & T_flat_shaded) != 0);
754 
755  if ((flags & T_recurse) != 0) {
756  EggGroupNode::iterator ci;
757  for (ci = begin(); ci != end(); ++ci) {
758  if ((*ci)->is_of_type(EggGroupNode::get_class_type())) {
759  EggGroupNode *group_child = DCAST(EggGroupNode, *ci);
760  group_child->mesh_triangles(flags);
761  }
762  }
763  }
764 }
765 
766 /**
767  * Creates PointLight primitives to reference any otherwise unreferences
768  * vertices discovered in this group or below.
769  */
770 void EggGroupNode::
772  // Create a temporary node to hold the EggPoint objects we might create
773  // while we iterate. (We don't add them during the iteration to avoid
774  // invalidating the iterator.)
775  PT(EggGroupNode) temp = new EggGroup("temp");
776 
777  EggGroupNode::iterator ci;
778  for (ci = begin(); ci != end(); ++ci) {
779  if ((*ci)->is_of_type(EggGroupNode::get_class_type())) {
780  EggGroupNode *group_child = DCAST(EggGroupNode, *ci);
781  group_child->make_point_primitives();
782 
783  } else if ((*ci)->is_of_type(EggVertexPool::get_class_type())) {
784  EggVertexPool *vpool = DCAST(EggVertexPool, *ci);
785  PT(EggPrimitive) prim = new EggPoint;
786  vpool->add_unused_vertices_to_prim(prim);
787  if (!prim->empty()) {
788  temp->add_child(prim);
789  }
790  }
791  }
792 
793  steal_children(*temp);
794 }
795 
796 /**
797  * Rename by stripping out the prefix
798  */
799 int EggGroupNode::
800 rename_nodes(vector_string strip_prefix, bool recurse) {
801  int num_renamed = 0;
802  for (unsigned int ni = 0; ni < strip_prefix.size(); ++ni) {
803  string axe_name = strip_prefix[ni];
804  if (this->get_name().substr(0, axe_name.size()) == axe_name) {
805  string new_name = this->get_name().substr(axe_name.size());
806  // cout << "renaming " << this->get_name() << "->" << new_name << endl;
807  this->set_name(new_name);
808  num_renamed += 1;
809  }
810  }
811  if (recurse) {
812  EggGroupNode::iterator ci;
813  for (ci = begin(); ci != end(); ++ci) {
814  if ((*ci)->is_of_type(EggGroupNode::get_class_type())) {
815  EggGroupNode *group_child = DCAST(EggGroupNode, *ci);
816  num_renamed += group_child->rename_nodes(strip_prefix, recurse);
817  }
818  else if ((*ci)->is_of_type(EggNode::get_class_type())) {
819  EggNode *node_child = DCAST(EggNode, *ci);
820  num_renamed += node_child->rename_node(strip_prefix);
821  }
822  }
823  }
824  return num_renamed;
825 }
826 
827 /**
828  * Removes all vertices from VertexPools within this group or below that are
829  * not referenced by at least one primitive. Also collapses together
830  * equivalent vertices, and renumbers all vertices after the operation so
831  * their indices are consecutive, beginning at zero. Returns the total number
832  * of vertices removed.
833  *
834  * Note that this operates on the VertexPools within this group level, without
835  * respect to primitives that reference these vertices (unlike other functions
836  * like strip_normals()). It is therefore most useful to call this on the
837  * EggData root, rather than on a subgroup within the hierarchy, since a
838  * VertexPool may appear anywhere in the hierarchy.
839  */
840 int EggGroupNode::
841 remove_unused_vertices(bool recurse) {
842  int num_removed = 0;
843 
844  Children::iterator ci, cnext;
845  ci = _children.begin();
846  while (ci != _children.end()) {
847  cnext = ci;
848  ++cnext;
849  EggNode *child = *ci;
850 
851  if (child->is_of_type(EggVertexPool::get_class_type())) {
852  EggVertexPool *vpool = DCAST(EggVertexPool, child);
853  num_removed += vpool->remove_unused_vertices();
854 
855  if (vpool->empty()) {
856  // If, after removing all the vertices, there's nothing left in the
857  // vertex pool, then remove the whole vertex pool.
858  _children.erase(ci);
859  }
860 
861  } else if (child->is_of_type(EggGroupNode::get_class_type())) {
862  if (recurse) {
863  num_removed += DCAST(EggGroupNode, child)->remove_unused_vertices(recurse);
864  }
865  }
866 
867  ci = cnext;
868  }
869 
870  return num_removed;
871 }
872 
873 /**
874  * Removes primitives at this level and below which appear to be degenerate;
875  * e.g. polygons with fewer than 3 vertices, etc. Returns the number of
876  * primitives removed.
877  */
878 int EggGroupNode::
880  int num_removed = 0;
881 
882  Children::iterator ci, cnext;
883  ci = _children.begin();
884  while (ci != _children.end()) {
885  cnext = ci;
886  ++cnext;
887  EggNode *child = *ci;
888 
889  if (child->is_of_type(EggPrimitive::get_class_type())) {
890  EggPrimitive *prim = DCAST(EggPrimitive, child);
891  if (!prim->cleanup()) {
892  _children.erase(ci);
893  num_removed++;
894  }
895 
896  } else if (child->is_of_type(EggGroupNode::get_class_type())) {
897  if (recurse) {
898  num_removed += DCAST(EggGroupNode, child)->remove_invalid_primitives(recurse);
899  }
900  }
901 
902  ci = cnext;
903  }
904 
905  return num_removed;
906 }
907 
908 /**
909  * Resets the connected_shading information on all primitives at this node and
910  * below, so that it may be accurately rederived by the next call to
911  * get_connected_shading().
912  *
913  * It may be a good idea to call remove_unused_vertices() as well, to
914  * establish the correct connectivity between common vertices.
915  */
916 void EggGroupNode::
918  Children::iterator ci;
919  for (ci = _children.begin(); ci != _children.end(); ++ci) {
920  EggNode *child = *ci;
921 
922  if (child->is_of_type(EggPrimitive::get_class_type())) {
923  EggPrimitive *prim = DCAST(EggPrimitive, child);
924  prim->clear_connected_shading();
925  } else if (child->is_of_type(EggGroupNode::get_class_type())) {
926  DCAST(EggGroupNode, child)->clear_connected_shading();
927  }
928  }
929 }
930 
931 /**
932  * Queries the connected_shading information on all primitives at this node
933  * and below, to ensure that it has been completely filled in before we start
934  * mucking around with vertices.
935  */
936 void EggGroupNode::
938  Children::iterator ci;
939  for (ci = _children.begin(); ci != _children.end(); ++ci) {
940  EggNode *child = *ci;
941 
942  if (child->is_of_type(EggPrimitive::get_class_type())) {
943  EggPrimitive *prim = DCAST(EggPrimitive, child);
944  prim->get_connected_shading();
945  } else if (child->is_of_type(EggGroupNode::get_class_type())) {
946  DCAST(EggGroupNode, child)->get_connected_shading();
947  }
948  }
949 }
950 
951 /**
952  * Applies per-vertex normal and color to all vertices, if they are in fact
953  * per-vertex (and different for each vertex), or moves them to the primitive
954  * if they are all the same.
955  *
956  * After this call, either the primitive will have normals or its vertices
957  * will, but not both. Ditto for colors.
958  *
959  * If use_connected_shading is true, each polygon is considered in conjunction
960  * with all connected polygons; otherwise, each polygon is considered
961  * individually.
962  *
963  * If allow_per_primitive is false, S_per_face or S_overall will treated like
964  * S_per_vertex: normals and colors will always be assigned to the vertices.
965  * In this case, there will never be per-primitive colors or normals after
966  * this call returns. On the other hand, if allow_per_primitive is true, then
967  * S_per_face means that normals and colors should be assigned to the
968  * primitives, and removed from the vertices, as described above.
969  *
970  * This may create redundant vertices in the vertex pool, so it may be a good
971  * idea to follow this up with remove_unused_vertices().
972  */
973 void EggGroupNode::
974 unify_attributes(bool use_connected_shading, bool allow_per_primitive,
975  bool recurse) {
976  Children::iterator ci;
977  for (ci = _children.begin(); ci != _children.end(); ++ci) {
978  EggNode *child = *ci;
979 
980  if (child->is_of_type(EggPrimitive::get_class_type())) {
981  EggPrimitive *prim = DCAST(EggPrimitive, child);
982 
983  EggPrimitive::Shading shading = EggPrimitive::S_per_vertex;
984 
985  if (allow_per_primitive) {
986  shading = prim->get_shading();
987  if (use_connected_shading) {
988  shading = prim->get_connected_shading();
989  }
990  }
991 
992  prim->unify_attributes(shading);
993 
994  } else if (child->is_of_type(EggGroupNode::get_class_type())) {
995  if (recurse) {
996  DCAST(EggGroupNode, child)->unify_attributes
997  (use_connected_shading, allow_per_primitive, recurse);
998  }
999  }
1000  }
1001 }
1002 
1003 /**
1004  * Sets the last vertex of the triangle (or each component) to the primitive
1005  * normal and/or color, if the primitive is flat-shaded. This reflects the
1006  * OpenGL convention of storing flat-shaded properties on the last vertex,
1007  * although it is not usually a convention in Egg.
1008  *
1009  * This may create redundant vertices in the vertex pool, so it may be a good
1010  * idea to follow this up with remove_unused_vertices().
1011  */
1012 void EggGroupNode::
1013 apply_last_attribute(bool recurse) {
1014  Children::iterator ci;
1015  for (ci = _children.begin(); ci != _children.end(); ++ci) {
1016  EggNode *child = *ci;
1017 
1018  if (child->is_of_type(EggPrimitive::get_class_type())) {
1019  EggPrimitive *prim = DCAST(EggPrimitive, child);
1020  prim->apply_last_attribute();
1021  } else if (child->is_of_type(EggGroupNode::get_class_type())) {
1022  if (recurse) {
1023  DCAST(EggGroupNode, child)->apply_last_attribute(recurse);
1024  }
1025  }
1026  }
1027 }
1028 
1029 /**
1030  * Sets the first vertex of the triangle (or each component) to the primitive
1031  * normal and/or color, if the primitive is flat-shaded. This reflects the
1032  * DirectX convention of storing flat-shaded properties on the first vertex,
1033  * although it is not usually a convention in Egg.
1034  *
1035  * This may create redundant vertices in the vertex pool, so it may be a good
1036  * idea to follow this up with remove_unused_vertices().
1037  */
1038 void EggGroupNode::
1039 apply_first_attribute(bool recurse) {
1040  Children::iterator ci;
1041  for (ci = _children.begin(); ci != _children.end(); ++ci) {
1042  EggNode *child = *ci;
1043 
1044  if (child->is_of_type(EggPrimitive::get_class_type())) {
1045  EggPrimitive *prim = DCAST(EggPrimitive, child);
1046  prim->apply_first_attribute();
1047  } else if (child->is_of_type(EggGroupNode::get_class_type())) {
1048  if (recurse) {
1049  DCAST(EggGroupNode, child)->apply_first_attribute(recurse);
1050  }
1051  }
1052  }
1053 }
1054 
1055 /**
1056  * Intended as a followup to apply_last_attribute(), this also sets an
1057  * attribute on the first vertices of the primitive, if they don't already
1058  * have an attribute set, just so they end up with *something*.
1059  */
1060 void EggGroupNode::
1062  Children::iterator ci;
1063  for (ci = _children.begin(); ci != _children.end(); ++ci) {
1064  EggNode *child = *ci;
1065 
1066  if (child->is_of_type(EggPrimitive::get_class_type())) {
1067  EggPrimitive *prim = DCAST(EggPrimitive, child);
1068  prim->post_apply_flat_attribute();
1069  } else if (child->is_of_type(EggGroupNode::get_class_type())) {
1070  if (recurse) {
1071  DCAST(EggGroupNode, child)->post_apply_flat_attribute(recurse);
1072  }
1073  }
1074  }
1075 }
1076 
1077 /**
1078  * Returns true if there are any primitives (e.g. polygons) defined within
1079  * this group or below, false otherwise.
1080  */
1081 bool EggGroupNode::
1083  Children::const_iterator ci;
1084  for (ci = _children.begin();
1085  ci != _children.end();
1086  ++ci) {
1087  if ((*ci)->has_primitives()) {
1088  return true;
1089  }
1090  }
1091 
1092  return false;
1093 }
1094 
1095 /**
1096  * Returns true if there are any primitives (e.g. polygons) defined within
1097  * this group or below, but the search does not include nested joints.
1098  */
1099 bool EggGroupNode::
1101  Children::const_iterator ci;
1102  for (ci = _children.begin();
1103  ci != _children.end();
1104  ++ci) {
1105  EggNode *child = (*ci);
1106 
1107  if (!child->is_joint()) {
1108  if (child->joint_has_primitives()) {
1109  return true;
1110  }
1111  }
1112  }
1113 
1114  return false;
1115 }
1116 
1117 /**
1118  * Returns true if any of the primitives (e.g. polygons) defined within this
1119  * group or below have either face or vertex normals defined, false otherwise.
1120  */
1121 bool EggGroupNode::
1122 has_normals() const {
1123  Children::const_iterator ci;
1124  for (ci = _children.begin();
1125  ci != _children.end();
1126  ++ci) {
1127  if ((*ci)->has_normals()) {
1128  return true;
1129  }
1130  }
1131 
1132  return false;
1133 }
1134 
1135 /**
1136  * Copies vertices used by the primitives at this group node (and below, if
1137  * recurse is true) into one or more new vertex pools, and updates the
1138  * primitives to reference these pools. It is up to the caller to parent the
1139  * newly-created vertex pools somewhere appropriate in the egg hierarchy.
1140  *
1141  * No more than max_vertices will be placed into any one vertex pool. This is
1142  * the sole criteria for splitting vertex pools.
1143  */
1144 void EggGroupNode::
1145 rebuild_vertex_pools(EggVertexPools &vertex_pools, unsigned int max_vertices,
1146  bool recurse) {
1147  Children::iterator ci;
1148  for (ci = _children.begin(); ci != _children.end(); ++ci) {
1149  EggNode *child = *ci;
1150 
1151  if (child->is_of_type(EggPrimitive::get_class_type())) {
1152  typedef pvector< PT(EggVertex) > Vertices;
1153  Vertices vertices;
1154  EggPrimitive *prim = DCAST(EggPrimitive, child);
1155 
1156  // Copy all of the vertices out.
1157  EggPrimitive::const_iterator pi;
1158  for (pi = prim->begin(); pi != prim->end(); ++pi) {
1159  vertices.push_back(*pi);
1160  }
1161 
1162  typedef epvector<EggAttributes> Attributes;
1163  Attributes attributes;
1164 
1165  if (prim->is_of_type(EggCompositePrimitive::get_class_type())) {
1166  // A compositive primitive has the additional complication of dealing
1167  // with its attributes.
1168  EggCompositePrimitive *cprim = DCAST(EggCompositePrimitive, prim);
1169  int i;
1170  int num_components = cprim->get_num_components();
1171  for (i = 0; i < num_components; i++) {
1172  attributes.push_back(*cprim->get_component(i));
1173  }
1174  }
1175 
1176  prim->clear();
1177 
1178  // Now look for a new home for the vertices. First, see if any of the
1179  // vertex pools we've already created already have a copy of each one of
1180  // the vertices.
1181  bool found_pool = false;
1182  EggVertexPool *best_pool = nullptr;
1183  int best_new_vertices = 0;
1184 
1185  Vertices new_vertices;
1186  EggVertexPools::iterator vpi;
1187  for (vpi = vertex_pools.begin();
1188  vpi != vertex_pools.end() && !found_pool;
1189  ++vpi) {
1190  EggVertexPool *vertex_pool = (*vpi);
1191  int num_new_vertices = 0;
1192 
1193  new_vertices.clear();
1194  new_vertices.reserve(vertices.size());
1195 
1196  Vertices::const_iterator vi;
1197  for (vi = vertices.begin();
1198  vi != vertices.end() && !found_pool;
1199  ++vi) {
1200  EggVertex *vertex = (*vi);
1201  EggVertex *new_vertex = vertex_pool->find_matching_vertex(*vertex);
1202  new_vertices.push_back(new_vertex);
1203  if (new_vertex == nullptr) {
1204  ++num_new_vertices;
1205  }
1206  }
1207 
1208  if (num_new_vertices == 0) {
1209  // Great, we found a vertex pool that already shares all these
1210  // vertices. No need to look any further.
1211  found_pool = true;
1212 
1213  } else if (vertex_pool->size() + num_new_vertices <= max_vertices) {
1214  // We would have to add some vertices to this pool, so this vertex
1215  // pool qualifies only if the number of vertices we have to add
1216  // would still keep it within our limit.
1217  if (best_pool == nullptr ||
1218  num_new_vertices < best_new_vertices) {
1219  // This is currently our most favorable vertex pool.
1220  best_pool = vertex_pool;
1221  best_new_vertices = num_new_vertices;
1222  }
1223  }
1224  }
1225 
1226  if (!found_pool) {
1227  if (best_pool == nullptr) {
1228  // There was no vertex pool that qualified. We will have to create
1229  // a new vertex pool.
1230  best_pool = new EggVertexPool("");
1231  vertex_pools.push_back(best_pool);
1232  }
1233 
1234  new_vertices.clear();
1235  new_vertices.reserve(vertices.size());
1236 
1237  Vertices::const_iterator vi;
1238  for (vi = vertices.begin(); vi != vertices.end(); ++vi) {
1239  EggVertex *vertex = (*vi);
1240  EggVertex *new_vertex = best_pool->create_unique_vertex(*vertex);
1241  new_vertex->copy_grefs_from(*vertex);
1242  new_vertices.push_back(new_vertex);
1243  }
1244  }
1245 
1246  Vertices::const_iterator vi;
1247  nassertv(new_vertices.size() == vertices.size());
1248  for (vi = new_vertices.begin(); vi != new_vertices.end(); ++vi) {
1249  EggVertex *new_vertex = (*vi);
1250  nassertv(new_vertex != nullptr);
1251  prim->add_vertex(new_vertex);
1252  }
1253 
1254  if (prim->is_of_type(EggCompositePrimitive::get_class_type())) {
1255  // Now restore the composite attributes.
1256  EggCompositePrimitive *cprim = DCAST(EggCompositePrimitive, prim);
1257  int i;
1258  int num_components = cprim->get_num_components();
1259  nassertv(num_components == (int)attributes.size());
1260  for (i = 0; i < num_components; i++) {
1261  cprim->set_component(i, &attributes[i]);
1262  }
1263  }
1264 
1265  } else if (child->is_of_type(EggGroupNode::get_class_type())) {
1266  if (recurse) {
1267  DCAST(EggGroupNode, child)->rebuild_vertex_pools(vertex_pools, max_vertices, recurse);
1268  }
1269  }
1270  }
1271 }
1272 
1273 /**
1274  * This function is called from within EggGroupNode whenever the parentage of
1275  * the node has changed. It should update the depth and under_instance flags
1276  * accordingly.
1277  *
1278  * Offset is the difference between the old depth value and the new value. It
1279  * should be consistent with the supplied depth value. If it is not, we have
1280  * some error.
1281  */
1282 void EggGroupNode::
1283 update_under(int depth_offset) {
1284  EggNode::update_under(depth_offset);
1285 
1286  Children::iterator ci;
1287  for (ci = _children.begin();
1288  ci != _children.end();
1289  ++ci) {
1290  nassertv((*ci)->get_parent() == this);
1291  (*ci)->update_under(depth_offset);
1292  }
1293 }
1294 
1295 /**
1296  * This is called from within the egg code by transform(). It applies a
1297  * transformation matrix to the current node in some sensible way, then
1298  * continues down the tree.
1299  *
1300  * The first matrix is the transformation to apply; the second is its inverse.
1301  * The third parameter is the coordinate system we are changing to, or
1302  * CS_default if we are not changing coordinate systems.
1303  */
1304 void EggGroupNode::
1305 r_transform(const LMatrix4d &mat, const LMatrix4d &inv,
1306  CoordinateSystem to_cs) {
1307  Children::iterator ci;
1308  for (ci = _children.begin();
1309  ci != _children.end();
1310  ++ci) {
1311  (*ci)->r_transform(mat, inv, to_cs);
1312  }
1313 }
1314 
1315 /**
1316  * This is called from within the egg code by transform_vertices_only()(). It
1317  * applies a transformation matrix to the current node in some sensible way
1318  * (if the current node is a vertex pool with vertices), then continues down
1319  * the tree.
1320  */
1321 void EggGroupNode::
1322 r_transform_vertices(const LMatrix4d &mat) {
1323  Children::iterator ci;
1324  for (ci = _children.begin();
1325  ci != _children.end();
1326  ++ci) {
1327  (*ci)->r_transform_vertices(mat);
1328  }
1329 }
1330 
1331 /**
1332  * This is only called immediately after loading an egg file from disk, to
1333  * propagate the value found in the CoordinateSystem entry (or the default
1334  * Y-up coordinate system) to all nodes that care about what the coordinate
1335  * system is.
1336  */
1337 void EggGroupNode::
1338 r_mark_coordsys(CoordinateSystem cs) {
1339  Children::iterator ci;
1340  for (ci = _children.begin();
1341  ci != _children.end();
1342  ++ci) {
1343  (*ci)->r_mark_coordsys(cs);
1344  }
1345 }
1346 
1347 /**
1348  * The recursive implementation of flatten_transforms().
1349  */
1350 void EggGroupNode::
1351 r_flatten_transforms() {
1352  Children::iterator ci;
1353  for (ci = _children.begin();
1354  ci != _children.end();
1355  ++ci) {
1356  (*ci)->r_flatten_transforms();
1357  }
1358 }
1359 
1360 /**
1361  * The recursive implementation of apply_texmats().
1362  */
1363 void EggGroupNode::
1364 r_apply_texmats(EggTextureCollection &textures) {
1365  Children::iterator ci;
1366  for (ci = _children.begin();
1367  ci != _children.end();
1368  ++ci) {
1369  (*ci)->r_apply_texmats(textures);
1370  }
1371 }
1372 
1373 /**
1374  * Walks the tree, looking for an EggCoordinateSystem entry. If one is found,
1375  * extracts it and returns its value. If multiple entries are found, extracts
1376  * all of them and returns CS_invalid if they disagree.
1377  */
1378 CoordinateSystem EggGroupNode::
1379 find_coordsys_entry() {
1380  CoordinateSystem coordsys = CS_default;
1381 
1382  // We can do this cicnext iteration through the list as we modify it, only
1383  // because we know this works with an STL list type container. If this were
1384  // a vector or a set, this wouldn't necessarily work.
1385 
1386  Children::iterator ci, cnext;
1387  ci = _children.begin();
1388  while (ci != _children.end()) {
1389  cnext = ci;
1390  ++cnext;
1391  EggNode *child = *ci;
1392 
1393  if (child->is_of_type(EggCoordinateSystem::get_class_type())) {
1394  CoordinateSystem new_cs =
1395  DCAST(EggCoordinateSystem, child)->get_value();
1396 
1397  // Now remove the CoordinateSystem entry from our child list.
1398  prepare_remove_child(child);
1399  _children.erase(ci);
1400 
1401  if (new_cs != CS_default) {
1402  if (coordsys != CS_default && coordsys != new_cs) {
1403  coordsys = CS_invalid;
1404  } else {
1405  coordsys = new_cs;
1406  }
1407  }
1408 
1409  } else if (child->is_of_type(EggGroupNode::get_class_type())) {
1410  CoordinateSystem new_cs =
1411  DCAST(EggGroupNode, child)->find_coordsys_entry();
1412  if (new_cs != CS_default) {
1413  if (coordsys != CS_default && coordsys != new_cs) {
1414  coordsys = CS_invalid;
1415  } else {
1416  coordsys = new_cs;
1417  }
1418  }
1419  }
1420 
1421  ci = cnext;
1422  }
1423 
1424  return coordsys;
1425 }
1426 
1427 /**
1428  * Walks the tree, looking for EggTextures. Each EggTexture that is found is
1429  * removed from the hierarchy and added to the EggTextureCollection. Returns
1430  * the number of EggTextures found.
1431  */
1432 int EggGroupNode::
1433 find_textures(EggTextureCollection *collection) {
1434  int num_found = 0;
1435 
1436  // We can do this cicnext iteration through the list as we modify it, only
1437  // because we know this works with an STL list type container. If this were
1438  // a vector or a set, this wouldn't necessarily work.
1439 
1440  Children::iterator ci, cnext;
1441  ci = _children.begin();
1442  while (ci != _children.end()) {
1443  cnext = ci;
1444  ++cnext;
1445  EggNode *child = *ci;
1446 
1447  if (child->is_of_type(EggTexture::get_class_type())) {
1448  PT_EggTexture tex = DCAST(EggTexture, child);
1449 
1450  // Now remove the EggTexture entry from our child list.
1451  prepare_remove_child(tex);
1452  _children.erase(ci);
1453 
1454  // And add it to the collection.
1455  collection->add_texture(tex);
1456  num_found++;
1457 
1458  } else if (child->is_of_type(EggGroupNode::get_class_type())) {
1459  num_found +=
1460  DCAST(EggGroupNode, child)->find_textures(collection);
1461  }
1462 
1463  ci = cnext;
1464  }
1465 
1466  return num_found;
1467 }
1468 
1469 /**
1470  * Walks the tree, looking for EggMaterials. Each EggMaterial that is found
1471  * is removed from the hierarchy and added to the EggMaterialCollection.
1472  * Returns the number of EggMaterials found.
1473  */
1474 int EggGroupNode::
1475 find_materials(EggMaterialCollection *collection) {
1476  int num_found = 0;
1477 
1478  // We can do this cicnext iteration through the list as we modify it, only
1479  // because we know this works with an STL list type container. If this were
1480  // a vector or a set, this wouldn't necessarily work.
1481 
1482  Children::iterator ci, cnext;
1483  ci = _children.begin();
1484  while (ci != _children.end()) {
1485  cnext = ci;
1486  ++cnext;
1487  EggNode *child = *ci;
1488 
1489  if (child->is_of_type(EggMaterial::get_class_type())) {
1490  PT_EggMaterial tex = DCAST(EggMaterial, child);
1491 
1492  // Now remove the EggMaterial entry from our child list.
1493  prepare_remove_child(tex);
1494  _children.erase(ci);
1495 
1496  // And add it to the collection.
1497  collection->add_material(tex);
1498  num_found++;
1499 
1500  } else if (child->is_of_type(EggGroupNode::get_class_type())) {
1501  num_found +=
1502  DCAST(EggGroupNode, child)->find_materials(collection);
1503  }
1504 
1505  ci = cnext;
1506  }
1507 
1508  return num_found;
1509 }
1510 
1511 /**
1512  * Walks the tree and locates unloaded external reference nodes, which it
1513  * attempts to locate and load in. The reference node is replaced with the
1514  * entire subtree loaded. This is intended to be called from
1515  * EggData::load_externals().
1516  */
1517 bool EggGroupNode::
1518 r_load_externals(const DSearchPath &searchpath, CoordinateSystem coordsys,
1519  BamCacheRecord *record) {
1520  bool success = true;
1521 
1522  Children::iterator ci;
1523  for (ci = _children.begin();
1524  ci != _children.end();
1525  ++ci) {
1526  EggNode *child = *ci;
1527  if (child->is_of_type(EggExternalReference::get_class_type())) {
1528  PT(EggExternalReference) ref = DCAST(EggExternalReference, child);
1529 
1530  // Replace the reference with an empty group node. When we load the
1531  // external file successfully, we'll put its contents here.
1532  Filename filename = ref->get_filename();
1533  EggGroupNode *new_node =
1534  new EggGroupNode(filename.get_basename_wo_extension());
1535  replace(ci, new_node);
1536 
1537  if (!EggData::resolve_egg_filename(filename, searchpath)) {
1538  egg_cat.error()
1539  << "Could not locate " << filename << " in "
1540  << searchpath << "\n";
1541  } else {
1542  // Now define a new EggData structure to hold the external reference,
1543  // and load it.
1544  EggData ext_data;
1545  ext_data.set_coordinate_system(coordsys);
1546  ext_data.set_auto_resolve_externals(true);
1547  if (ext_data.read(filename)) {
1548  // The external file was read correctly. Add its contents into the
1549  // tree at this point.
1550  if (record != nullptr) {
1551  record->add_dependent_file(filename);
1552  }
1553 
1554  success =
1555  ext_data.load_externals(searchpath, record)
1556  && success;
1557  new_node->steal_children(ext_data);
1558  }
1559  }
1560 
1561  } else if (child->is_of_type(EggGroupNode::get_class_type())) {
1562  EggGroupNode *group_child = DCAST(EggGroupNode, child);
1563  success =
1564  group_child->r_load_externals(searchpath, coordsys, record)
1565  && success;
1566  }
1567  }
1568  return success;
1569 }
1570 
1571 
1572 /**
1573  * Marks the node as a child of the group. This is an internal function
1574  * called by the STL-like functions push_back() and insert(), in preparation
1575  * for actually adding the child.
1576  *
1577  * It is an error to add a node that is already a child of this group or some
1578  * other group.
1579  */
1580 void EggGroupNode::
1581 prepare_add_child(EggNode *node) {
1582  nassertv(node != nullptr);
1584  node->test_ref_count_integrity();
1585  // Make sure the node is not already a child of some other group.
1586  nassertv(node->get_parent() == nullptr);
1587  nassertv(node->get_depth() == 0);
1588  node->_parent = this;
1589 
1590  node->update_under(get_depth() + 1);
1591 }
1592 
1593 
1594 /**
1595  * Marks the node as removed from the group. This is an internal function
1596  * called by the STL-like functions pop_back() and erase(), in preparation for
1597  * actually doing the removal.
1598  *
1599  * It is an error to attempt to remove a node that is not already a child of
1600  * this group.
1601  */
1602 void EggGroupNode::
1603 prepare_remove_child(EggNode *node) {
1604  nassertv(node != nullptr);
1605  // Make sure the node is in fact a child of this group.
1606  nassertv(node->get_parent() == this);
1607  nassertv(node->get_depth() == get_depth() + 1);
1608  node->_parent = nullptr;
1609 
1610  node->update_under(-(get_depth() + 1));
1611 }
1612 
1613 
1614 
1615 /**
1616  * This is part of the implementation of recompute_vertex_normals(). It walks
1617  * the scene graph at this group node and below, identifying all the polygons
1618  * and the vertices they have in common.
1619  */
1620 void EggGroupNode::
1621 r_collect_vertex_normals(EggGroupNode::NVertexCollection &collection,
1622  double threshold, CoordinateSystem cs) {
1623  // We can do this cicnext iteration through the list as we modify it, only
1624  // because we know this works with an STL list type container. If this were
1625  // a vector or a set, this wouldn't necessarily work.
1626 
1627  Children::iterator ci, cnext;
1628  ci = _children.begin();
1629  while (ci != _children.end()) {
1630  cnext = ci;
1631  ++cnext;
1632  EggNode *child = *ci;
1633 
1634  if (child->is_of_type(EggPolygon::get_class_type())) {
1635  EggPolygon *polygon = DCAST(EggPolygon, child);
1636  polygon->clear_normal();
1637 
1638  NVertexReference ref;
1639  ref._polygon = polygon;
1640  if (!polygon->calculate_normal(ref._normal, cs)) {
1641  // The polygon is degenerate. Remove it.
1642 
1643  prepare_remove_child(child);
1644  _children.erase(ci);
1645 
1646  } else {
1647  // Now add each vertex from the polygon separately to our collection.
1648  size_t num_vertices = polygon->size();
1649  for (size_t i = 0; i < num_vertices; i++) {
1650  EggVertex *vertex = polygon->get_vertex(i);
1651  ref._vertex = i;
1652  collection[vertex->get_pos3()].push_back(ref);
1653  }
1654  }
1655 
1656  } else if (child->is_of_type(EggGroupNode::get_class_type())) {
1657  EggGroupNode *group = DCAST(EggGroupNode, child);
1658 
1659  // We can't share vertices across an Instance node. Don't even bother
1660  // trying. Instead, just restart.
1661  if (group->is_under_instance()) {
1662  group->recompute_vertex_normals(threshold, cs);
1663  } else {
1664  group->r_collect_vertex_normals(collection, threshold, cs);
1665  }
1666  }
1667 
1668  ci = cnext;
1669  }
1670 }
1671 
1672 /**
1673  * This is part of the implementation of recompute_vertex_normals(). It
1674  * accepts a group of polygons and their common normals, and computes the same
1675  * normal for all their shared vertices.
1676  */
1677 void EggGroupNode::
1678 do_compute_vertex_normals(const NVertexGroup &group) {
1679  nassertv(!group.empty());
1680 
1681  // Determine the common normal. This is simply the average of all the
1682  // polygon normals that share this vertex.
1683  LNormald normal(0.0, 0.0, 0.0);
1684  NVertexGroup::const_iterator gi;
1685  for (gi = group.begin(); gi != group.end(); ++gi) {
1686  const NVertexReference &ref = (*gi);
1687  normal += ref._normal;
1688  }
1689 
1690  normal /= (double)group.size();
1691  normal.normalize();
1692 
1693  // Now we have the common normal; apply it to all the vertices.
1694 
1695  for (gi = group.begin(); gi != group.end(); ++gi) {
1696  const NVertexReference &ref = (*gi);
1697  EggVertex *vertex = ref._polygon->get_vertex(ref._vertex);
1698  EggVertexPool *pool = vertex->get_pool();
1699 
1700  EggVertex new_vertex(*vertex);
1701  new_vertex.set_normal(normal);
1702  EggVertex *unique = pool->create_unique_vertex(new_vertex);
1703  unique->copy_grefs_from(*vertex);
1704 
1705  ref._polygon->set_vertex(ref._vertex, unique);
1706  }
1707 }
1708 
1709 /**
1710  * This is part of the implementation of recompute_tangent_binormal(). It
1711  * walks the scene graph at this group node and below, identifying all the
1712  * polygons and the vertices they have in common.
1713  */
1714 void EggGroupNode::
1715 r_collect_tangent_binormal(const GlobPattern &uv_name,
1716  EggGroupNode::TBNVertexCollection &collection) {
1717  Children::iterator ci;
1718  for (ci = _children.begin(); ci != _children.end(); ++ci) {
1719  EggNode *child = *ci;
1720 
1721  if (child->is_of_type(EggPolygon::get_class_type())) {
1722  EggPolygon *polygon = DCAST(EggPolygon, child);
1723 
1724  TBNVertexReference ref;
1725  ref._polygon = polygon;
1726 
1727  // Now add each vertex from the polygon separately to our collection.
1728  size_t num_vertices = polygon->size();
1729  for (size_t i = 0; i < num_vertices; i++) {
1730  // We look at the triangle formed by each three consecutive vertices
1731  // to determine the s direction and t direction at each vertex. v1 is
1732  // the key vertex, the one at position i; v2 is vertex i + 1, and v3
1733  // is vertex i - 1.
1734  EggVertex *v1 = polygon->get_vertex(i);
1735  EggVertex *v2 = polygon->get_vertex((i + 1) % num_vertices);
1736  EggVertex *v3 = polygon->get_vertex((i + num_vertices - 1) % num_vertices);
1737  if (v1->has_normal() || polygon->has_normal()) {
1738  // Go through all of the UV names on the vertex, looking for one
1739  // that matches the glob pattern.
1741  for (uvi = v1->uv_begin(); uvi != v1->uv_end(); ++uvi) {
1742  EggVertexUV *uv_obj = (*uvi);
1743  string name = uv_obj->get_name();
1744  if (uv_name.matches(name) &&
1745  v2->has_uv(name) && v3->has_uv(name)) {
1746  TBNVertexValue value;
1747  value._uv_name = name;
1748  value._pos = v1->get_pos3();
1749  if (v1->has_normal()) {
1750  value._normal = v1->get_normal();
1751  } else {
1752  value._normal = polygon->get_normal();
1753  }
1754  value._uv = v1->get_uv(name);
1755 
1756  // Compute the s direction and t direction for this vertex.
1757  LPoint3d p1 = v1->get_pos3();
1758  LPoint3d p2 = v2->get_pos3();
1759  LPoint3d p3 = v3->get_pos3();
1760 
1761  LTexCoordd w1 = v1->get_uv(name);
1762  LTexCoordd w2 = v2->get_uv(name);
1763  LTexCoordd w3 = v3->get_uv(name);
1764 
1765  // Check the facing of the texture; we will have to split
1766  // vertices whose UV's are mirrored along a seam. The facing is
1767  // determined by the winding order of the texcoords on the
1768  // polygon. A front-facing polygon should not contribute to the
1769  // tangent and binormal of a back-facing polygon, and vice-
1770  // versa.
1771  value._facing = is_right(w1 - w2, w3 - w1);
1772 
1773  double x1 = p2[0] - p1[0];
1774  double x2 = p3[0] - p1[0];
1775  double y1 = p2[1] - p1[1];
1776  double y2 = p3[1] - p1[1];
1777  double z1 = p2[2] - p1[2];
1778  double z2 = p3[2] - p1[2];
1779 
1780  double s1 = w2[0] - w1[0];
1781  double s2 = w3[0] - w1[0];
1782  double t1 = w2[1] - w1[1];
1783  double t2 = w3[1] - w1[1];
1784 
1785  double denom = (s1 * t2 - s2 * t1);
1786  if (denom == 0.0) {
1787  ref._sdir.set(0.0, 0.0, 0.0);
1788  ref._tdir.set(0.0, 0.0, 0.0);
1789  } else {
1790  double r = 1.0 / denom;
1791  ref._sdir.set((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r,
1792  (t2 * z1 - t1 * z2) * r);
1793  ref._tdir.set((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r,
1794  (s1 * z2 - s2 * z1) * r);
1795  }
1796 
1797  // Store the vertex referenced to the polygon.
1798  ref._vertex = i;
1799  collection[value].push_back(ref);
1800  }
1801  }
1802  }
1803  }
1804 
1805  } else if (child->is_of_type(EggGroupNode::get_class_type())) {
1806  EggGroupNode *group = DCAST(EggGroupNode, child);
1807 
1808  // We can't share vertices across an Instance node. Don't even bother
1809  // trying. Instead, just restart.
1810  if (group->is_under_instance()) {
1811  group->recompute_tangent_binormal(uv_name);
1812  } else {
1813  group->r_collect_tangent_binormal(uv_name, collection);
1814  }
1815  }
1816  }
1817 }
1818 
1819 /**
1820  * This is part of the implementation of recompute_tangent_binormal(). It
1821  * accepts a group of polygons and their common normals and UV's, and computes
1822  * the tangent and binormal for all their shared vertices.
1823  */
1824 void EggGroupNode::
1825 do_compute_tangent_binormal(const TBNVertexValue &value,
1826  const TBNVertexGroup &group) {
1827  nassertv(!group.empty());
1828 
1829  // Accumulate together all of the s vectors and t vectors computed for the
1830  // different vertices that are together here.
1831  LNormald sdir(0.0, 0.0, 0.0);
1832  LNormald tdir(0.0, 0.0, 0.0);
1833 
1834  TBNVertexGroup::const_iterator gi;
1835  for (gi = group.begin(); gi != group.end(); ++gi) {
1836  const TBNVertexReference &ref = (*gi);
1837  sdir += ref._sdir;
1838  tdir += ref._tdir;
1839  }
1840 
1841  // If sdir andor tdir are zero, choose an arbitrary vector instead. (This
1842  // is really the only reason we normalize sdir and tdir, though it also
1843  // helps stabilize the math below in case the vectors are very small but not
1844  // quite zero.)
1845  if (!sdir.normalize()) {
1846  sdir.set(1.0, 0.0, 0.0);
1847  }
1848  if (!tdir.normalize()) {
1849  tdir = sdir.cross(LNormald(0.0, 0.0, -1.0));
1850  }
1851 
1852  LNormald tangent = (sdir - value._normal * value._normal.dot(sdir));
1853  tangent.normalize();
1854 
1855  LNormald binormal = cross(value._normal, tangent);
1856  if (dot(binormal, tdir) < 0.0f) {
1857  binormal = -binormal;
1858  }
1859  // Shouldn't need to normalize this, but we do just for good measure.
1860  binormal.normalize();
1861 
1862  // Now we have the common tangent and binormal; apply them to all the
1863  // vertices.
1864 
1865  for (gi = group.begin(); gi != group.end(); ++gi) {
1866  const TBNVertexReference &ref = (*gi);
1867  EggVertex *vertex = ref._polygon->get_vertex(ref._vertex);
1868  EggVertexPool *pool = vertex->get_pool();
1869 
1870  EggVertex new_vertex(*vertex);
1871  EggVertexUV *uv_obj = new_vertex.modify_uv_obj(value._uv_name);
1872  nassertv(uv_obj != nullptr);
1873  uv_obj->set_tangent(tangent);
1874  uv_obj->set_binormal(binormal);
1875 
1876  EggVertex *unique = pool->create_unique_vertex(new_vertex);
1877  unique->copy_grefs_from(*vertex);
1878 
1879  ref._polygon->set_vertex(ref._vertex, unique);
1880  }
1881 }
bool empty() const
Returns true if the pool is empty.
A base class for any of a number of kinds of geometry primitives: polygons, point lights,...
Definition: eggPrimitive.h:47
The set of UV's that may or may not be assigned to a vertex.
Definition: eggVertexUV.h:29
void strip_normals()
Removes all normals from primitives, and the vertices they reference, at this node and below.
const Filename & get_filename() const
Returns a nonmodifiable reference to the filename.
void make_point_primitives()
Creates PointLight primitives to reference any otherwise unreferences vertices discovered in this gro...
virtual void unify_attributes(Shading shading)
If the shading property is S_per_vertex, ensures that all vertices have a normal and a color,...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
static bool resolve_egg_filename(Filename &egg_filename, const DSearchPath &searchpath=DSearchPath())
Looks for the indicated filename, first along the indicated searchpath, and then along the model_path...
Definition: eggData.cxx:44
This is an iterator adaptor that converts any iterator that returns a pair (e.g.
PT(EggNode) EggGroupNode
Removes the indicated child node from the group and returns it.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is our own Panda specialization on the default STL map.
Definition: pmap.h:49
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
The base class for primitives such as triangle strips and triangle fans, which include several compon...
get_depth
Returns the number of nodes above this node in the egg hierarchy.
Definition: eggNode.h:48
get_uv_name
Returns the texcoord name that has been specified for this texture, or the empty string if no texcoor...
Definition: eggTexture.h:337
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual bool joint_has_primitives() const
Returns true if there are any primitives (e.g.
virtual void apply_first_attribute()
Sets the first vertex of the triangle (or each component) to the primitive normal and/or color,...
The <CoordinateSystem> entry at the top of an egg file.
This is an egg node that contains a filename.
EggVertexPool * get_pool() const
Returns the vertex pool this vertex belongs in.
Definition: eggVertex.I:19
virtual void apply_last_attribute()
Sets the last vertex of the triangle (or each component) to the primitive normal and/or color,...
virtual bool cleanup()
Cleans up modeling errors in whatever context this makes sense.
void unify_attributes(bool use_connected_shading, bool allow_per_primitive, bool recurse)
Applies per-vertex normal and color to all vertices, if they are in fact per-vertex (and different fo...
A base class for nodes in the hierarchy that are not leaf nodes.
Definition: eggGroupNode.h:46
This is a collection of materials by MRef name.
A hierarchy of directories and files that appears to be one continuous file system,...
int triangulate_polygons(int flags)
Replace all higher-order polygons at this point in the scene graph and below with triangles.
void get_connected_shading()
Queries the connected_shading information on all primitives at this node and below,...
void clear()
Removes all of the vertices from the primitive.
Definition: eggPrimitive.I:352
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_component
Returns the attributes for the nth component triangle.
has_alpha_filename
Returns true if a separate file for the alpha component has been applied, false otherwise.
Definition: eggTexture.h:343
LTexCoordd get_uv() const
Returns the unnamed UV coordinate pair on the vertex.
Definition: eggVertex.I:179
Defines a texture map that may be applied to geometry.
Definition: eggTexture.h:30
void clear_connected_shading()
Resets the connected_shading information on all primitives at this node and below,...
std::string get_basename_wo_extension() const
Returns the basename part of the filename, without the file extension.
Definition: filename.I:386
void recompute_polygon_normals(CoordinateSystem cs=CS_default)
Recomputes all the polygon normals for polygon geometry at this group node and below so that they acc...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool recompute_tangent_binormal_auto()
This function recomputes the tangent and binormal for any texture coordinate set that affects a norma...
set_auto_resolve_externals
Indicates whether the EggData object will automatically resolve any external references when read() i...
Definition: eggData.h:72
bool add_material(EggMaterial *material)
Explicitly adds a new material to the collection.
get_shading
Returns the shading properties apparent on this particular primitive.
Definition: eggPrimitive.h:111
bool test_ref_count_integrity() const
Does some easy checks to make sure that the reference count isn't completely bogus.
This is a collection of textures by TRef name.
virtual std::string get_default_extension() const
Returns the default extension for this filename type.
void apply_first_attribute(bool recurse)
Sets the first vertex of the triangle (or each component) to the primitive normal and/or color,...
bool resolve_filename(Filename &filename, const DSearchPath &searchpath, const std::string &default_extension=std::string()) const
Searches the given search path for the filename.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
LVertexd get_pos3() const
Valid if get_num_dimensions() returns 3 or 4.
Definition: eggVertex.I:131
bool add_texture(EggTexture *texture)
Explicitly adds a new texture to the collection.
This is the primary interface into all the egg data, and the root of the egg file structure.
Definition: eggData.h:37
size_type size() const
Returns the number of vertices in the pool.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_vertex
Returns a particular index based on its index number.
Definition: eggPrimitive.h:187
A single point, or a collection of points as defined by a single <PointLight> entry.
Definition: eggPoint.h:25
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool matches(const std::string &candidate) const
Returns true if the candidate string matches the pattern, false otherwise.
Definition: globPattern.I:122
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool read(Filename filename, std::string display_name=std::string())
Opens the indicated filename and reads the egg data contents from it.
Definition: eggData.cxx:65
get_connected_shading
Determines what sort of shading properties this primitive's connected neighbors have.
Definition: eggPrimitive.h:112
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:42
static bool is_right(const LVector2d &v1, const LVector2d &v2)
Returns true if the 2-d v1 is to the right of v2.
Definition: eggGroupNode.I:18
void mesh(EggGroupNode *group, bool flat_shaded)
Accepts an EggGroupNode, which contains a set of EggPrimitives–typically, triangles and quads–as chil...
Definition: eggMesher.cxx:49
set_vertex
Replaces a particular vertex based on its index number in the list of vertices.
Definition: eggPrimitive.h:191
The main glue of the egg hierarchy, this corresponds to the <Group>, <Instance>, and <Joint> type nod...
Definition: eggGroup.h:34
virtual void write(std::ostream &out, int indent_level) const
Writes the group and all of its children to the indicated output stream in Egg format.
virtual void reverse_vertex_ordering()
Reverses the ordering of the vertices in this primitive, if appropriate, in order to change the direc...
virtual void post_apply_flat_attribute()
Intended as a followup to apply_last_attribute(), this also sets an attribute on the first vertices o...
Collects together unrelated EggPrimitives, determines their edge connectivity, and generates a set of...
Definition: eggMesher.h:33
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:39
An instance of this class is written to the front of a Bam or Txo file to make the file a cached inst...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Any one-, two-, three-, or four-component vertex, possibly with attributes such as a normal.
Definition: eggVertex.h:39
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual bool has_primitives() const
Returns true if there are any primitives (e.g.
int rename_nodes(vector_string strip_prefix, bool recurse)
Rename by stripping out the prefix.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
int remove_invalid_primitives(bool recurse)
Removes primitives at this level and below which appear to be degenerate; e.g.
bool load_externals(const DSearchPath &searchpath=DSearchPath())
Loads up all the egg files referenced by <File> entries within the egg structure, and inserts their c...
Definition: eggData.cxx:162
int remove_unused_vertices()
Removes all vertices from the pool that are not referenced by at least one primitive.
void steal_children(EggGroupNode &other)
Moves all the children from the other node to this one.
static VirtualFileSystem * get_global_ptr()
Returns the default global VirtualFileSystem.
void mesh_triangles(int flags)
Combine triangles together into triangle strips, at this group and below.
int remove_unused_vertices(bool recurse)
Removes all vertices from VertexPools within this group or below that are not referenced by at least ...
void add_unused_vertices_to_prim(EggPrimitive *prim)
Adds all of the unused vertices in this vertex pool to the indicated primitive, in ascending order.
bool has_uv() const
Returns true if the vertex has an unnamed UV coordinate pair, false otherwise.
Definition: eggVertex.I:158
void apply_last_attribute(bool recurse)
Sets the last vertex of the triangle (or each component) to the primitive normal and/or color,...
EggNode * get_next_child()
Returns the next child in the group's list of children since the last call to get_first_child() or ge...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual bool is_joint() const
Returns true if this particular node represents a <Joint> entry or not.
Definition: eggNode.cxx:65
int find_used_textures(EggNode *node)
Walks the egg hierarchy beginning at the indicated node, looking for textures that are referenced by ...
virtual bool has_normals() const
Returns true if any of the primitives (e.g.
bool is_local() const
Returns true if the filename is local, e.g.
Definition: filename.I:549
A single polygon.
Definition: eggPolygon.h:24
void ref() const
Explicitly increments the reference count.
void rebuild_vertex_pools(EggVertexPools &vertex_pools, unsigned int max_vertices, bool recurse)
Copies vertices used by the primitives at this group node (and below, if recurse is true) into one or...
bool recompute_polygon_normal(CoordinateSystem cs=CS_default)
Recalculates the normal according to the order of the vertices, and sets it.
Definition: eggPolygon.I:43
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_alpha_filename
Returns the separate file assigned for the alpha channel.
Definition: eggTexture.h:343
EggVertex * find_matching_vertex(const EggVertex &copy)
If the EggVertexPool already has a vertex matching the indicated vertex, returns it; otherwise,...
bool is_under_instance() const
Returns true if there is an <Instance> node somewhere in the egg tree at or above this node,...
Definition: eggNode.I:68
void replace(iterator position, PT(EggNode) x)
Replaces the node at the indicated position with the indicated node.
EggNode * add_child(EggNode *node)
Adds the indicated child to the group and returns it.
int rename_node(vector_string strip_prefix)
Rename by stripping out the prefix.
Definition: eggNode.cxx:34
set_coordinate_system
Changes the coordinate system of the EggData.
Definition: eggData.h:73
void force_filenames(const Filename &directory)
Similar to resolve_filenames, but each non-absolute filename encountered is arbitrarily taken to be i...
const_uv_iterator uv_begin() const
Returns an iterator that allows walking through the complete set of named UV's on the vertex.
Definition: eggVertex.I:220
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A base class for things that may be directly added into the egg hierarchy.
Definition: eggNode.h:35
set_alpha_filename
Specifies a separate file that will be loaded in with the 1- or 3-component texture and applied as th...
Definition: eggTexture.h:343
bool calculate_normal(LNormald &result, CoordinateSystem cs=CS_default) const
Calculates the true polygon normal–the vector pointing out of the front of the polygon–based on the v...
Definition: eggPolygon.cxx:57
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
EggNode * get_first_child()
Returns the first child in the group's list of children, or NULL if the list of children is empty.
Defines a reference to another egg file which should be inserted at this point.
This class stores a list of directories that can be searched, in order, to locate a particular file.
Definition: dSearchPath.h:28
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition: typedObject.I:28
void add_dependent_file(const Filename &pathname)
Adds the indicated file to the list of files that will be loaded to generate the data in this record.
void copy_grefs_from(const EggVertex &other)
Copies all the group references from the other vertex onto this one.
Definition: eggVertex.cxx:747
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
bool has_absolute_pathnames() const
Returns true if any nodes at this level and below include a reference to a file via an absolute pathn...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void post_apply_flat_attribute(bool recurse)
Intended as a followup to apply_last_attribute(), this also sets an attribute on the first vertices o...
set_component
Changes the attributes for the nth component triangle.
void resolve_filenames(const DSearchPath &searchpath)
Walks the tree and attempts to resolve any filenames encountered.
EggVertex * create_unique_vertex(const EggVertex &copy)
Creates a new vertex in the pool that is a copy of the indicated one and returns it.
A collection of vertices.
Definition: eggVertexPool.h:41
EggVertex * add_vertex(EggVertex *vertex)
Adds the indicated vertex to the end of the primitive's list of vertices, and returns it.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
EggNode * find_child(const std::string &name) const
Returns the child of this node whose name is the indicated string, or NULL if there is no child of th...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void recompute_vertex_normals(double threshold, CoordinateSystem cs=CS_default)
Recomputes all the vertex normals for polygon geometry at this group node and below so that they accu...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void reverse_vertex_ordering()
Reverses the vertex ordering of all polygons defined at this node and below.
void clear_connected_shading()
Resets the connected_shading member in this primitive, so that get_connected_shading() will recompute...
Definition: eggPrimitive.I:84
const_uv_iterator uv_end() const
Returns an iterator that allows walking through the complete set of named UV's on the vertex.
Definition: eggVertex.I:242
This class can be used to test for string matches against standard Unix- shell filename globbing conv...
Definition: globPattern.h:32
get_num_components
Returns the number of individual component triangles within the composite.
bool recompute_tangent_binormal(const GlobPattern &uv_name)
This function recomputes the tangent and binormal for the named texture coordinate set for all vertic...