Panda3D
Loading...
Searching...
No Matches
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.
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,...
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,...
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.
DepthWriteMode get_depth_write_mode() const
Returns the depth_write mode that was set, or DWM_unspecified if nothing was set.
VisibilityMode get_visibility_mode() const
Returns the visibility mode that was set, or VM_unspecified if nothing was set.
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.
This represents the <Transform> entry of a group or texture node: a list of component transform opera...
const LMatrix4d & get_transform3d() const
Returns the overall transform as a 4x4 matrix.
bool has_transform() const
Returns true if the transform is nonempty, false if it is empty (no transform components have been ad...
void clear_transform()
Resets the transform to empty, identity.
void add_matrix4(const LMatrix4d &mat)
Appends an arbitrary 4x4 matrix to the current transform.
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.
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.
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
This is our own Panda specialization on the default STL set.
Definition pset.h:49
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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.
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition indent.cxx:20
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.