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
25using std::ostream;
26using std::string;
27
28
29TypeHandle EggGroup::_type_handle;
30
31/**
32 *
33 */
34EggGroup::
35EggGroup(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 */
52EggGroup::
53EggGroup(const EggGroup &copy) {
54 (*this) = copy;
55}
56
57/**
58 *
59 */
60EggGroup &EggGroup::
61operator = (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 */
112EggGroup::
113~EggGroup() {
115}
116
117/**
118 *
119 */
120void EggGroup::
121set_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 */
145has_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 */
161remove_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 */
177write(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 */
315write_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 */
332write_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 */
371write_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 */
399write_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 */
413write_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 */
426write_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 */
436write_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 */
454write_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 */
468is_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 */
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 */
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 */
608ref_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 */
640unref_vertex(EggVertex *vert) {
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 */
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 */
677get_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 */
692set_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 */
721steal_vrefs(EggGroup *other) {
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 */
739void EggGroup::
740test_vref_integrity() const {
742
743 VertexRef::const_iterator vri;
744 for (vri = vref_begin(); vri != vref_end(); ++vri) {
745 const EggVertex *vert = (*vri).first;
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 */
760add_group_ref(EggGroup *group) {
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 */
769int EggGroup::
770get_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 */
778get_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 */
787remove_group_ref(int n) {
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 */
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 */
807EggGroup::GroupType EggGroup::
808string_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 */
824EggGroup::DartType EggGroup::
825string_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 */
843EggGroup::DCSType EggGroup::
844string_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 */
865EggGroup::BillboardType EggGroup::
866string_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 */
885EggGroup::CollisionSolidType EggGroup::
886string_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 */
917EggGroup::CollideFlags EggGroup::
918string_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 */
945EggGroup::BlendMode EggGroup::
946string_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 */
969EggGroup::BlendOperand EggGroup::
970string_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 */
1019as_transform() {
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 */
1029void EggGroup::
1030write_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;
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 */
1096bool EggGroup::
1097egg_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 */
1108void EggGroup::
1109adjust_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 */
1166void EggGroup::
1167r_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 */
1210void EggGroup::
1211r_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 */
1244void EggGroup::
1245transform_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 */
1258ostream &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 */
1277ostream &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 */
1298ostream &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 */
1321ostream &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 */
1340ostream &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 */
1369ostream &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 */
1414ostream &
1415operator << (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 */
1445ostream &
1446operator << (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}
A type of group node that holds related subnodes.
Definition: eggBin.h:26
A base class for nodes in the hierarchy that are not leaf nodes.
Definition: eggGroupNode.h:46
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.
The main glue of the egg hierarchy, this corresponds to the <Group>, <Instance>, and <Joint> type nod...
Definition: eggGroup.h:34
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
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_draw_order()
Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or some such object at this leve...
Definition: eggGroup.cxx:549
set_billboard_center
Sets the point around which the billboard will rotate, if this node contains a billboard specificatio...
Definition: eggGroup.h:290
void remove_group_ref(int n)
Removes the nth <Ref> entry within this group.
Definition: eggGroup.cxx:787
void unref_vertex(EggVertex *vert)
Removes the vertex from the set of those referenced by the group.
Definition: eggGroup.cxx:640
get_group_ref
Returns the nth <Ref> entry within this group.
Definition: eggGroup.h:354
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
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
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
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
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 add_group_ref(EggGroup *group)
Adds a new <Ref> entry to the group.
Definition: eggGroup.cxx:760
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
void clear_group_refs()
Removes all of the <Ref> entries within this group.
Definition: eggGroup.cxx:796
void unref_all_vertices()
Removes all vertices from the reference list.
Definition: eggGroup.cxx:656
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_bin()
Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or some such object at this leve...
Definition: eggGroup.cxx:563
void steal_vrefs(EggGroup *other)
Moves all of the vertex references from the indicated other group into this one.
Definition: eggGroup.cxx:721
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
virtual bool is_joint() const
Returns true if this particular node represents a <Joint> entry or not.
Definition: eggGroup.cxx:468
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
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
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
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
get_num_group_refs
Returns the number of <Ref> entries within this group.
Definition: eggGroup.h:354
double get_vertex_membership(const EggVertex *vert) const
Returns the amount of membership of the indicated vertex in this group.
Definition: eggGroup.cxx:677
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
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
has_blend_color
Returns true if the blend color has been specified, false otherwise.
Definition: eggGroup.h:318
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
bool is_instance_type() const
Returns true if this group is an instance type node; i.e.
Definition: eggGroup.I:32
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
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
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 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
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 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 CollisionSolidType string_cs_type(const std::string &strval)
Returns the CollisionSolidType value associated with the given string representation,...
Definition: eggGroup.cxx:886
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
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
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 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
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
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
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_bin()
Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or some such object at this leve...
Definition: eggNode.cxx:174
const LMatrix4d & get_vertex_frame_inv() const
Returns the inverse of the matrix returned by get_vertex_frame().
Definition: eggNode.I:135
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
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
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
const LMatrix4d & get_node_frame() const
Returns the coordinate frame of the node itself.
Definition: eggNode.I:122
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
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
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
bool is_local_coord() const
Returns true if this node's vertices are not in the global coordinate space.
Definition: eggNode.I:87
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
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_draw_order()
Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or some such object at this leve...
Definition: eggNode.cxx:160
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
This class stores miscellaneous rendering properties that is associated with geometry,...
Definition: eggRenderMode.h:31
bool has_bin() const
Returns true if a bin name has been set for this particular object.
void write(std::ostream &out, int indent_level) const
Writes the attributes to the indicated output stream in Egg format.
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
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
VisibilityMode get_visibility_mode() const
Returns the visibility mode that was set, or VM_unspecified if nothing was set.
Definition: eggRenderMode.I:75
bool has_draw_order() const
Returns true if the draw-order flag has been set for this particular object.
bool has_depth_offset() const
Returns true if the depth-offset flag has been set for this particular object.
AlphaMode get_alpha_mode() const
Returns the alpha mode that was set, or AM_unspecified if nothing was set.
Definition: eggRenderMode.I:98
This represents the <Transform> entry of a group or texture node: a list of component transform opera...
Definition: eggTransform.h:29
const LMatrix4d & get_transform3d() const
Returns the overall transform as a 4x4 matrix.
Definition: eggTransform.I:212
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
void clear_transform()
Resets the transform to empty, identity.
Definition: eggTransform.I:114
void add_matrix4(const LMatrix4d &mat)
Appends an arbitrary 4x4 matrix to the current transform.
Definition: eggTransform.I:132
void write(std::ostream &out, int indent_level, const std::string &label) const
Writes the transform to the indicated stream in Egg format.
A collection of vertices.
Definition: eggVertexPool.h:41
Any one-, two-, three-, or four-component vertex, possibly with attributes such as a normal.
Definition: eggVertex.h:39
bool has_gref(const EggGroup *group) const
Returns true if the indicated group references this vertex, false otherwise.
Definition: eggVertex.cxx:733
int get_index() const
Returns the index number of the vertex within its pool.
Definition: eggVertex.I:277
EggVertexPool * get_pool() const
Returns the vertex pool this vertex belongs in.
Definition: eggVertex.I:19
bool test_ref_count_integrity() const
Does some easy checks to make sure that the reference count isn't completely bogus.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition: typedObject.I:28
This is our own Panda specialization on the default STL map.
Definition: pmap.h:49
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition: dcindent.cxx:22
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.