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