Panda3D
eggGroup.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 eggGroup.cxx
10  * @author drose
11  * @date 1999-01-16
12  */
13 
14 #include "eggGroup.h"
15 #include "eggMiscFuncs.h"
16 #include "eggVertexPool.h"
17 #include "eggBin.h"
18 #include "lexerDefs.h"
19 
20 #include "indent.h"
21 #include "string_utils.h"
22 #include "lmatrix.h"
23 #include "dcast.h"
24 
25 using std::ostream;
26 using std::string;
27 
28 
29 TypeHandle EggGroup::_type_handle;
30 
31 /**
32  *
33  */
34 EggGroup::
35 EggGroup(const string &name) : EggGroupNode(name) {
36  _flags = 0;
37  _flags2 = 0;
38  _fps = 0.0;
39  _blend_mode = BM_unspecified;
40  _blend_operand_a = BO_unspecified;
41  _blend_operand_b = BO_unspecified;
42  _blend_color = LColor::zero();
43  _u_speed = 0;
44  _v_speed = 0;
45  _w_speed = 0;
46  _r_speed = 0;
47 }
48 
49 /**
50  *
51  */
52 EggGroup::
53 EggGroup(const EggGroup &copy) {
54  (*this) = copy;
55 }
56 
57 /**
58  *
59  */
60 EggGroup &EggGroup::
61 operator = (const EggGroup &copy) {
62  EggTransform::operator = (copy);
63  _flags = copy._flags;
64  _flags2 = copy._flags2;
65  _collide_mask = copy._collide_mask;
66  _from_collide_mask = copy._from_collide_mask;
67  _into_collide_mask = copy._into_collide_mask;
68  _billboard_center = copy._billboard_center;
69  _object_types = copy._object_types;
70  _collision_name = copy._collision_name;
71  _fps = copy._fps;
72  _lod = copy._lod;
73  _blend_mode = copy._blend_mode;
74  _blend_operand_a = copy._blend_operand_a;
75  _blend_operand_b = copy._blend_operand_b;
76  _blend_color = copy._blend_color;
77  _tag_data = copy._tag_data;
78  _u_speed = copy._u_speed;
79  _v_speed = copy._v_speed;
80  _w_speed = copy._w_speed;
81  _r_speed = copy._r_speed;
82  _default_pose = copy._default_pose;
83 
85  _vref = copy._vref;
86 
87  // We must walk through the vertex ref list, and flag each vertex as now
88  // reffed by this group.
89  VertexRef::iterator vri;
90  for (vri = _vref.begin(); vri != _vref.end(); ++vri) {
91  EggVertex *vert = (*vri).first;
92 
93  bool inserted = vert->_gref.insert(this).second;
94  // Did the group not exist previously in the vertex's gref list? If it
95  // was there already, we must be out of sync between vertices and groups.
96  nassertr(inserted, *this);
97  }
98 
99  // These must be down here, because the EggNode assignment operator will
100  // force an update_under(). Therefore, we can't call it until all the
101  // attributes that affect adjust_under() are in place.
102  EggGroupNode::operator = (copy);
103  EggRenderMode::operator = (copy);
104 
105  return *this;
106 }
107 
108 
109 /**
110  *
111  */
112 EggGroup::
113 ~EggGroup() {
115 }
116 
117 /**
118  *
119  */
120 void EggGroup::
121 set_group_type(GroupType type) {
122  if (type != get_group_type()) {
123 #ifndef NDEBUG
124  if (type != GT_instance) {
125  // Only valid to change to a non-instance type if we have no group refs.
126  nassertv(_group_refs.empty());
127  }
128 #endif
129 
130  // Make sure the user didn't give us any stray bits.
131  nassertv((type & ~F_group_type)==0);
132  _flags = (_flags & ~F_group_type) | type;
133 
134  // Now we might have changed the type to or from an instance node, so we
135  // have to recompute the under_flags.
136  update_under(0);
137  }
138 }
139 
140 /**
141  * Returns true if the indicated object type has been added to the group, or
142  * false otherwise.
143  */
144 bool EggGroup::
145 has_object_type(const string &object_type) const {
146  vector_string::const_iterator oi;
147  for (oi = _object_types.begin(); oi != _object_types.end(); ++oi) {
148  if (cmp_nocase_uh((*oi), object_type) == 0) {
149  return true;
150  }
151  }
152  return false;
153 }
154 
155 /**
156  * Removes the first instance of the indicated object type from the group if
157  * it is present. Returns true if the object type was found and removed,
158  * false otherwise.
159  */
160 bool EggGroup::
161 remove_object_type(const string &object_type) {
162  vector_string::iterator oi;
163  for (oi = _object_types.begin(); oi != _object_types.end(); ++oi) {
164  if (cmp_nocase_uh((*oi), object_type) == 0) {
165  _object_types.erase(oi);
166  return true;
167  }
168  }
169  return false;
170 }
171 
172 /**
173  * Writes the group and all of its children to the indicated output stream in
174  * Egg format.
175  */
176 void EggGroup::
177 write(ostream &out, int indent_level) const {
178  test_under_integrity();
179 
180  switch (get_group_type()) {
181  case GT_group:
182  write_header(out, indent_level, "<Group>");
183  break;
184 
185  case GT_instance:
186  write_header(out, indent_level, "<Instance>");
187  break;
188 
189  case GT_joint:
190  write_header(out, indent_level, "<Joint>");
191  break;
192 
193  default:
194  // invalid group type
195  nassert_raise("invalid EggGroup type");
196  return;
197  }
198 
199  if (is_of_type(EggBin::get_class_type())) {
200  indent(out, indent_level + 2)
201  << "// Bin " << DCAST(EggBin, this)->get_bin_number() << "\n";
202  }
203 
204  if (has_lod()) {
205  get_lod().write(out, indent_level + 2);
206  }
207 
208  write_billboard_flags(out, indent_level + 2);
209  write_collide_flags(out, indent_level + 2);
210  write_model_flags(out, indent_level + 2);
211  write_switch_flags(out, indent_level + 2);
212 
213  if (has_transform()) {
214  EggTransform::write(out, indent_level + 2, "<Transform>");
215  }
216 
217  if (get_group_type() == GT_joint && _default_pose.has_transform()) {
218  _default_pose.write(out, indent_level + 2, "<DefaultPose>");
219  }
220 
221  if (get_scroll_u() != 0) {
222  indent(out, indent_level + 2)
223  << "<Scalar> scroll_u { " << get_scroll_u() << " }\n";
224 
225  }
226 
227  if (get_scroll_v() != 0) {
228  indent(out, indent_level + 2)
229  << "<Scalar> scroll_v { " << get_scroll_v() << " }\n";
230 
231  }
232 
233  if (get_scroll_w() != 0) {
234  indent(out, indent_level + 2)
235  << "<Scalar> scroll_w { " << get_scroll_w() << " }\n";
236 
237  }
238 
239  if (get_scroll_r() != 0) {
240  indent(out, indent_level + 2)
241  << "<Scalar> scroll_r { " << get_scroll_r() << " }\n";
242 
243  }
244 
245  write_object_types(out, indent_level + 2);
246  write_decal_flags(out, indent_level + 2);
247  write_tags(out, indent_level + 2);
248  write_render_mode(out, indent_level + 2);
249 
250  if (get_portal_flag()) {
251  indent(out, indent_level + 2) << "<Scalar> portal { 1 }\n";
252  }
253 
254  if (get_occluder_flag()) {
255  indent(out, indent_level + 2) << "<Scalar> occluder { 1 }\n";
256  }
257 
258  if (get_polylight_flag()) {
259  indent(out, indent_level + 2) << "<Scalar> polylight { 1 }\n";
260  }
261 
262  if (has_indexed_flag()) {
263  indent(out, indent_level + 2)
264  << "<Scalar> indexed { " << get_indexed_flag() << " }\n";
265  }
266 
267  if (get_blend_mode() != BM_unspecified) {
268  indent(out, indent_level + 2)
269  << "<Scalar> blend { " << get_blend_mode() << " }\n";
270  }
271 
272  if (get_blend_operand_a() != BO_unspecified) {
273  indent(out, indent_level + 2)
274  << "<Scalar> blendop-a { " << get_blend_operand_a() << " }\n";
275  }
276 
277  if (get_blend_operand_b() != BO_unspecified) {
278  indent(out, indent_level + 2)
279  << "<Scalar> blendop-b { " << get_blend_operand_b() << " }\n";
280  }
281 
282  if (has_blend_color()) {
283  const LColor &c = get_blend_color();
284  indent(out, indent_level + 2)
285  << "<Scalar> blendr { " << c[0] << " }\n";
286  indent(out, indent_level + 2)
287  << "<Scalar> blendg { " << c[1] << " }\n";
288  indent(out, indent_level + 2)
289  << "<Scalar> blendb { " << c[2] << " }\n";
290  indent(out, indent_level + 2)
291  << "<Scalar> blenda { " << c[3] << " }\n";
292  }
293 
294  GroupRefs::const_iterator gri;
295  for (gri = _group_refs.begin(); gri != _group_refs.end(); ++gri) {
296  EggGroup *group_ref = (*gri);
297  indent(out, indent_level + 2)
298  << "<Ref> { " << group_ref->get_name() << " }\n";
299  }
300 
301  // We have to write the children nodes before we write the vertex
302  // references, since we might be referencing a vertex that's defined in one
303  // of those children nodes!
304  EggGroupNode::write(out, indent_level + 2);
305  write_vertex_ref(out, indent_level + 2);
306 
307  indent(out, indent_level) << "}\n";
308 }
309 
310 /**
311  * Writes just the <Billboard> entry and related fields to the indicated
312  * ostream.
313  */
314 void EggGroup::
315 write_billboard_flags(ostream &out, int indent_level) const {
316  if (get_billboard_type() != BT_none) {
317  indent(out, indent_level)
318  << "<Billboard> { " << get_billboard_type() << " }\n";
319  }
320 
321  if (has_billboard_center()) {
322  indent(out, indent_level)
323  << "<BillboardCenter> { " << get_billboard_center() << " }\n";
324  }
325 }
326 
327 /**
328  * Writes just the <Collide> entry and related fields to the indicated
329  * ostream.
330  */
331 void EggGroup::
332 write_collide_flags(ostream &out, int indent_level) const {
333  if (get_cs_type() != CST_none) {
334  indent(out, indent_level) << "<Collide> ";
335  if (has_collision_name()) {
336  enquote_string(out, get_collision_name()) << " ";
337  }
338  out << "{ " << get_cs_type();
339  if (get_collide_flags() != CF_none) {
340  out << " " << get_collide_flags();
341  }
342  out << " }\n";
343  }
344 
345  if (has_collide_mask()) {
346  indent(out, indent_level)
347  << "<Scalar> collide-mask { 0x";
348  get_collide_mask().output_hex(out, 0);
349  out << " }\n";
350  }
351 
352  if (has_from_collide_mask()) {
353  indent(out, indent_level)
354  << "<Scalar> from-collide-mask { 0x";
355  get_from_collide_mask().output_hex(out, 0);
356  out << " }\n";
357  }
358 
359  if (has_into_collide_mask()) {
360  indent(out, indent_level)
361  << "<Scalar> into-collide-mask { 0x";
362  get_into_collide_mask().output_hex(out, 0);
363  out << " }\n";
364  }
365 }
366 
367 /**
368  * Writes the <Model> flag and related flags to the indicated ostream.
369  */
370 void EggGroup::
371 write_model_flags(ostream &out, int indent_level) const {
372  if (get_dcs_type() != DC_unspecified) {
373  indent(out, indent_level)
374  << "<DCS> { " << get_dcs_type() << " }\n";
375  }
376 
377  if (get_dart_type() != DT_none) {
378  indent(out, indent_level)
379  << "<Dart> { " << get_dart_type() << " }\n";
380  }
381 
382  if (get_model_flag()) {
383  indent(out, indent_level) << "<Model> { 1 }\n";
384  }
385 
386  if (get_texlist_flag()) {
387  indent(out, indent_level) << "<TexList> { 1 }\n";
388  }
389 
390  if (get_direct_flag()) {
391  indent(out, indent_level) << "<Scalar> direct { 1 }\n";
392  }
393 }
394 
395 /**
396  * Writes the <Switch> flag and related flags to the indicated ostream.
397  */
398 void EggGroup::
399 write_switch_flags(ostream &out, int indent_level) const {
400  if (get_switch_flag()) {
401  indent(out, indent_level) << "<Switch> { 1 }\n";
402  if (get_switch_fps() != 0.0) {
403  indent(out, indent_level)
404  << "<Scalar> fps { " << get_switch_fps() << " }\n";
405  }
406  }
407 }
408 
409 /**
410  * Writes just the <ObjectTypes> entries, if any, to the indicated ostream.
411  */
412 void EggGroup::
413 write_object_types(ostream &out, int indent_level) const {
414  vector_string::const_iterator oi;
415  for (oi = _object_types.begin(); oi != _object_types.end(); ++oi) {
416  indent(out, indent_level)
417  << "<ObjectType> { ";
418  enquote_string(out, (*oi)) << " }\n";
419  }
420 }
421 
422 /**
423  * Writes the flags related to decaling, if any.
424  */
425 void EggGroup::
426 write_decal_flags(ostream &out, int indent_level) const {
427  if (get_decal_flag()) {
428  indent(out, indent_level) << "<Scalar> decal { 1 }\n";
429  }
430 }
431 
432 /**
433  * Writes just the <Tag> entries, if any, to the indicated ostream.
434  */
435 void EggGroup::
436 write_tags(ostream &out, int indent_level) const {
437  TagData::const_iterator ti;
438  for (ti = _tag_data.begin(); ti != _tag_data.end(); ++ti) {
439  const string &key = (*ti).first;
440  const string &value = (*ti).second;
441 
442  indent(out, indent_level) << "<Tag> ";
443  enquote_string(out, key) << " {\n";
444  enquote_string(out, value, indent_level + 2) << "\n";
445  indent(out, indent_level) << "}\n";
446  }
447 }
448 
449 /**
450  * Writes the flags inherited from EggRenderMode and similar flags that
451  * control obscure render effects.
452  */
453 void EggGroup::
454 write_render_mode(ostream &out, int indent_level) const {
455  EggRenderMode::write(out, indent_level);
456 
457  if (get_nofog_flag()) {
458  indent(out, indent_level) << "<Scalar> no-fog { 1 }\n";
459  }
460 }
461 
462 /**
463  * Returns true if this particular node represents a <Joint> entry or not.
464  * This is a handy thing to know since Joints are sorted to the end of their
465  * sibling list when writing an egg file. See EggGroupNode::write().
466  */
467 bool EggGroup::
468 is_joint() const {
469  return (get_group_type() == GT_joint);
470 }
471 
472 /**
473  * Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or
474  * some such object at this level or above this group that has an alpha_mode
475  * other than AM_unspecified. Returns a valid EggRenderMode pointer if one is
476  * found, or NULL otherwise.
477  */
480  if (get_alpha_mode() != AM_unspecified) {
481  return this;
482  }
484 }
485 
486 /**
487  * Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or
488  * some such object at this level or above this group that has a
489  * depth_write_mode other than DWM_unspecified. Returns a valid EggRenderMode
490  * pointer if one is found, or NULL otherwise.
491  */
494  if (get_depth_write_mode() != DWM_unspecified) {
495  return this;
496  }
498 }
499 
500 /**
501  * Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or
502  * some such object at this level or above this group that has a
503  * depth_test_mode other than DTM_unspecified. Returns a valid EggRenderMode
504  * pointer if one is found, or NULL otherwise.
505  */
508  if (get_depth_test_mode() != DTM_unspecified) {
509  return this;
510  }
512 }
513 
514 /**
515  * Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or
516  * some such object at this level or above this group that has a
517  * visibility_mode other than VM_unspecified. Returns a valid EggRenderMode
518  * pointer if one is found, or NULL otherwise.
519  */
522  if (get_visibility_mode() != VM_unspecified) {
523  return this;
524  }
526 }
527 
528 /**
529  * Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or
530  * some such object at this level or above this group that has a depth_offset
531  * specified. Returns a valid EggRenderMode pointer if one is found, or NULL
532  * otherwise.
533  */
536  if (has_depth_offset()) {
537  return this;
538  }
540 }
541 
542 /**
543  * Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or
544  * some such object at this level or above this group that has a draw_order
545  * specified. Returns a valid EggRenderMode pointer if one is found, or NULL
546  * otherwise.
547  */
550  if (has_draw_order()) {
551  return this;
552  }
554 }
555 
556 /**
557  * Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or
558  * some such object at this level or above this group that has a bin
559  * specified. Returns a valid EggRenderMode pointer if one is found, or NULL
560  * otherwise.
561  */
564  if (has_bin()) {
565  return this;
566  }
568 }
569 
570 /**
571  * Walks back up the hierarchy, looking for an EggGroup at this level or above
572  * that has the "indexed" scalar set. Returns the value of the indexed scalar
573  * if it is found, or false if it is not.
574  *
575  * In other words, returns true if the "indexed" flag is in effect for the
576  * indicated node, false otherwise.
577  */
578 bool EggGroup::
580  if (has_indexed_flag()) {
581  return get_indexed_flag();
582  }
584 }
585 
586 /**
587  * Walks back up the hierarchy, looking for an EggGroup at this level or above
588  * that has the "decal" flag set. Returns the value of the decal flag if it
589  * is found, or false if it is not.
590  *
591  * In other words, returns true if the "decal" flag is in effect for the
592  * indicated node, false otherwise.
593  */
594 bool EggGroup::
596  if (get_decal_flag()) {
597  return true;
598  }
600 }
601 
602 /**
603  * Adds the vertex to the set of those referenced by the group, at the
604  * indicated membership level. If the vertex is already being referenced,
605  * increases the membership amount by the indicated amount.
606  */
607 void EggGroup::
608 ref_vertex(EggVertex *vert, double membership) {
609  VertexRef::iterator vri = _vref.find(vert);
610 
611  if (vri != _vref.end()) {
612  // The vertex was already being reffed; increment its membership amount.
613  (*vri).second += membership;
614 
615  // If that takes us down to zero, go ahead and unref the vertex.
616  if ((*vri).second == 0.0) {
617  unref_vertex(vert);
618  }
619 
620  } else {
621  // The vertex was not already reffed; ref it.
622  if (membership != 0.0) {
623  _vref[vert] = membership;
624 
625  bool inserted = vert->_gref.insert(this).second;
626  // Did the group not exist previously in the vertex's gref list? If it
627  // was there already, we must be out of sync between vertices and
628  // groups.
629  nassertv(inserted);
630  }
631  }
632 }
633 
634 
635 /**
636  * Removes the vertex from the set of those referenced by the group. Does
637  * nothing if the vertex is not already reffed.
638  */
639 void EggGroup::
641  VertexRef::iterator vri = _vref.find(vert);
642 
643  if (vri != _vref.end()) {
644  _vref.erase(vri);
645  int count = vert->_gref.erase(this);
646  // Did the group exist in the vertex's gref list? If it didn't, we must
647  // be out of sync between vertices and groups.
648  nassertv(count == 1);
649  }
650 }
651 
652 /**
653  * Removes all vertices from the reference list.
654  */
655 void EggGroup::
657  // We must walk through the vertex ref list, and flag each vertex as
658  // unreffed in its own structure.
659  VertexRef::iterator vri;
660  for (vri = _vref.begin(); vri != _vref.end(); ++vri) {
661  EggVertex *vert = (*vri).first;
662  int count = vert->_gref.erase(this);
663  // Did the group exist in the vertex's gref list? If it didn't, we must
664  // be out of sync between vertices and groups.
665  nassertv(count == 1);
666  }
667 
668  _vref.clear();
669 }
670 
671 
672 /**
673  * Returns the amount of membership of the indicated vertex in this group. If
674  * the vertex is not reffed by the group, returns 0.
675  */
676 double EggGroup::
677 get_vertex_membership(const EggVertex *vert) const {
678  VertexRef::const_iterator vri = _vref.find((EggVertex *)vert);
679 
680  if (vri != _vref.end()) {
681  return (*vri).second;
682  } else {
683  return 0.0;
684  }
685 }
686 
687 /**
688  * Explicitly sets the net membership of the indicated vertex in this group to
689  * the given value.
690  */
691 void EggGroup::
692 set_vertex_membership(EggVertex *vert, double membership) {
693  if (membership == 0.0) {
694  unref_vertex(vert);
695  return;
696  }
697 
698  VertexRef::iterator vri = _vref.find(vert);
699 
700  if (vri != _vref.end()) {
701  // The vertex was already being reffed; just change its membership amount.
702  (*vri).second = membership;
703 
704  } else {
705  // The vertex was not already reffed; ref it.
706  _vref[vert] = membership;
707 
708  bool inserted = vert->_gref.insert(this).second;
709  // Did the group not exist previously in the vertex's gref list? If it
710  // was there already, we must be out of sync between vertices and groups.
711  nassertv(inserted);
712  }
713 }
714 
715 /**
716  * Moves all of the vertex references from the indicated other group into this
717  * one. If a given vertex was previously shared by both groups, the relative
718  * memberships will be summed.
719  */
720 void EggGroup::
722  nassertv(other != this);
723  VertexRef::const_iterator vri;
724  for (vri = other->vref_begin(); vri != other->vref_end(); ++vri) {
725  EggVertex *vert = (*vri).first;
726  double membership = (*vri).second;
727  ref_vertex(vert, membership);
728  }
729  other->unref_all_vertices();
730 }
731 
732 
733 #ifdef _DEBUG
734 
735 /**
736  * Verifies that each vertex in the group exists and that it knows it is
737  * referenced by the group.
738  */
739 void EggGroup::
740 test_vref_integrity() const {
742 
743  VertexRef::const_iterator vri;
744  for (vri = vref_begin(); vri != vref_end(); ++vri) {
745  const EggVertex *vert = (*vri).first;
746  vert->test_ref_count_integrity();
747 
748  nassertv(vert->has_gref(this));
749  }
750 }
751 
752 #endif // _DEBUG
753 
754 /**
755  * Adds a new <Ref> entry to the group. This declares an internal reference
756  * to another node, and is used to implement scene-graph instancing; it is
757  * only valid if the group_type is GT_instance.
758  */
759 void EggGroup::
761  nassertv(get_group_type() == GT_instance);
762  _group_refs.push_back(group);
763 }
764 
765 /**
766  * Returns the number of <Ref> entries within this group. See
767  * add_group_ref().
768  */
769 int EggGroup::
770 get_num_group_refs() const {
771  return _group_refs.size();
772 }
773 
774 /**
775  * Returns the nth <Ref> entry within this group. See add_group_ref().
776  */
778 get_group_ref(int n) const {
779  nassertr(n >= 0 && n < (int)_group_refs.size(), nullptr);
780  return _group_refs[n];
781 }
782 
783 /**
784  * Removes the nth <Ref> entry within this group. See add_group_ref().
785  */
786 void EggGroup::
788  nassertv(n >= 0 && n < (int)_group_refs.size());
789  _group_refs.erase(_group_refs.begin() + n);
790 }
791 
792 /**
793  * Removes all of the <Ref> entries within this group. See add_group_ref().
794  */
795 void EggGroup::
797  _group_refs.clear();
798 }
799 
800 
801 
802 /**
803  * Returns the GroupType value associated with the given string
804  * representation, or GT_invalid if the string does not match any known
805  * GroupType value.
806  */
807 EggGroup::GroupType EggGroup::
808 string_group_type(const string &strval) {
809  if (cmp_nocase_uh(strval, "group") == 0) {
810  return GT_group;
811  } else if (cmp_nocase_uh(strval, "instance") == 0) {
812  return GT_instance;
813  } else if (cmp_nocase_uh(strval, "joint") == 0) {
814  return GT_joint;
815  } else {
816  return GT_invalid;
817  }
818 }
819 
820 /**
821  * Returns the DartType value associated with the given string representation,
822  * or DT_none if the string does not match any known DartType value.
823  */
824 EggGroup::DartType EggGroup::
825 string_dart_type(const string &strval) {
826  if (cmp_nocase_uh(strval, "sync") == 0) {
827  return DT_sync;
828  } else if (cmp_nocase_uh(strval, "nosync") == 0) {
829  return DT_nosync;
830  } else if (cmp_nocase_uh(strval, "default") == 0) {
831  return DT_default;
832  } else if (cmp_nocase_uh(strval, "structured") == 0) {
833  return DT_structured;
834  } else {
835  return DT_none;
836  }
837 }
838 
839 /**
840  * Returns the DCSType value associated with the given string representation,
841  * or DC_unspecified if the string does not match any known DCSType value.
842  */
843 EggGroup::DCSType EggGroup::
844 string_dcs_type(const string &strval) {
845  if (cmp_nocase_uh(strval, "none") == 0) {
846  return DC_none;
847  } else if (cmp_nocase_uh(strval, "local") == 0) {
848  return DC_local;
849  } else if (cmp_nocase_uh(strval, "net") == 0) {
850  return DC_net;
851  } else if (cmp_nocase_uh(strval, "no_touch") == 0) {
852  return DC_no_touch;
853  } else if (cmp_nocase_uh(strval, "default") == 0) {
854  return DC_default;
855  } else {
856  return DC_unspecified;
857  }
858 }
859 
860 /**
861  * Returns the BillboardType value associated with the given string
862  * representation, or BT_none if the string does not match any known
863  * BillboardType value.
864  */
865 EggGroup::BillboardType EggGroup::
866 string_billboard_type(const string &strval) {
867  if (cmp_nocase_uh(strval, "axis") == 0) {
868  return BT_axis;
869  } else if (cmp_nocase_uh(strval, "point_eye") == 0) {
870  return BT_point_camera_relative;
871  } else if (cmp_nocase_uh(strval, "point_world") == 0) {
872  return BT_point_world_relative;
873  } else if (cmp_nocase_uh(strval, "point") == 0) {
874  return BT_point_world_relative;
875  } else {
876  return BT_none;
877  }
878 }
879 
880 /**
881  * Returns the CollisionSolidType value associated with the given string
882  * representation, or CST_none if the string does not match any known
883  * CollisionSolidType value.
884  */
885 EggGroup::CollisionSolidType EggGroup::
886 string_cs_type(const string &strval) {
887  if (cmp_nocase_uh(strval, "plane") == 0) {
888  return CST_plane;
889  } else if (cmp_nocase_uh(strval, "polygon") == 0) {
890  return CST_polygon;
891  } else if (cmp_nocase_uh(strval, "polyset") == 0) {
892  return CST_polyset;
893  } else if (cmp_nocase_uh(strval, "sphere") == 0) {
894  return CST_sphere;
895  } else if (cmp_nocase_uh(strval, "box") == 0) {
896  return CST_box;
897  } else if (cmp_nocase_uh(strval, "inv-sphere") == 0 ||
898  cmp_nocase_uh(strval, "invsphere") == 0) {
899  return CST_inv_sphere;
900  } else if (cmp_nocase_uh(strval, "tube") == 0 ||
901  cmp_nocase_uh(strval, "capsule") == 0) {
902  return CST_tube;
903  } else if (cmp_nocase_uh(strval, "floor-mesh") == 0 ||
904  cmp_nocase_uh(strval, "floormesh") == 0) {
905  return CST_floor_mesh;
906  } else {
907  return CST_none;
908  }
909 }
910 
911 /**
912  * Returns the CollideFlags value associated with the given string
913  * representation, or CF_none if the string does not match any known
914  * CollideFlags value. This only recognizes a single keyword; it does not
915  * attempt to parse a string of keywords.
916  */
917 EggGroup::CollideFlags EggGroup::
918 string_collide_flags(const string &strval) {
919  if (cmp_nocase_uh(strval, "intangible") == 0) {
920  return CF_intangible;
921  } else if (cmp_nocase_uh(strval, "event") == 0) {
922  return CF_event;
923  } else if (cmp_nocase_uh(strval, "descend") == 0) {
924  return CF_descend;
925  } else if (cmp_nocase_uh(strval, "keep") == 0) {
926  return CF_keep;
927  } else if (cmp_nocase_uh(strval, "solid") == 0) {
928  return CF_solid;
929  } else if (cmp_nocase_uh(strval, "center") == 0) {
930  return CF_center;
931  } else if (cmp_nocase_uh(strval, "turnstile") == 0) {
932  return CF_turnstile;
933  } else if (cmp_nocase_uh(strval, "level") == 0) {
934  return CF_level;
935  } else {
936  return CF_none;
937  }
938 }
939 
940 /**
941  * Returns the BlendMode value associated with the given string
942  * representation, or BM_none if the string does not match any known
943  * BlendMode.
944  */
945 EggGroup::BlendMode EggGroup::
946 string_blend_mode(const string &strval) {
947  if (cmp_nocase_uh(strval, "none") == 0) {
948  return BM_none;
949  } else if (cmp_nocase_uh(strval, "add") == 0) {
950  return BM_add;
951  } else if (cmp_nocase_uh(strval, "subtract") == 0) {
952  return BM_subtract;
953  } else if (cmp_nocase_uh(strval, "inv_subtract") == 0) {
954  return BM_inv_subtract;
955  } else if (cmp_nocase_uh(strval, "min") == 0) {
956  return BM_min;
957  } else if (cmp_nocase_uh(strval, "max") == 0) {
958  return BM_max;
959  } else {
960  return BM_unspecified;
961  }
962 }
963 
964 /**
965  * Returns the BlendOperand value associated with the given string
966  * representation, or BO_none if the string does not match any known
967  * BlendOperand.
968  */
969 EggGroup::BlendOperand EggGroup::
970 string_blend_operand(const string &strval) {
971  if (cmp_nocase_uh(strval, "zero") == 0) {
972  return BO_zero;
973  } else if (cmp_nocase_uh(strval, "one") == 0) {
974  return BO_one;
975  } else if (cmp_nocase_uh(strval, "incoming_color") == 0) {
976  return BO_incoming_color;
977  } else if (cmp_nocase_uh(strval, "one_minus_incoming_color") == 0) {
978  return BO_one_minus_incoming_color;
979  } else if (cmp_nocase_uh(strval, "fbuffer_color") == 0) {
980  return BO_fbuffer_color;
981  } else if (cmp_nocase_uh(strval, "one_minus_fbuffer_color") == 0) {
982  return BO_one_minus_fbuffer_color;
983  } else if (cmp_nocase_uh(strval, "incoming_alpha") == 0) {
984  return BO_incoming_alpha;
985  } else if (cmp_nocase_uh(strval, "one_minus_incoming_alpha") == 0) {
986  return BO_one_minus_incoming_alpha;
987  } else if (cmp_nocase_uh(strval, "fbuffer_alpha") == 0) {
988  return BO_fbuffer_alpha;
989  } else if (cmp_nocase_uh(strval, "one_minus_fbuffer_alpha") == 0) {
990  return BO_one_minus_fbuffer_alpha;
991  } else if (cmp_nocase_uh(strval, "constant_color") == 0) {
992  return BO_constant_color;
993  } else if (cmp_nocase_uh(strval, "one_minus_constant_color") == 0) {
994  return BO_one_minus_constant_color;
995  } else if (cmp_nocase_uh(strval, "constant_alpha") == 0) {
996  return BO_constant_alpha;
997  } else if (cmp_nocase_uh(strval, "one_minus_constant_alpha") == 0) {
998  return BO_one_minus_constant_alpha;
999  } else if (cmp_nocase_uh(strval, "incoming_color_saturate") == 0) {
1000  return BO_incoming_color_saturate;
1001  } else if (cmp_nocase_uh(strval, "color_scale") == 0) {
1002  return BO_color_scale;
1003  } else if (cmp_nocase_uh(strval, "one_minus_color_scale") == 0) {
1004  return BO_one_minus_color_scale;
1005  } else if (cmp_nocase_uh(strval, "alpha_scale") == 0) {
1006  return BO_alpha_scale;
1007  } else if (cmp_nocase_uh(strval, "one_minus_alpha_scale") == 0) {
1008  return BO_one_minus_alpha_scale;
1009  } else {
1010  return BO_unspecified;
1011  }
1012 }
1013 
1014 /**
1015  * Returns this object cross-cast to an EggTransform pointer, if it inherits
1016  * from EggTransform, or NULL if it does not.
1017  */
1020  return this;
1021 }
1022 
1023 
1024 /**
1025  * Writes out the vertex ref component of the group body only. This may
1026  * consist of a number of <VertexRef> entries, each with its own membership
1027  * value.
1028  */
1029 void EggGroup::
1030 write_vertex_ref(ostream &out, int indent_level) const {
1031  // We want to put the vertices together into groups first by vertex pool,
1032  // then by membership value. Each of these groups becomes a separate
1033  // VertexRef entry. Within each group, we'll sort the vertices by index
1034  // number.
1035 
1036  typedef pset<int> Indices;
1037  typedef pmap<double, Indices> Memberships;
1038  typedef pmap<EggVertexPool *, Memberships> Pools;
1039 
1040  Pools _entries;
1041  bool all_membership_one = true;
1042 
1043  VertexRef::const_iterator vri;
1044  for (vri = _vref.begin(); vri != _vref.end(); ++vri) {
1045  EggVertex *vert = (*vri).first;
1046  double membership = (*vri).second;
1047 
1048  if (membership != 1.0) {
1049  all_membership_one = false;
1050  }
1051 
1052  _entries[vert->get_pool()][membership].insert(vert->get_index());
1053  }
1054 
1055  // Now that we've reordered them, we can simply traverse the entries and
1056  // write them out.
1057  Pools::const_iterator pi;
1058  for (pi = _entries.begin(); pi != _entries.end(); ++pi) {
1059  EggVertexPool *pool = (*pi).first;
1060  const Memberships &memberships = (*pi).second;
1061  Memberships::const_iterator mi;
1062  for (mi = memberships.begin(); mi != memberships.end(); ++mi) {
1063  double membership = (*mi).first;
1064  const Indices &indices = (*mi).second;
1065 
1066  indent(out, indent_level)
1067  << "<VertexRef> {\n";
1068  write_long_list(out, indent_level+2, indices.begin(), indices.end(),
1069  "", "", 72);
1070 
1071  // If all vrefs in this group have membership of 1, don't bother to
1072  // write out the membership scalar.
1073  if (!all_membership_one) {
1074  indent(out, indent_level + 2)
1075  << "<Scalar> membership { " << membership << " }\n";
1076  }
1077  if (pool == nullptr) {
1078  indent(out, indent_level + 2)
1079  << "// Invalid NULL vertex pool.\n";
1080  } else {
1081  indent(out, indent_level + 2)
1082  << "<Ref> { " << pool->get_name() << " }\n";
1083  }
1084  indent(out, indent_level)
1085  << "}\n";
1086  }
1087  }
1088 }
1089 
1090 /**
1091  * This function is called within parse_egg(). It should call the appropriate
1092  * function on the lexer to initialize the parser into the state associated
1093  * with this object. If the object cannot be parsed into directly, it should
1094  * return false.
1095  */
1096 bool EggGroup::
1097 egg_start_parse_body() {
1098  egg_start_group_body();
1099  return true;
1100 }
1101 
1102 /**
1103  * This is called within update_under() after all the various under settings
1104  * have been inherited directly from the parent node. It is responsible for
1105  * adjusting these settings to reflect states local to the current node; for
1106  * instance, an <Instance> node will force the UF_under_instance bit on.
1107  */
1108 void EggGroup::
1109 adjust_under() {
1110  // If we have our own transform, it carries forward.
1111 
1112  // As of 41801, this now also affects the local_coord flag, below. This
1113  // means that a <Transform> entry within an <Instance> node transforms the
1114  // instance itself.
1115  if (has_transform()) {
1116  _under_flags |= UF_under_transform;
1117 
1118  // Our own transform also affects our node frame.
1119  _node_frame =
1120  new MatrixFrame(get_transform3d() * get_node_frame());
1121 
1122  // To prevent trying to invert a sigular matrix
1123  LMatrix4d mat;
1124  bool invert_ok = mat.invert_from(get_node_frame());
1125  if (invert_ok) {
1126  _node_frame_inv =
1127  new MatrixFrame(mat);
1128  } else {
1129  _node_frame_inv = nullptr;
1130  }
1131 
1132  _vertex_to_node =
1133  new MatrixFrame(get_vertex_frame() * get_node_frame_inv());
1134  _node_to_vertex =
1135  new MatrixFrame(get_node_frame() * get_vertex_frame_inv());
1136 
1137  }
1138 
1139  if (is_instance_type()) {
1140  _under_flags |= UF_under_instance;
1141  if (_under_flags & UF_under_transform) {
1142  // If we've reached an instance node and we're under a transform, that
1143  // means we've just defined a local coordinate system.
1144  _under_flags |= UF_local_coord;
1145  }
1146 
1147  // An instance node means that from this point and below, vertices are
1148  // defined relative to this node. Thus, the node frame becomes the vertex
1149  // frame.
1150  _vertex_frame = _node_frame;
1151  _vertex_frame_inv = _node_frame_inv;
1152  _vertex_to_node = nullptr;
1153  _node_to_vertex = nullptr;
1154  }
1155 }
1156 
1157 /**
1158  * This is called from within the egg code by transform(). It applies a
1159  * transformation matrix to the current node in some sensible way, then
1160  * continues down the tree.
1161  *
1162  * The first matrix is the transformation to apply; the second is its inverse.
1163  * The third parameter is the coordinate system we are changing to, or
1164  * CS_default if we are not changing coordinate systems.
1165  */
1166 void EggGroup::
1167 r_transform(const LMatrix4d &mat, const LMatrix4d &inv,
1168  CoordinateSystem to_cs) {
1169  if (has_transform() || get_group_type() == GT_joint) {
1170  // Since we want to apply this transform to all matrices, including nested
1171  // matrices, we can't simply premult it in and leave it, because that
1172  // would leave the rotational component in the scene graph's matrix, and
1173  // all nested matrices would inherit the same rotational component. So we
1174  // have to premult and then postmult by the inverse to undo the rotational
1175  // component each time.
1176 
1177  LMatrix4d mat1 = mat;
1178  LMatrix4d inv1 = inv;
1179 
1180  // If we have a translation component, we should only apply it to the top
1181  // matrix. All subsequent matrices get just the rotational component.
1182  mat1.set_row(3, LVector3d(0.0, 0.0, 0.0));
1183  inv1.set_row(3, LVector3d(0.0, 0.0, 0.0));
1184 
1185  internal_set_transform(inv1 * get_transform3d() * mat);
1186 
1187  if (_default_pose.has_transform()) {
1188  LMatrix4d t = _default_pose.get_transform3d();
1189  _default_pose.clear_transform();
1190  _default_pose.add_matrix4(inv1 * t * mat);
1191  }
1192 
1193  EggGroupNode::r_transform(mat1, inv1, to_cs);
1194  } else {
1195  EggGroupNode::r_transform(mat, inv, to_cs);
1196  }
1197 
1198  // Convert the LOD description too.
1199  if (has_lod()) {
1200  _lod->transform(mat);
1201  }
1202  if (has_billboard_center()) {
1203  _billboard_center = _billboard_center * mat;
1204  }
1205 }
1206 
1207 /**
1208  * The recursive implementation of flatten_transforms().
1209  */
1210 void EggGroup::
1211 r_flatten_transforms() {
1212  EggGroupNode::r_flatten_transforms();
1213 
1214  if (is_local_coord()) {
1215  LMatrix4d mat = get_vertex_frame();
1216  if (has_lod()) {
1217  _lod->transform(mat);
1218  }
1219 
1220  if (get_billboard_type() != BT_none && !has_billboard_center()) {
1221  // If we had a billboard without an explicit center, it was an implicit
1222  // instance. Now it's not any more.
1223  set_billboard_center(LPoint3d(0.0, 0.0, 0.0) * mat);
1224 
1225  } else if (has_billboard_center()) {
1226  _billboard_center = _billboard_center * mat;
1227  }
1228  }
1229 
1230  if (get_group_type() == GT_instance) {
1231  set_group_type(GT_group);
1232  }
1233 
1234  if (get_group_type() != GT_joint) {
1235  internal_clear_transform();
1236  }
1237 }
1238 
1239 
1240 /**
1241  * This virtual method is inherited by EggTransform3d; it is called whenever
1242  * the transform is changed.
1243  */
1244 void EggGroup::
1245 transform_changed() {
1246  // Recompute all of the cached transforms at this node and below. We should
1247  // probably make this smarter and do lazy evaluation of these transforms,
1248  // rather than having to recompute the whole tree with every change to a
1249  // parent node's transform.
1250  update_under(0);
1251 }
1252 
1253 
1254 
1255 /**
1256  *
1257  */
1258 ostream &operator << (ostream &out, EggGroup::GroupType t) {
1259  switch (t) {
1260  case EggGroup::GT_invalid:
1261  return out << "invalid group";
1262  case EggGroup::GT_group:
1263  return out << "group";
1264  case EggGroup::GT_instance:
1265  return out << "instance";
1266  case EggGroup::GT_joint:
1267  return out << "joint";
1268  }
1269 
1270  nassertr(false, out);
1271  return out << "(**invalid**)";
1272 }
1273 
1274 /**
1275  *
1276  */
1277 ostream &operator << (ostream &out, EggGroup::DartType t) {
1278  switch (t) {
1279  case EggGroup::DT_none:
1280  return out << "none";
1281  case EggGroup::DT_sync:
1282  return out << "sync";
1283  case EggGroup::DT_nosync:
1284  return out << "nosync";
1285  case EggGroup::DT_structured:
1286  return out << "structured";
1287  case EggGroup::DT_default:
1288  return out << "1";
1289  }
1290 
1291  nassertr(false, out);
1292  return out << "(**invalid**)";
1293 }
1294 
1295 /**
1296  *
1297  */
1298 ostream &operator << (ostream &out, EggGroup::DCSType t) {
1299  switch (t) {
1300  case EggGroup::DC_unspecified:
1301  return out << "unspecified";
1302  case EggGroup::DC_none:
1303  return out << "none";
1304  case EggGroup::DC_local:
1305  return out << "local";
1306  case EggGroup::DC_net:
1307  return out << "net";
1308  case EggGroup::DC_no_touch:
1309  return out << "no_touch";
1310  case EggGroup::DC_default:
1311  return out << "1";
1312  }
1313 
1314  nassertr(false, out);
1315  return out << "(**invalid**)";
1316 }
1317 
1318 /**
1319  *
1320  */
1321 ostream &operator << (ostream &out, EggGroup::BillboardType t) {
1322  switch (t) {
1323  case EggGroup::BT_none:
1324  return out << "none";
1325  case EggGroup::BT_axis:
1326  return out << "axis";
1327  case EggGroup::BT_point_camera_relative:
1328  return out << "point_eye";
1329  case EggGroup::BT_point_world_relative:
1330  return out << "point_world";
1331  }
1332 
1333  nassertr(false, out);
1334  return out << "(**invalid**)";
1335 }
1336 
1337 /**
1338  *
1339  */
1340 ostream &operator << (ostream &out, EggGroup::CollisionSolidType t) {
1341  switch (t) {
1342  case EggGroup::CST_none:
1343  return out << "None";
1344  case EggGroup::CST_plane:
1345  return out << "Plane";
1346  case EggGroup::CST_polygon:
1347  return out << "Polygon";
1348  case EggGroup::CST_polyset:
1349  return out << "Polyset";
1350  case EggGroup::CST_sphere:
1351  return out << "Sphere";
1352  case EggGroup::CST_inv_sphere:
1353  return out << "InvSphere";
1354  case EggGroup::CST_tube:
1355  return out << "Tube";
1356  case EggGroup::CST_floor_mesh:
1357  return out << "FloorMesh";
1358  case EggGroup::CST_box:
1359  return out << "Box";
1360  }
1361 
1362  nassertr(false, out);
1363  return out << "(**invalid**)";
1364 }
1365 
1366 /**
1367  *
1368  */
1369 ostream &operator << (ostream &out, EggGroup::CollideFlags t) {
1370  if (t == EggGroup::CF_none) {
1371  return out << "none";
1372  }
1373  int bits = (int)t;
1374  const char *space = "";
1375 
1376  if (bits & EggGroup::CF_intangible) {
1377  out << space << "intangible";
1378  space = " ";
1379  }
1380  if (bits & EggGroup::CF_event) {
1381  out << space << "event";
1382  space = " ";
1383  }
1384  if (bits & EggGroup::CF_descend) {
1385  out << space << "descend";
1386  space = " ";
1387  }
1388  if (bits & EggGroup::CF_keep) {
1389  out << space << "keep";
1390  space = " ";
1391  }
1392  if (bits & EggGroup::CF_solid) {
1393  out << space << "solid";
1394  space = " ";
1395  }
1396  if (bits & EggGroup::CF_center) {
1397  out << space << "center";
1398  space = " ";
1399  }
1400  if (bits & EggGroup::CF_turnstile) {
1401  out << space << "turnstile";
1402  space = " ";
1403  }
1404  if (bits & EggGroup::CF_level) {
1405  out << space << "level";
1406  space = " ";
1407  }
1408  return out;
1409 }
1410 
1411 /**
1412  *
1413  */
1414 ostream &
1415 operator << (ostream &out, EggGroup::BlendMode t) {
1416  switch (t) {
1417  case EggGroup::BM_unspecified:
1418  return out << "unspecified";
1419 
1420  case EggGroup::BM_none:
1421  return out << "none";
1422 
1423  case EggGroup::BM_add:
1424  return out << "add";
1425 
1426  case EggGroup::BM_subtract:
1427  return out << "subtract";
1428 
1429  case EggGroup::BM_inv_subtract:
1430  return out << "inv_subtract";
1431 
1432  case EggGroup::BM_min:
1433  return out << "min";
1434 
1435  case EggGroup::BM_max:
1436  return out << "max";
1437  }
1438 
1439  return out << "**invalid EggGroup::BlendMode(" << (int)t << ")**";
1440 }
1441 
1442 /**
1443  *
1444  */
1445 ostream &
1446 operator << (ostream &out, EggGroup::BlendOperand t) {
1447  switch (t) {
1448  case EggGroup::BO_unspecified:
1449  return out << "unspecified";
1450 
1451  case EggGroup::BO_zero:
1452  return out << "zero";
1453 
1454  case EggGroup::BO_one:
1455  return out << "one";
1456 
1457  case EggGroup::BO_incoming_color:
1458  return out << "incomfing_color";
1459 
1460  case EggGroup::BO_one_minus_incoming_color:
1461  return out << "one_minus_incoming_color";
1462 
1463  case EggGroup::BO_fbuffer_color:
1464  return out << "fbuffer_color";
1465 
1466  case EggGroup::BO_one_minus_fbuffer_color:
1467  return out << "one_minus_fbuffer_color";
1468 
1469  case EggGroup::BO_incoming_alpha:
1470  return out << "incoming_alpha";
1471 
1472  case EggGroup::BO_one_minus_incoming_alpha:
1473  return out << "one_minus_incoming_alpha";
1474 
1475  case EggGroup::BO_fbuffer_alpha:
1476  return out << "fbuffer_alpha";
1477 
1478  case EggGroup::BO_one_minus_fbuffer_alpha:
1479  return out << "one_minus_fbuffer_alpha";
1480 
1481  case EggGroup::BO_constant_color:
1482  return out << "constant_color";
1483 
1484  case EggGroup::BO_one_minus_constant_color:
1485  return out << "one_minus_constant_color";
1486 
1487  case EggGroup::BO_constant_alpha:
1488  return out << "constant_alpha";
1489 
1490  case EggGroup::BO_one_minus_constant_alpha:
1491  return out << "one_minus_constant_alpha";
1492 
1493  case EggGroup::BO_incoming_color_saturate:
1494  return out << "incoming_color_saturate";
1495 
1496  case EggGroup::BO_color_scale:
1497  return out << "color_scale";
1498 
1499  case EggGroup::BO_one_minus_color_scale:
1500  return out << "one_minus_color_scale";
1501 
1502  case EggGroup::BO_alpha_scale:
1503  return out << "alpha_scale";
1504 
1505  case EggGroup::BO_one_minus_alpha_scale:
1506  return out << "one_minus_alpha_scale";
1507  }
1508 
1509  return out << "**invalid EggGroup::BlendOperand(" << (int)t << ")**";
1510 }
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.
Definition: eggGroup.cxx:177
virtual bool determine_indexed()
Walks back up the hierarchy, looking for an EggGroup at this level or above that has the "indexed" sc...
Definition: eggNode.cxx:191
AlphaMode get_alpha_mode() const
Returns the alpha mode that was set, or AM_unspecified if nothing was set.
Definition: eggRenderMode.I:98
VisibilityMode get_visibility_mode() const
Returns the visibility mode that was set, or VM_unspecified if nothing was set.
Definition: eggRenderMode.I:75
static DartType string_dart_type(const std::string &strval)
Returns the DartType value associated with the given string representation, or DT_none if the string ...
Definition: eggGroup.cxx:825
const LMatrix4d & get_transform3d() const
Returns the overall transform as a 4x4 matrix.
Definition: eggTransform.I:212
void clear_transform()
Resets the transform to empty, identity.
Definition: eggTransform.I:114
void write_render_mode(std::ostream &out, int indent_level) const
Writes the flags inherited from EggRenderMode and similar flags that control obscure render effects.
Definition: eggGroup.cxx:454
virtual bool is_joint() const
Returns true if this particular node represents a <Joint> entry or not.
Definition: eggGroup.cxx:468
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is our own Panda specialization on the default STL map.
Definition: pmap.h:49
void write_header(std::ostream &out, int indent_level, const char *egg_keyword) const
Writes the first line of the egg object, e.g.
virtual EggRenderMode * determine_depth_write_mode()
Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or some such object at this leve...
Definition: eggGroup.cxx:493
virtual EggRenderMode * determine_bin()
Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or some such object at this leve...
Definition: eggGroup.cxx:563
bool has_bin() const
Returns true if a bin name has been set for this particular object.
const LMatrix4d & get_node_frame_inv() const
Returns the inverse of the matrix returned by get_node_frame().
Definition: eggNode.I:149
virtual EggRenderMode * determine_alpha_mode()
Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or some such object at this leve...
Definition: eggGroup.cxx:479
VertexRef::const_iterator vref_begin() const
Returns an iterator that can, in conjunction with vref_end(), be used to traverse the entire set of r...
Definition: eggGroup.I:845
bool remove_object_type(const std::string &object_type)
Removes the first instance of the indicated object type from the group if it is present.
Definition: eggGroup.cxx:161
void add_group_ref(EggGroup *group)
Adds a new <Ref> entry to the group.
Definition: eggGroup.cxx:760
EggVertexPool * get_pool() const
Returns the vertex pool this vertex belongs in.
Definition: eggVertex.I:19
const LMatrix4d & get_vertex_frame() const
Returns the coordinate frame of the vertices referenced by primitives at or under this node.
Definition: eggNode.I:108
A base class for nodes in the hierarchy that are not leaf nodes.
Definition: eggGroupNode.h:46
ostream & enquote_string(ostream &out, const string &str, int indent_level, bool always_quote)
Writes the string to the indicated output stream.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual EggRenderMode * determine_depth_test_mode()
Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or some such object at this leve...
Definition: eggGroup.cxx:507
virtual EggRenderMode * determine_draw_order()
Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or some such object at this leve...
Definition: eggNode.cxx:160
static BillboardType string_billboard_type(const std::string &strval)
Returns the BillboardType value associated with the given string representation, or BT_none if the st...
Definition: eggGroup.cxx:866
virtual EggRenderMode * determine_depth_test_mode()
Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or some such object at this leve...
Definition: eggNode.cxx:115
void steal_vrefs(EggGroup *other)
Moves all of the vertex references from the indicated other group into this one.
Definition: eggGroup.cxx:721
void write_collide_flags(std::ostream &out, int indent_level) const
Writes just the <Collide> entry and related fields to the indicated ostream.
Definition: eggGroup.cxx:332
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void write(std::ostream &out, int indent_level, const std::string &label) const
Writes the transform to the indicated stream in Egg format.
bool test_ref_count_integrity() const
Does some easy checks to make sure that the reference count isn't completely bogus.
void write_billboard_flags(std::ostream &out, int indent_level) const
Writes just the <Billboard> entry and related fields to the indicated ostream.
Definition: eggGroup.cxx:315
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual EggRenderMode * determine_visibility_mode()
Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or some such object at this leve...
Definition: eggGroup.cxx:521
virtual EggTransform * as_transform()
Returns this object cross-cast to an EggTransform pointer, if it inherits from EggTransform,...
Definition: eggGroup.cxx:1019
DepthWriteMode get_depth_write_mode() const
Returns the depth_write mode that was set, or DWM_unspecified if nothing was set.
Definition: eggRenderMode.I:36
void write_model_flags(std::ostream &out, int indent_level) const
Writes the <Model> flag and related flags to the indicated ostream.
Definition: eggGroup.cxx:371
static CollisionSolidType string_cs_type(const std::string &strval)
Returns the CollisionSolidType value associated with the given string representation,...
Definition: eggGroup.cxx:886
void unref_all_vertices()
Removes all vertices from the reference list.
Definition: eggGroup.cxx:656
void unref_vertex(EggVertex *vert)
Removes the vertex from the set of those referenced by the group.
Definition: eggGroup.cxx:640
bool has_gref(const EggGroup *group) const
Returns true if the indicated group references this vertex, false otherwise.
Definition: eggVertex.cxx:733
virtual bool determine_decal()
Walks back up the hierarchy, looking for an EggGroup at this level or above that has the "decal" flag...
Definition: eggGroup.cxx:595
The main glue of the egg hierarchy, this corresponds to the <Group>, <Instance>, and <Joint> type nod...
Definition: eggGroup.h:34
This class stores miscellaneous rendering properties that is associated with geometry,...
Definition: eggRenderMode.h:31
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.
static CollideFlags string_collide_flags(const std::string &strval)
Returns the CollideFlags value associated with the given string representation, or CF_none if the str...
Definition: eggGroup.cxx:918
int get_index() const
Returns the index number of the vertex within its pool.
Definition: eggVertex.I:277
bool is_local_coord() const
Returns true if this node's vertices are not in the global coordinate space.
Definition: eggNode.I:87
static BlendMode string_blend_mode(const std::string &strval)
Returns the BlendMode value associated with the given string representation, or BM_none if the string...
Definition: eggGroup.cxx:946
virtual EggRenderMode * determine_draw_order()
Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or some such object at this leve...
Definition: eggGroup.cxx:549
virtual bool determine_decal()
Walks back up the hierarchy, looking for an EggGroup at this level or above that has the "decal" flag...
Definition: eggNode.cxx:208
const LMatrix4d & get_node_frame() const
Returns the coordinate frame of the node itself.
Definition: eggNode.I:122
void write_switch_flags(std::ostream &out, int indent_level) const
Writes the <Switch> flag and related flags to the indicated ostream.
Definition: eggGroup.cxx:399
virtual EggRenderMode * determine_visibility_mode()
Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or some such object at this leve...
Definition: eggNode.cxx:130
bool has_object_type(const std::string &object_type) const
Returns true if the indicated object type has been added to the group, or false otherwise.
Definition: eggGroup.cxx:145
Any one-, two-, three-, or four-component vertex, possibly with attributes such as a normal.
Definition: eggVertex.h:39
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition: indent.cxx:20
void write_tags(std::ostream &out, int indent_level) const
Writes just the <Tag> entries, if any, to the indicated ostream.
Definition: eggGroup.cxx:436
bool is_instance_type() const
Returns true if this group is an instance type node; i.e.
Definition: eggGroup.I:32
void set_vertex_membership(EggVertex *vert, double membership)
Explicitly sets the net membership of the indicated vertex in this group to the given value.
Definition: eggGroup.cxx:692
void write_long_list(std::ostream &out, int indent_level, InputIterator ifirst, InputIterator ilast, std::string first_prefix="", std::string later_prefix="", int max_col=72)
Writes a list of things to the indicated output stream, with a space separating each item.
Definition: indent.I:22
double get_vertex_membership(const EggVertex *vert) const
Returns the amount of membership of the indicated vertex in this group.
Definition: eggGroup.cxx:677
virtual EggRenderMode * determine_depth_write_mode()
Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or some such object at this leve...
Definition: eggNode.cxx:100
virtual EggRenderMode * determine_alpha_mode()
Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or some such object at this leve...
Definition: eggNode.cxx:85
void write(std::ostream &out, int indent_level) const
Writes the attributes to the indicated output stream in Egg format.
static GroupType string_group_type(const std::string &strval)
Returns the GroupType value associated with the given string representation, or GT_invalid if the str...
Definition: eggGroup.cxx:808
bool has_draw_order() const
Returns true if the draw-order flag has been set for this particular object.
set_billboard_center
Sets the point around which the billboard will rotate, if this node contains a billboard specificatio...
Definition: eggGroup.h:290
virtual EggRenderMode * determine_bin()
Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or some such object at this leve...
Definition: eggNode.cxx:174
get_blend_color
Returns the blend color if one has been specified, or (0, 0, 0, 0) if one has not.
Definition: eggGroup.h:318
virtual bool determine_indexed()
Walks back up the hierarchy, looking for an EggGroup at this level or above that has the "indexed" sc...
Definition: eggGroup.cxx:579
void clear_group_refs()
Removes all of the <Ref> entries within this group.
Definition: eggGroup.cxx:796
void ref_vertex(EggVertex *vert, double membership=1.0)
Adds the vertex to the set of those referenced by the group, at the indicated membership level.
Definition: eggGroup.cxx:608
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool has_depth_offset() const
Returns true if the depth-offset flag has been set for this particular object.
get_group_ref
Returns the nth <Ref> entry within this group.
Definition: eggGroup.h:354
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 remove_group_ref(int n)
Removes the nth <Ref> entry within this group.
Definition: eggGroup.cxx:787
has_blend_color
Returns true if the blend color has been specified, false otherwise.
Definition: eggGroup.h:318
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
void write_object_types(std::ostream &out, int indent_level) const
Writes just the <ObjectTypes> entries, if any, to the indicated ostream.
Definition: eggGroup.cxx:413
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual EggRenderMode * determine_depth_offset()
Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or some such object at this leve...
Definition: eggNode.cxx:145
virtual EggRenderMode * determine_depth_offset()
Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or some such object at this leve...
Definition: eggGroup.cxx:535
void add_matrix4(const LMatrix4d &mat)
Appends an arbitrary 4x4 matrix to the current transform.
Definition: eggTransform.I:132
void write_decal_flags(std::ostream &out, int indent_level) const
Writes the flags related to decaling, if any.
Definition: eggGroup.cxx:426
static DCSType string_dcs_type(const std::string &strval)
Returns the DCSType value associated with the given string representation, or DC_unspecified if the s...
Definition: eggGroup.cxx:844
static BlendOperand string_blend_operand(const std::string &strval)
Returns the BlendOperand value associated with the given string representation, or BO_none if the str...
Definition: eggGroup.cxx:970
A collection of vertices.
Definition: eggVertexPool.h:41
VertexRef::const_iterator vref_end() const
Returns an iterator that can, in conjunction with vref_begin(), be used to traverse the entire set of...
Definition: eggGroup.I:857
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
DepthTestMode get_depth_test_mode() const
Returns the depth_test mode that was set, or DTM_unspecified if nothing was set.
Definition: eggRenderMode.I:55
const LMatrix4d & get_vertex_frame_inv() const
Returns the inverse of the matrix returned by get_vertex_frame().
Definition: eggNode.I:135
This represents the <Transform> entry of a group or texture node: a list of component transform opera...
Definition: eggTransform.h:29
A type of group node that holds related subnodes.
Definition: eggBin.h:26
bool has_transform() const
Returns true if the transform is nonempty, false if it is empty (no transform components have been ad...
Definition: eggTransform.I:143