Panda3D

eggGroup.cxx

00001 // Filename: eggGroup.cxx
00002 // Created by:  drose (16Jan99)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "eggGroup.h"
00016 #include "eggMiscFuncs.h"
00017 #include "eggVertexPool.h"
00018 #include "eggBin.h"
00019 #include "lexerDefs.h"
00020 
00021 #include "indent.h"
00022 #include "string_utils.h"
00023 #include "lmatrix.h"
00024 #include "dcast.h"
00025 
00026 
00027 TypeHandle EggGroup::_type_handle;
00028 
00029 ////////////////////////////////////////////////////////////////////
00030 //     Function: EggGroup::Constructor
00031 //       Access: Published
00032 //  Description:
00033 ////////////////////////////////////////////////////////////////////
00034 EggGroup::
00035 EggGroup(const string &name) : EggGroupNode(name) {
00036   _flags = 0;
00037   _flags2 = 0;
00038   _fps = 0.0;
00039   _blend_mode = BM_unspecified;
00040   _blend_operand_a = BO_unspecified;
00041   _blend_operand_b = BO_unspecified;
00042   _blend_color = Colorf::zero();
00043   _u_speed = 0;
00044   _v_speed = 0;
00045   _r_speed = 0;
00046 }
00047 
00048 ////////////////////////////////////////////////////////////////////
00049 //     Function: EggGroup::Copy Constructor
00050 //       Access: Published
00051 //  Description:
00052 ////////////////////////////////////////////////////////////////////
00053 EggGroup::
00054 EggGroup(const EggGroup &copy) {
00055   (*this) = copy;
00056 }
00057 
00058 ////////////////////////////////////////////////////////////////////
00059 //     Function: EggGroup::Copy assignment operator
00060 //       Access: Published
00061 //  Description:
00062 ////////////////////////////////////////////////////////////////////
00063 EggGroup &EggGroup::
00064 operator = (const EggGroup &copy) {
00065   EggTransform::operator = (copy);
00066   _flags = copy._flags;
00067   _flags2 = copy._flags2;
00068   _collide_mask = copy._collide_mask;
00069   _from_collide_mask = copy._from_collide_mask;
00070   _into_collide_mask = copy._into_collide_mask;
00071   _billboard_center = copy._billboard_center;
00072   _object_types = copy._object_types;
00073   _collision_name = copy._collision_name;
00074   _fps = copy._fps;
00075   _lod = copy._lod;
00076   _blend_mode = copy._blend_mode;
00077   _blend_operand_a = copy._blend_operand_a;
00078   _blend_operand_b = copy._blend_operand_b;
00079   _blend_color = copy._blend_color;
00080   _tag_data = copy._tag_data;
00081   _u_speed = copy._u_speed;
00082   _v_speed = copy._v_speed;
00083   _r_speed = copy._r_speed;
00084   _default_pose = copy._default_pose;
00085 
00086   unref_all_vertices();
00087   _vref = copy._vref;
00088 
00089   // We must walk through the vertex ref list, and flag each vertex as
00090   // now reffed by this group.
00091   VertexRef::iterator vri;
00092   for (vri = _vref.begin(); vri != _vref.end(); ++vri) {
00093     EggVertex *vert = (*vri).first;
00094 
00095     bool inserted = vert->_gref.insert(this).second;
00096     // Did the group not exist previously in the vertex's gref list?
00097     // If it was there already, we must be out of sync between
00098     // vertices and groups.
00099     nassertr(inserted, *this);
00100   }
00101 
00102   // These must be down here, because the EggNode assignment operator
00103   // will force an update_under().  Therefore, we can't call it until
00104   // all the attributes that affect adjust_under() are in place.
00105   EggGroupNode::operator = (copy);
00106   EggRenderMode::operator = (copy);
00107 
00108   return *this;
00109 }
00110 
00111 
00112 ////////////////////////////////////////////////////////////////////
00113 //     Function: EggGroup::Destructor
00114 //       Access: Published
00115 //  Description:
00116 ////////////////////////////////////////////////////////////////////
00117 EggGroup::
00118 ~EggGroup() {
00119   unref_all_vertices();
00120 }
00121 
00122 ////////////////////////////////////////////////////////////////////
00123 //     Function: EggGroup::set_group_type
00124 //       Access: Published
00125 //  Description:
00126 ////////////////////////////////////////////////////////////////////
00127 void EggGroup::
00128 set_group_type(GroupType type) {
00129   if (type != get_group_type()) {
00130 #ifndef NDEBUG
00131     if (type != GT_instance) {
00132       // Only valid to change to a non-instance type if we have no
00133       // group refs.
00134       nassertv(_group_refs.empty());
00135     }
00136 #endif 
00137 
00138     // Make sure the user didn't give us any stray bits.
00139     nassertv((type & ~F_group_type)==0);
00140     _flags = (_flags & ~F_group_type) | type;
00141 
00142     // Now we might have changed the type to or from an instance node,
00143     // so we have to recompute the under_flags.
00144     update_under(0);
00145   }
00146 }
00147 
00148 ////////////////////////////////////////////////////////////////////
00149 //     Function: EggGroup::has_object_type
00150 //       Access: Published
00151 //  Description: Returns true if the indicated object type has been
00152 //               added to the group, or false otherwise.
00153 ////////////////////////////////////////////////////////////////////
00154 bool EggGroup::
00155 has_object_type(const string &object_type) const {
00156   vector_string::const_iterator oi;
00157   for (oi = _object_types.begin(); oi != _object_types.end(); ++oi) {
00158     if (cmp_nocase_uh((*oi), object_type) == 0) {
00159       return true;
00160     }
00161   }
00162   return false;
00163 }
00164 
00165 ////////////////////////////////////////////////////////////////////
00166 //     Function: EggGroup::remove_object_type
00167 //       Access: Published
00168 //  Description: Removes the first instance of the indicated object
00169 //               type from the group if it is present.  Returns true
00170 //               if the object type was found and removed, false
00171 //               otherwise.
00172 ////////////////////////////////////////////////////////////////////
00173 bool EggGroup::
00174 remove_object_type(const string &object_type) {
00175   vector_string::iterator oi;
00176   for (oi = _object_types.begin(); oi != _object_types.end(); ++oi) {
00177     if (cmp_nocase_uh((*oi), object_type) == 0) {
00178       _object_types.erase(oi);
00179       return true;
00180     }
00181   }
00182   return false;
00183 }
00184 
00185 ////////////////////////////////////////////////////////////////////
00186 //     Function: EggGroup::write
00187 //       Access: Published, Virtual
00188 //  Description: Writes the group and all of its children to the
00189 //               indicated output stream in Egg format.
00190 ////////////////////////////////////////////////////////////////////
00191 void EggGroup::
00192 write(ostream &out, int indent_level) const {
00193   test_under_integrity();
00194 
00195   switch (get_group_type()) {
00196   case GT_group:
00197     write_header(out, indent_level, "<Group>");
00198     break;
00199 
00200   case GT_instance:
00201     write_header(out, indent_level, "<Instance>");
00202     break;
00203 
00204   case GT_joint:
00205     write_header(out, indent_level, "<Joint>");
00206     break;
00207 
00208   default:
00209     // invalid group type
00210     nassertv(false);
00211   }
00212 
00213   if (is_of_type(EggBin::get_class_type())) {
00214     indent(out, indent_level + 2)
00215       << "// Bin " << DCAST(EggBin, this)->get_bin_number() << "\n";
00216   }
00217 
00218   if (has_lod()) {
00219     get_lod().write(out, indent_level + 2);
00220   }
00221 
00222   write_billboard_flags(out, indent_level + 2);
00223   write_collide_flags(out, indent_level + 2);
00224   write_model_flags(out, indent_level + 2);
00225   write_switch_flags(out, indent_level + 2);
00226 
00227   if (has_transform()) {
00228     EggTransform::write(out, indent_level + 2, "<Transform>");
00229   }
00230 
00231   if (get_group_type() == GT_joint && _default_pose.has_transform()) {
00232     _default_pose.write(out, indent_level + 2, "<DefaultPose>");
00233   }
00234 
00235   if(get_scroll_u() != 0) {
00236     indent(out, indent_level) 
00237       << "<Scalar> scroll_u { " << get_scroll_u() << " }\n";
00238 
00239   }
00240 
00241   if(get_scroll_v() != 0) {
00242     indent(out, indent_level) 
00243       << "<Scalar> scroll_v { " << get_scroll_v() << " }\n";
00244 
00245   }
00246 
00247   if(get_scroll_r() != 0) {
00248     indent(out, indent_level) 
00249       << "<Scalar> scroll_r { " << get_scroll_r() << " }\n";
00250 
00251   }
00252 
00253 
00254   write_object_types(out, indent_level + 2);
00255   write_decal_flags(out, indent_level + 2);
00256   write_tags(out, indent_level + 2);
00257   write_render_mode(out, indent_level + 2);
00258 
00259   if (get_portal_flag()) {
00260     indent(out, indent_level) << "<Scalar> portal { 1 }\n";
00261   }
00262 
00263   if (get_polylight_flag()) {
00264     indent(out, indent_level) << "<Scalar> polylight { 1 }\n";
00265   }
00266 
00267   if (has_indexed_flag()) {
00268     indent(out, indent_level) 
00269       << "<Scalar> indexed { " << get_indexed_flag() << " }\n";
00270   }
00271 
00272   if (get_blend_mode() != BM_unspecified) {
00273     indent(out, indent_level)
00274       << "<Scalar> blend { " << get_blend_mode() << " }\n";
00275   }
00276 
00277   if (get_blend_operand_a() != BO_unspecified) {
00278     indent(out, indent_level)
00279       << "<Scalar> blendop-a { " << get_blend_operand_a() << " }\n";
00280   }
00281 
00282   if (get_blend_operand_b() != BO_unspecified) {
00283     indent(out, indent_level)
00284       << "<Scalar> blendop-b { " << get_blend_operand_b() << " }\n";
00285   }
00286 
00287   if (has_blend_color()) {
00288     const Colorf &c = get_blend_color();
00289     indent(out, indent_level)
00290       << "<Scalar> blendr { " << c[0] << " }\n";
00291     indent(out, indent_level)
00292       << "<Scalar> blendg { " << c[1] << " }\n";
00293     indent(out, indent_level)
00294       << "<Scalar> blendb { " << c[2] << " }\n";
00295     indent(out, indent_level)
00296       << "<Scalar> blenda { " << c[3] << " }\n";
00297   }
00298 
00299   GroupRefs::const_iterator gri;
00300   for (gri = _group_refs.begin(); gri != _group_refs.end(); ++gri) {
00301     EggGroup *group_ref = (*gri);
00302     indent(out, indent_level + 2)
00303       << "<Ref> { " << group_ref->get_name() << " }\n";
00304   }
00305 
00306   // We have to write the children nodes before we write the vertex
00307   // references, since we might be referencing a vertex that's defined
00308   // in one of those children nodes!
00309   EggGroupNode::write(out, indent_level + 2);
00310   write_vertex_ref(out, indent_level + 2);
00311 
00312   indent(out, indent_level) << "}\n";
00313 }
00314 
00315 ////////////////////////////////////////////////////////////////////
00316 //     Function: EggGroup::write_billboard_flags
00317 //       Access: Published
00318 //  Description: Writes just the <Billboard> entry and related fields to
00319 //               the indicated ostream.
00320 ////////////////////////////////////////////////////////////////////
00321 void EggGroup::
00322 write_billboard_flags(ostream &out, int indent_level) const {
00323   if (get_billboard_type() != BT_none) {
00324     indent(out, indent_level)
00325       << "<Billboard> { " << get_billboard_type() << " }\n";
00326   }
00327 
00328   if (has_billboard_center()) {
00329     indent(out, indent_level)
00330       << "<BillboardCenter> { " << get_billboard_center() << " }\n";
00331   }
00332 }
00333 
00334 ////////////////////////////////////////////////////////////////////
00335 //     Function: EggGroup::write_collide_flags
00336 //       Access: Published
00337 //  Description: Writes just the <Collide> entry and related fields to
00338 //               the indicated ostream.
00339 ////////////////////////////////////////////////////////////////////
00340 void EggGroup::
00341 write_collide_flags(ostream &out, int indent_level) const {
00342   if (get_cs_type() != CST_none) {
00343     indent(out, indent_level) << "<Collide> ";
00344     if (has_collision_name()) {
00345       enquote_string(out, get_collision_name()) << " ";
00346     }
00347     out << "{ " << get_cs_type();
00348     if (get_collide_flags() != CF_none) {
00349       out << " " << get_collide_flags();
00350     }
00351     out << " }\n";
00352   }
00353 
00354   if (has_collide_mask()) {
00355     indent(out, indent_level)
00356       << "<Scalar> collide-mask { 0x";
00357     get_collide_mask().output_hex(out, 0);
00358     out << " }\n";
00359   }
00360 
00361   if (has_from_collide_mask()) {
00362     indent(out, indent_level)
00363       << "<Scalar> from-collide-mask { 0x";
00364     get_from_collide_mask().output_hex(out, 0);
00365     out << " }\n";
00366   }
00367 
00368   if (has_into_collide_mask()) {
00369     indent(out, indent_level)
00370       << "<Scalar> into-collide-mask { 0x";
00371     get_into_collide_mask().output_hex(out, 0);
00372     out << " }\n";
00373   }
00374 }
00375 
00376 ////////////////////////////////////////////////////////////////////
00377 //     Function: EggGroup::write_model_flags
00378 //       Access: Published
00379 //  Description: Writes the <Model> flag and related flags to the
00380 //               indicated ostream.
00381 ////////////////////////////////////////////////////////////////////
00382 void EggGroup::
00383 write_model_flags(ostream &out, int indent_level) const {
00384   if (get_dcs_type() != DC_unspecified) {
00385     indent(out, indent_level) 
00386       << "<DCS> { " << get_dcs_type() << " }\n";
00387   }
00388 
00389   if (get_dart_type() != DT_none) {
00390     indent(out, indent_level)
00391       << "<Dart> { " << get_dart_type() << " }\n";
00392   }
00393 
00394   if (get_model_flag()) {
00395     indent(out, indent_level) << "<Model> { 1 }\n";
00396   }
00397 
00398   if (get_texlist_flag()) {
00399     indent(out, indent_level) << "<TexList> { 1 }\n";
00400   }
00401 
00402   if (get_direct_flag()) {
00403     indent(out, indent_level) << "<Scalar> direct { 1 }\n";
00404   }
00405 }
00406 
00407 ////////////////////////////////////////////////////////////////////
00408 //     Function: EggGroup::write_switch_flags
00409 //       Access: Published
00410 //  Description: Writes the <Switch> flag and related flags to the
00411 //               indicated ostream.
00412 ////////////////////////////////////////////////////////////////////
00413 void EggGroup::
00414 write_switch_flags(ostream &out, int indent_level) const {
00415   if (get_switch_flag()) {
00416     indent(out, indent_level) << "<Switch> { 1 }\n";
00417     if (get_switch_fps() != 0.0) {
00418       indent(out, indent_level)
00419         << "<Scalar> fps { " << get_switch_fps() << " }\n";
00420     }
00421   }
00422 }
00423 
00424 ////////////////////////////////////////////////////////////////////
00425 //     Function: EggGroup::write_object_types
00426 //       Access: Published
00427 //  Description: Writes just the <ObjectTypes> entries, if any, to the
00428 //               indicated ostream.
00429 ////////////////////////////////////////////////////////////////////
00430 void EggGroup::
00431 write_object_types(ostream &out, int indent_level) const {
00432   vector_string::const_iterator oi;
00433   for (oi = _object_types.begin(); oi != _object_types.end(); ++oi) {
00434     indent(out, indent_level)
00435       << "<ObjectType> { ";
00436     enquote_string(out, (*oi)) << " }\n";
00437   }
00438 }
00439 
00440 ////////////////////////////////////////////////////////////////////
00441 //     Function: EggGroup::write_decal_flags
00442 //       Access: Published
00443 //  Description: Writes the flags related to decaling, if any.
00444 ////////////////////////////////////////////////////////////////////
00445 void EggGroup::
00446 write_decal_flags(ostream &out, int indent_level) const {
00447   if (get_decal_flag()) {
00448     indent(out, indent_level) << "<Scalar> decal { 1 }\n";
00449   }
00450 }
00451 
00452 ////////////////////////////////////////////////////////////////////
00453 //     Function: EggGroup::write_tags
00454 //       Access: Published
00455 //  Description: Writes just the <Tag> entries, if any, to the
00456 //               indicated ostream.
00457 ////////////////////////////////////////////////////////////////////
00458 void EggGroup::
00459 write_tags(ostream &out, int indent_level) const {
00460   TagData::const_iterator ti;
00461   for (ti = _tag_data.begin(); ti != _tag_data.end(); ++ti) {
00462     const string &key = (*ti).first;
00463     const string &value = (*ti).second;
00464 
00465     indent(out, indent_level) << "<Tag> ";
00466     enquote_string(out, key) << " {\n";
00467     enquote_string(out, value, indent_level + 2) << "\n";
00468     indent(out, indent_level) << "}\n";
00469   }
00470 }
00471 
00472 ////////////////////////////////////////////////////////////////////
00473 //     Function: EggGroup::write_render_mode
00474 //       Access: Published
00475 //  Description: Writes the flags inherited from EggRenderMode and
00476 //               similar flags that control obscure render effects.
00477 ////////////////////////////////////////////////////////////////////
00478 void EggGroup::
00479 write_render_mode(ostream &out, int indent_level) const {
00480   EggRenderMode::write(out, indent_level);
00481 
00482   if (get_nofog_flag()) {
00483     indent(out, indent_level) << "<Scalar> no-fog { 1 }\n";
00484   }
00485 }
00486 
00487 ////////////////////////////////////////////////////////////////////
00488 //     Function: EggGroup::is_joint
00489 //       Access: Published, Virtual
00490 //  Description: Returns true if this particular node represents a
00491 //               <Joint> entry or not.  This is a handy thing to know
00492 //               since Joints are sorted to the end of their sibling
00493 //               list when writing an egg file.  See
00494 //               EggGroupNode::write().
00495 ////////////////////////////////////////////////////////////////////
00496 bool EggGroup::
00497 is_joint() const {
00498   return (get_group_type() == GT_joint);
00499 }
00500 
00501 ////////////////////////////////////////////////////////////////////
00502 //     Function: EggGroup::determine_alpha_mode
00503 //       Access: Published, Virtual
00504 //  Description: Walks back up the hierarchy, looking for an EggGroup
00505 //               or EggPrimitive or some such object at this level or
00506 //               above this group that has an alpha_mode other than
00507 //               AM_unspecified.  Returns a valid EggRenderMode pointer
00508 //               if one is found, or NULL otherwise.
00509 ////////////////////////////////////////////////////////////////////
00510 EggRenderMode *EggGroup::
00511 determine_alpha_mode() {
00512   if (get_alpha_mode() != AM_unspecified) {
00513     return this;
00514   }
00515   return EggGroupNode::determine_alpha_mode();
00516 }
00517 
00518 ////////////////////////////////////////////////////////////////////
00519 //     Function: EggGroup::determine_depth_write_mode
00520 //       Access: Published, Virtual
00521 //  Description: Walks back up the hierarchy, looking for an EggGroup
00522 //               or EggPrimitive or some such object at this level or
00523 //               above this group that has a depth_write_mode other
00524 //               than DWM_unspecified.  Returns a valid EggRenderMode
00525 //               pointer if one is found, or NULL otherwise.
00526 ////////////////////////////////////////////////////////////////////
00527 EggRenderMode *EggGroup::
00528 determine_depth_write_mode() {
00529   if (get_depth_write_mode() != DWM_unspecified) {
00530     return this;
00531   }
00532   return EggGroupNode::determine_depth_write_mode();
00533 }
00534 
00535 ////////////////////////////////////////////////////////////////////
00536 //     Function: EggGroup::determine_depth_test_mode
00537 //       Access: Published, Virtual
00538 //  Description: Walks back up the hierarchy, looking for an EggGroup
00539 //               or EggPrimitive or some such object at this level or
00540 //               above this group that has a depth_test_mode other
00541 //               than DTM_unspecified.  Returns a valid EggRenderMode
00542 //               pointer if one is found, or NULL otherwise.
00543 ////////////////////////////////////////////////////////////////////
00544 EggRenderMode *EggGroup::
00545 determine_depth_test_mode() {
00546   if (get_depth_test_mode() != DTM_unspecified) {
00547     return this;
00548   }
00549   return EggGroupNode::determine_depth_test_mode();
00550 }
00551 
00552 ////////////////////////////////////////////////////////////////////
00553 //     Function: EggGroup::determine_visibility_mode
00554 //       Access: Published, Virtual
00555 //  Description: Walks back up the hierarchy, looking for an EggGroup
00556 //               or EggPrimitive or some such object at this level or
00557 //               above this group that has a visibility_mode other
00558 //               than VM_unspecified.  Returns a valid EggRenderMode
00559 //               pointer if one is found, or NULL otherwise.
00560 ////////////////////////////////////////////////////////////////////
00561 EggRenderMode *EggGroup::
00562 determine_visibility_mode() {
00563   if (get_visibility_mode() != VM_unspecified) {
00564     return this;
00565   }
00566   return EggGroupNode::determine_visibility_mode();
00567 }
00568 
00569 ////////////////////////////////////////////////////////////////////
00570 //     Function: EggGroup::determine_depth_offset
00571 //       Access: Published, Virtual
00572 //  Description: Walks back up the hierarchy, looking for an EggGroup
00573 //               or EggPrimitive or some such object at this level or
00574 //               above this group that has a depth_offset specified.
00575 //               Returns a valid EggRenderMode pointer if one is found,
00576 //               or NULL otherwise.
00577 ////////////////////////////////////////////////////////////////////
00578 EggRenderMode *EggGroup::
00579 determine_depth_offset() {
00580   if (has_depth_offset()) {
00581     return this;
00582   }
00583   return EggGroupNode::determine_depth_offset();
00584 }
00585 
00586 ////////////////////////////////////////////////////////////////////
00587 //     Function: EggGroup::determine_draw_order
00588 //       Access: Published, Virtual
00589 //  Description: Walks back up the hierarchy, looking for an EggGroup
00590 //               or EggPrimitive or some such object at this level or
00591 //               above this group that has a draw_order specified.
00592 //               Returns a valid EggRenderMode pointer if one is found,
00593 //               or NULL otherwise.
00594 ////////////////////////////////////////////////////////////////////
00595 EggRenderMode *EggGroup::
00596 determine_draw_order() {
00597   if (has_draw_order()) {
00598     return this;
00599   }
00600   return EggGroupNode::determine_draw_order();
00601 }
00602 
00603 ////////////////////////////////////////////////////////////////////
00604 //     Function: EggGroup::determine_bin
00605 //       Access: Published, Virtual
00606 //  Description: Walks back up the hierarchy, looking for an EggGroup
00607 //               or EggPrimitive or some such object at this level or
00608 //               above this group that has a bin specified.  Returns a
00609 //               valid EggRenderMode pointer if one is found, or NULL
00610 //               otherwise.
00611 ////////////////////////////////////////////////////////////////////
00612 EggRenderMode *EggGroup::
00613 determine_bin() {
00614   if (has_bin()) {
00615     return this;
00616   }
00617   return EggGroupNode::determine_bin();
00618 }
00619 
00620 ////////////////////////////////////////////////////////////////////
00621 //     Function: EggGroup::determine_indexed
00622 //       Access: Published, Virtual
00623 //  Description: Walks back up the hierarchy, looking for an EggGroup
00624 //               at this level or above that has the "indexed" scalar
00625 //               set.  Returns the value of the indexed scalar if it
00626 //               is found, or false if it is not.
00627 //
00628 //               In other words, returns true if the "indexed" flag is
00629 //               in effect for the indicated node, false otherwise.
00630 ////////////////////////////////////////////////////////////////////
00631 bool EggGroup::
00632 determine_indexed() {
00633   if (has_indexed_flag()) {
00634     return get_indexed_flag();
00635   }
00636   return EggGroupNode::determine_indexed();
00637 }
00638 
00639 ////////////////////////////////////////////////////////////////////
00640 //     Function: EggGroup::determine_decal
00641 //       Access: Published, Virtual
00642 //  Description: Walks back up the hierarchy, looking for an EggGroup
00643 //               at this level or above that has the "decal" flag
00644 //               set.  Returns the value of the decal flag if it
00645 //               is found, or false if it is not.
00646 //
00647 //               In other words, returns true if the "decal" flag is
00648 //               in effect for the indicated node, false otherwise.
00649 ////////////////////////////////////////////////////////////////////
00650 bool EggGroup::
00651 determine_decal() {
00652   if (get_decal_flag()) {
00653     return true;
00654   }
00655   return EggGroupNode::determine_decal();
00656 }
00657 
00658 ////////////////////////////////////////////////////////////////////
00659 //     Function: EggGroup::ref_vertex
00660 //       Access: Published
00661 //  Description: Adds the vertex to the set of those referenced by the
00662 //               group, at the indicated membership level.  If the
00663 //               vertex is already being referenced, increases the
00664 //               membership amount by the indicated amount.
00665 ////////////////////////////////////////////////////////////////////
00666 void EggGroup::
00667 ref_vertex(EggVertex *vert, double membership) {
00668   VertexRef::iterator vri = _vref.find(vert);
00669 
00670   if (vri != _vref.end()) {
00671     // The vertex was already being reffed; increment its membership
00672     // amount.
00673     (*vri).second += membership;
00674 
00675     // If that takes us down to zero, go ahead and unref the vertex.
00676     if ((*vri).second == 0.0) {
00677       unref_vertex(vert);
00678     }
00679 
00680   } else {
00681     // The vertex was not already reffed; ref it.
00682     if (membership != 0.0) {
00683       _vref[vert] = membership;
00684 
00685       bool inserted = vert->_gref.insert(this).second;
00686       // Did the group not exist previously in the vertex's gref list?
00687       // If it was there already, we must be out of sync between
00688       // vertices and groups.
00689       nassertv(inserted);
00690     }
00691   }
00692 }
00693 
00694 
00695 ////////////////////////////////////////////////////////////////////
00696 //     Function: EggGroup::unref_vertex
00697 //       Access: Published
00698 //  Description: Removes the vertex from the set of those referenced
00699 //               by the group.  Does nothing if the vertex is not
00700 //               already reffed.
00701 ////////////////////////////////////////////////////////////////////
00702 void EggGroup::
00703 unref_vertex(EggVertex *vert) {
00704   VertexRef::iterator vri = _vref.find(vert);
00705 
00706   if (vri != _vref.end()) {
00707     _vref.erase(vri);
00708     int count = vert->_gref.erase(this);
00709     // Did the group exist in the vertex's gref list?  If it didn't,
00710     // we must be out of sync between vertices and groups.
00711     nassertv(count == 1);
00712   }
00713 }
00714 
00715 ////////////////////////////////////////////////////////////////////
00716 //     Function: EggGroup::unref_all_vertices
00717 //       Access: Published
00718 //  Description: Removes all vertices from the reference list.
00719 ////////////////////////////////////////////////////////////////////
00720 void EggGroup::
00721 unref_all_vertices() {
00722   // We must walk through the vertex ref list, and flag each vertex as
00723   // unreffed in its own structure.
00724   VertexRef::iterator vri;
00725   for (vri = _vref.begin(); vri != _vref.end(); ++vri) {
00726     EggVertex *vert = (*vri).first;
00727     int count = vert->_gref.erase(this);
00728     // Did the group exist in the vertex's gref list?  If it didn't,
00729     // we must be out of sync between vertices and groups.
00730     nassertv(count == 1);
00731   }
00732 
00733   _vref.clear();
00734 }
00735 
00736 
00737 ////////////////////////////////////////////////////////////////////
00738 //     Function: EggGroup::get_vertex_membership
00739 //       Access: Published
00740 //  Description: Returns the amount of membership of the indicated
00741 //               vertex in this group.  If the vertex is not reffed by
00742 //               the group, returns 0.
00743 ////////////////////////////////////////////////////////////////////
00744 double EggGroup::
00745 get_vertex_membership(const EggVertex *vert) const {
00746   VertexRef::const_iterator vri = _vref.find((EggVertex *)vert);
00747 
00748   if (vri != _vref.end()) {
00749     return (*vri).second;
00750   } else {
00751     return 0.0;
00752   }
00753 }
00754 
00755 ////////////////////////////////////////////////////////////////////
00756 //     Function: EggGroup::set_vertex_membership
00757 //       Access: Published
00758 //  Description: Explicitly sets the net membership of the indicated
00759 //               vertex in this group to the given value.
00760 ////////////////////////////////////////////////////////////////////
00761 void EggGroup::
00762 set_vertex_membership(EggVertex *vert, double membership) {
00763   if (membership == 0.0) {
00764     unref_vertex(vert);
00765     return;
00766   }
00767 
00768   VertexRef::iterator vri = _vref.find(vert);
00769 
00770   if (vri != _vref.end()) {
00771     // The vertex was already being reffed; just change its membership
00772     // amount.
00773     (*vri).second = membership;
00774 
00775   } else {
00776     // The vertex was not already reffed; ref it.
00777     _vref[vert] = membership;
00778 
00779     bool inserted = vert->_gref.insert(this).second;
00780     // Did the group not exist previously in the vertex's gref list?
00781     // If it was there already, we must be out of sync between
00782     // vertices and groups.
00783     nassertv(inserted);
00784   }
00785 }
00786 
00787 ////////////////////////////////////////////////////////////////////
00788 //     Function: EggGroup::steal_vrefs
00789 //       Access: Published
00790 //  Description: Moves all of the vertex references from the indicated
00791 //               other group into this one.  If a given vertex was
00792 //               previously shared by both groups, the relative
00793 //               memberships will be summed.
00794 ////////////////////////////////////////////////////////////////////
00795 void EggGroup::
00796 steal_vrefs(EggGroup *other) {
00797   nassertv(other != this);
00798   VertexRef::const_iterator vri;
00799   for (vri = other->vref_begin(); vri != other->vref_end(); ++vri) {
00800     EggVertex *vert = (*vri).first;
00801     double membership = (*vri).second;
00802     ref_vertex(vert, membership);
00803   }
00804   other->unref_all_vertices();
00805 }
00806 
00807 
00808 #ifndef NDEBUG
00809 
00810 ////////////////////////////////////////////////////////////////////
00811 //     Function: EggGroup::test_vref_integrity
00812 //       Access: Published
00813 //  Description: Verifies that each vertex in the group exists and
00814 //               that it knows it is referenced by the group.
00815 ////////////////////////////////////////////////////////////////////
00816 void EggGroup::
00817 test_vref_integrity() const {
00818   test_ref_count_integrity();
00819 
00820   VertexRef::const_iterator vri;
00821   for (vri = vref_begin(); vri != vref_end(); ++vri) {
00822     const EggVertex *vert = (*vri).first;
00823     vert->test_ref_count_integrity();
00824 
00825     nassertv(vert->has_gref(this));
00826   }
00827 }
00828 
00829 #endif  // NDEBUG
00830 
00831 ////////////////////////////////////////////////////////////////////
00832 //     Function: EggGroup::add_group_ref
00833 //       Access: Published
00834 //  Description: Adds a new <Ref> entry to the group.  This declares
00835 //               an internal reference to another node, and is used to
00836 //               implement scene-graph instancing; it is only valid if
00837 //               the group_type is GT_instance.
00838 ////////////////////////////////////////////////////////////////////
00839 void EggGroup::
00840 add_group_ref(EggGroup *group) {
00841   nassertv(get_group_type() == GT_instance);
00842   _group_refs.push_back(group);
00843 }
00844 
00845 ////////////////////////////////////////////////////////////////////
00846 //     Function: EggGroup::get_num_group_refs
00847 //       Access: Published
00848 //  Description: Returns the number of <Ref> entries within this
00849 //               group.  See add_group_ref().
00850 ////////////////////////////////////////////////////////////////////
00851 int EggGroup::
00852 get_num_group_refs() const {
00853   return _group_refs.size();
00854 }
00855 
00856 ////////////////////////////////////////////////////////////////////
00857 //     Function: EggGroup::get_group_ref
00858 //       Access: Published
00859 //  Description: Returns the nth <Ref> entry within this group.  See
00860 //               add_group_ref().
00861 ////////////////////////////////////////////////////////////////////
00862 EggGroup *EggGroup::
00863 get_group_ref(int n) const {
00864   nassertr(n >= 0 && n < (int)_group_refs.size(), NULL);
00865   return _group_refs[n];
00866 }
00867 
00868 ////////////////////////////////////////////////////////////////////
00869 //     Function: EggGroup::remove_group_ref
00870 //       Access: Published
00871 //  Description: Removes the nth <Ref> entry within this group.  See
00872 //               add_group_ref().
00873 ////////////////////////////////////////////////////////////////////
00874 void EggGroup::
00875 remove_group_ref(int n) {
00876   nassertv(n >= 0 && n < (int)_group_refs.size());
00877   _group_refs.erase(_group_refs.begin() + n);
00878 }
00879 
00880 ////////////////////////////////////////////////////////////////////
00881 //     Function: EggGroup::clear_group_refs
00882 //       Access: Published
00883 //  Description: Removes all of the <Ref> entries within this group.
00884 //               See add_group_ref().
00885 ////////////////////////////////////////////////////////////////////
00886 void EggGroup::
00887 clear_group_refs() {
00888   _group_refs.clear();
00889 }
00890 
00891 
00892 
00893 ////////////////////////////////////////////////////////////////////
00894 //     Function: EggGroup::string_group_type
00895 //       Access: Published, Static
00896 //  Description: Returns the GroupType value associated with the given
00897 //               string representation, or GT_invalid if the string
00898 //               does not match any known GroupType value.
00899 ////////////////////////////////////////////////////////////////////
00900 EggGroup::GroupType EggGroup::
00901 string_group_type(const string &strval) {
00902   if (cmp_nocase_uh(strval, "group") == 0) {
00903     return GT_group;
00904   } else if (cmp_nocase_uh(strval, "instance") == 0) {
00905     return GT_instance;
00906   } else if (cmp_nocase_uh(strval, "joint") == 0) {
00907     return GT_joint;
00908   } else {
00909     return GT_invalid;
00910   }
00911 }
00912 
00913 ////////////////////////////////////////////////////////////////////
00914 //     Function: EggGroup::string_dart_type
00915 //       Access: Published, Static
00916 //  Description: Returns the DartType value associated with the given
00917 //               string representation, or DT_none if the string
00918 //               does not match any known DartType value.
00919 ////////////////////////////////////////////////////////////////////
00920 EggGroup::DartType EggGroup::
00921 string_dart_type(const string &strval) {
00922   if (cmp_nocase_uh(strval, "sync") == 0) {
00923     return DT_sync;
00924   } else if (cmp_nocase_uh(strval, "nosync") == 0) {
00925     return DT_nosync;
00926   } else if (cmp_nocase_uh(strval, "default") == 0) {
00927     return DT_default;
00928   } else if (cmp_nocase_uh(strval, "structured") == 0) {
00929     return DT_structured;
00930   } else {
00931     return DT_none;
00932   }
00933 }
00934 
00935 ////////////////////////////////////////////////////////////////////
00936 //     Function: EggGroup::string_dcs_type
00937 //       Access: Published, Static
00938 //  Description: Returns the DCSType value associated with the given
00939 //               string representation, or DC_unspecified if the
00940 //               string does not match any known DCSType value.
00941 ////////////////////////////////////////////////////////////////////
00942 EggGroup::DCSType EggGroup::
00943 string_dcs_type(const string &strval) {
00944   if (cmp_nocase_uh(strval, "none") == 0) {
00945     return DC_none;
00946   } else if (cmp_nocase_uh(strval, "local") == 0) {
00947     return DC_local;
00948   } else if (cmp_nocase_uh(strval, "net") == 0) {
00949     return DC_net;
00950   } else if (cmp_nocase_uh(strval, "no_touch") == 0) {
00951     return DC_no_touch;
00952   } else if (cmp_nocase_uh(strval, "default") == 0) {
00953     return DC_default;
00954   } else {
00955     return DC_unspecified;
00956   }
00957 }
00958 
00959 ////////////////////////////////////////////////////////////////////
00960 //     Function: EggGroup::string_billboard_type
00961 //       Access: Published, Static
00962 //  Description: Returns the BillboardType value associated with the
00963 //               given string representation, or BT_none if the string
00964 //               does not match any known BillboardType value.
00965 ////////////////////////////////////////////////////////////////////
00966 EggGroup::BillboardType EggGroup::
00967 string_billboard_type(const string &strval) {
00968   if (cmp_nocase_uh(strval, "axis") == 0) {
00969     return BT_axis;
00970   } else if (cmp_nocase_uh(strval, "point_eye") == 0) {
00971     return BT_point_camera_relative;
00972   } else if (cmp_nocase_uh(strval, "point_world") == 0) {
00973     return BT_point_world_relative;
00974   } else if (cmp_nocase_uh(strval, "point") == 0) {
00975     return BT_point_world_relative;
00976   } else {
00977     return BT_none;
00978   }
00979 }
00980 
00981 ////////////////////////////////////////////////////////////////////
00982 //     Function: EggGroup::string_cs_type
00983 //       Access: Published, Static
00984 //  Description: Returns the CollisionSolidType value associated with the
00985 //               given string representation, or CST_none if the string
00986 //               does not match any known CollisionSolidType value.
00987 ////////////////////////////////////////////////////////////////////
00988 EggGroup::CollisionSolidType EggGroup::
00989 string_cs_type(const string &strval) {
00990   if (cmp_nocase_uh(strval, "plane") == 0) {
00991     return CST_plane;
00992   } else if (cmp_nocase_uh(strval, "polygon") == 0) {
00993     return CST_polygon;
00994   } else if (cmp_nocase_uh(strval, "polyset") == 0) {
00995     return CST_polyset;
00996   } else if (cmp_nocase_uh(strval, "sphere") == 0) {
00997     return CST_sphere;
00998   } else if (cmp_nocase_uh(strval, "inv-sphere") == 0 ||
00999              cmp_nocase_uh(strval, "invsphere") == 0) {
01000     return CST_inv_sphere;
01001   } else if (cmp_nocase_uh(strval, "tube") == 0) {
01002     return CST_tube;
01003   } else if (cmp_nocase_uh(strval, "floor-mesh") == 0) {    
01004     return CST_floor_mesh;
01005   } else {
01006     return CST_none;
01007   }
01008 }
01009 
01010 ////////////////////////////////////////////////////////////////////
01011 //     Function: EggGroup::string_collide_flags
01012 //       Access: Published, Static
01013 //  Description: Returns the CollideFlags value associated with the
01014 //               given string representation, or CF_none if the string
01015 //               does not match any known CollideFlags value.  This
01016 //               only recognizes a single keyword; it does not attempt
01017 //               to parse a string of keywords.
01018 ////////////////////////////////////////////////////////////////////
01019 EggGroup::CollideFlags EggGroup::
01020 string_collide_flags(const string &strval) {
01021   if (cmp_nocase_uh(strval, "intangible") == 0) {
01022     return CF_intangible;
01023   } else if (cmp_nocase_uh(strval, "event") == 0) {
01024     return CF_event;
01025   } else if (cmp_nocase_uh(strval, "descend") == 0) {
01026     return CF_descend;
01027   } else if (cmp_nocase_uh(strval, "keep") == 0) {
01028     return CF_keep;
01029   } else if (cmp_nocase_uh(strval, "solid") == 0) {
01030     return CF_solid;
01031   } else if (cmp_nocase_uh(strval, "center") == 0) {
01032     return CF_center;
01033   } else if (cmp_nocase_uh(strval, "turnstile") == 0) {
01034     return CF_turnstile;
01035   } else if (cmp_nocase_uh(strval, "level") == 0) {
01036     return CF_level;
01037   } else {
01038     return CF_none;
01039   }
01040 }
01041 
01042 ////////////////////////////////////////////////////////////////////
01043 //     Function: EggGroup::string_blend_mode
01044 //       Access: Published, Static
01045 //  Description: Returns the BlendMode value associated with the
01046 //               given string representation, or BM_none if the string
01047 //               does not match any known BlendMode.
01048 ////////////////////////////////////////////////////////////////////
01049 EggGroup::BlendMode EggGroup::
01050 string_blend_mode(const string &strval) {
01051   if (cmp_nocase_uh(strval, "none") == 0) {
01052     return BM_none;
01053   } else if (cmp_nocase_uh(strval, "add") == 0) {
01054     return BM_add;
01055   } else if (cmp_nocase_uh(strval, "subtract") == 0) {
01056     return BM_subtract;
01057   } else if (cmp_nocase_uh(strval, "inv_subtract") == 0) {
01058     return BM_inv_subtract;
01059   } else if (cmp_nocase_uh(strval, "min") == 0) {
01060     return BM_min;
01061   } else if (cmp_nocase_uh(strval, "max") == 0) {
01062     return BM_max;
01063   } else {
01064     return BM_unspecified;
01065   }
01066 }
01067 
01068 ////////////////////////////////////////////////////////////////////
01069 //     Function: EggGroup::string_blend_operand
01070 //       Access: Published, Static
01071 //  Description: Returns the BlendOperand value associated with the
01072 //               given string representation, or BO_none if the string
01073 //               does not match any known BlendOperand.
01074 ////////////////////////////////////////////////////////////////////
01075 EggGroup::BlendOperand EggGroup::
01076 string_blend_operand(const string &strval) {
01077   if (cmp_nocase_uh(strval, "zero") == 0) {
01078     return BO_zero;
01079   } else if (cmp_nocase_uh(strval, "one") == 0) {
01080     return BO_one;
01081   } else if (cmp_nocase_uh(strval, "incoming_color") == 0) {
01082     return BO_incoming_color;
01083   } else if (cmp_nocase_uh(strval, "one_minus_incoming_color") == 0) {
01084     return BO_one_minus_incoming_color;
01085   } else if (cmp_nocase_uh(strval, "fbuffer_color") == 0) {
01086     return BO_fbuffer_color;
01087   } else if (cmp_nocase_uh(strval, "one_minus_fbuffer_color") == 0) {
01088     return BO_one_minus_fbuffer_color;
01089   } else if (cmp_nocase_uh(strval, "incoming_alpha") == 0) {
01090     return BO_incoming_alpha;
01091   } else if (cmp_nocase_uh(strval, "one_minus_incoming_alpha") == 0) {
01092     return BO_one_minus_incoming_alpha;
01093   } else if (cmp_nocase_uh(strval, "fbuffer_alpha") == 0) {
01094     return BO_fbuffer_alpha;
01095   } else if (cmp_nocase_uh(strval, "one_minus_fbuffer_alpha") == 0) {
01096     return BO_one_minus_fbuffer_alpha;
01097   } else if (cmp_nocase_uh(strval, "constant_color") == 0) {
01098     return BO_constant_color;
01099   } else if (cmp_nocase_uh(strval, "one_minus_constant_color") == 0) {
01100     return BO_one_minus_constant_color;
01101   } else if (cmp_nocase_uh(strval, "constant_alpha") == 0) {
01102     return BO_constant_alpha;
01103   } else if (cmp_nocase_uh(strval, "one_minus_constant_alpha") == 0) {
01104     return BO_one_minus_constant_alpha;
01105   } else if (cmp_nocase_uh(strval, "incoming_color_saturate") == 0) {
01106     return BO_incoming_color_saturate;
01107   } else if (cmp_nocase_uh(strval, "color_scale") == 0) {
01108     return BO_color_scale;
01109   } else if (cmp_nocase_uh(strval, "one_minus_color_scale") == 0) {
01110     return BO_one_minus_color_scale;
01111   } else if (cmp_nocase_uh(strval, "alpha_scale") == 0) {
01112     return BO_alpha_scale;
01113   } else if (cmp_nocase_uh(strval, "one_minus_alpha_scale") == 0) {
01114     return BO_one_minus_alpha_scale;
01115   } else {
01116     return BO_unspecified;
01117   }
01118 }
01119 
01120 ////////////////////////////////////////////////////////////////////
01121 //     Function: EggGroup::as_transform
01122 //       Access: Public, Virtual
01123 //  Description: Returns this object cross-cast to an EggTransform
01124 //               pointer, if it inherits from EggTransform, or NULL if
01125 //               it does not.
01126 ////////////////////////////////////////////////////////////////////
01127 EggTransform *EggGroup::
01128 as_transform() {
01129   return this;
01130 }
01131 
01132 
01133 ////////////////////////////////////////////////////////////////////
01134 //     Function: EggGroup::write_vertex_ref
01135 //       Access: Protected
01136 //  Description: Writes out the vertex ref component of the group body
01137 //               only.  This may consist of a number of <VertexRef>
01138 //               entries, each with its own membership value.
01139 ////////////////////////////////////////////////////////////////////
01140 void EggGroup::
01141 write_vertex_ref(ostream &out, int indent_level) const {
01142   // We want to put the vertices together into groups first by vertex
01143   // pool, then by membership value.  Each of these groups becomes a
01144   // separate VertexRef entry.  Within each group, we'll sort the
01145   // vertices by index number.
01146 
01147   typedef pset<int> Indices;
01148   typedef pmap<double, Indices> Memberships;
01149   typedef pmap<EggVertexPool *, Memberships> Pools;
01150 
01151   Pools _entries;
01152   bool all_membership_one = true;
01153 
01154   VertexRef::const_iterator vri;
01155   for (vri = _vref.begin(); vri != _vref.end(); ++vri) {
01156     EggVertex *vert = (*vri).first;
01157     double membership = (*vri).second;
01158 
01159     if (membership != 1.0) {
01160       all_membership_one = false;
01161     }
01162 
01163     _entries[vert->get_pool()][membership].insert(vert->get_index());
01164   }
01165 
01166   // Now that we've reordered them, we can simply traverse the entries
01167   // and write them out.
01168   Pools::const_iterator pi;
01169   for (pi = _entries.begin(); pi != _entries.end(); ++pi) {
01170     EggVertexPool *pool = (*pi).first;
01171     const Memberships &memberships = (*pi).second;
01172     Memberships::const_iterator mi;
01173     for (mi = memberships.begin(); mi != memberships.end(); ++mi) {
01174       double membership = (*mi).first;
01175       const Indices &indices = (*mi).second;
01176 
01177       indent(out, indent_level)
01178         << "<VertexRef> {\n";
01179       write_long_list(out, indent_level+2, indices.begin(), indices.end(),
01180                       "", "", 72);
01181 
01182       // If all vrefs in this group have membership of 1, don't bother
01183       // to write out the membership scalar.
01184       if (!all_membership_one) {
01185         indent(out, indent_level + 2)
01186           << "<Scalar> membership { " << membership << " }\n";
01187       }
01188       if (pool == (EggVertexPool *)NULL) {
01189         indent(out, indent_level + 2)
01190           << "// Invalid NULL vertex pool.\n";
01191       } else {
01192         indent(out, indent_level + 2)
01193           << "<Ref> { " << pool->get_name() << " }\n";
01194       }
01195       indent(out, indent_level)
01196         << "}\n";
01197     }
01198   }
01199 }
01200 
01201 ////////////////////////////////////////////////////////////////////
01202 //     Function: EggGroup::egg_start_parse_body
01203 //       Access: Protected, Virtual
01204 //  Description: This function is called within parse_egg().  It
01205 //               should call the appropriate function on the lexer to
01206 //               initialize the parser into the state associated with
01207 //               this object.  If the object cannot be parsed into
01208 //               directly, it should return false.
01209 ////////////////////////////////////////////////////////////////////
01210 bool EggGroup::
01211 egg_start_parse_body() {
01212   egg_start_group_body();
01213   return true;
01214 }
01215 
01216 ////////////////////////////////////////////////////////////////////
01217 //     Function: EggGroup::adjust_under
01218 //       Access: Protected, Virtual
01219 //  Description: This is called within update_under() after all the
01220 //               various under settings have been inherited directly
01221 //               from the parent node.  It is responsible for
01222 //               adjusting these settings to reflect states local to
01223 //               the current node; for instance, an <Instance> node
01224 //               will force the UF_under_instance bit on.
01225 ////////////////////////////////////////////////////////////////////
01226 void EggGroup::
01227 adjust_under() {
01228   // If we have our own transform, it carries forward.
01229 
01230   // As of 4/18/01, this now also affects the local_coord flag, below.
01231   // This means that a <Transform> entry within an <Instance> node
01232   // transforms the instance itself.
01233   if (has_transform()) {
01234     _under_flags |= UF_under_transform;
01235 
01236     // Our own transform also affects our node frame.
01237     _node_frame =
01238       new MatrixFrame(get_transform3d() * get_node_frame());
01239 
01240     // To prevent trying to invert a sigular matrix
01241     LMatrix4d mat;
01242     bool invert_ok = mat.invert_from(get_node_frame());
01243     if (invert_ok) {
01244       _node_frame_inv =
01245         new MatrixFrame(mat);
01246     } else {
01247       _node_frame_inv = NULL;
01248     }
01249 
01250     _vertex_to_node =
01251       new MatrixFrame(get_vertex_frame() * get_node_frame_inv());
01252     _node_to_vertex =
01253       new MatrixFrame(get_node_frame() * get_vertex_frame_inv());
01254 
01255   }
01256 
01257   if (is_instance_type()) {
01258     _under_flags |= UF_under_instance;
01259     if (_under_flags & UF_under_transform) {
01260       // If we've reached an instance node and we're under a
01261       // transform, that means we've just defined a local coordinate
01262       // system.
01263       _under_flags |= UF_local_coord;
01264     }
01265 
01266     // An instance node means that from this point and below, vertices
01267     // are defined relative to this node.  Thus, the node frame
01268     // becomes the vertex frame.
01269     _vertex_frame = _node_frame;
01270     _vertex_frame_inv = _node_frame_inv;
01271     _vertex_to_node = NULL;
01272     _node_to_vertex = NULL;
01273   }
01274 }
01275 
01276 ////////////////////////////////////////////////////////////////////
01277 //     Function: EggGroup::r_transform
01278 //       Access: Protected, Virtual
01279 //  Description: This is called from within the egg code by
01280 //               transform().  It applies a transformation matrix
01281 //               to the current node in some sensible way, then
01282 //               continues down the tree.
01283 //
01284 //               The first matrix is the transformation to apply; the
01285 //               second is its inverse.  The third parameter is the
01286 //               coordinate system we are changing to, or CS_default
01287 //               if we are not changing coordinate systems.
01288 ////////////////////////////////////////////////////////////////////
01289 void EggGroup::
01290 r_transform(const LMatrix4d &mat, const LMatrix4d &inv,
01291             CoordinateSystem to_cs) {
01292   if (has_transform() || get_group_type() == GT_joint) {
01293     // Since we want to apply this transform to all matrices,
01294     // including nested matrices, we can't simply premult it in and
01295     // leave it, because that would leave the rotational component in
01296     // the scene graph's matrix, and all nested matrices would inherit
01297     // the same rotational component.  So we have to premult and then
01298     // postmult by the inverse to undo the rotational component each
01299     // time.
01300 
01301     LMatrix4d mat1 = mat;
01302     LMatrix4d inv1 = inv;
01303 
01304     // If we have a translation component, we should only apply
01305     // it to the top matrix.  All subsequent matrices get just the
01306     // rotational component.
01307     mat1.set_row(3, LVector3d(0.0, 0.0, 0.0));
01308     inv1.set_row(3, LVector3d(0.0, 0.0, 0.0));
01309 
01310     internal_set_transform(inv1 * get_transform3d() * mat);
01311 
01312     if (_default_pose.has_transform()) {
01313       LMatrix4d t = _default_pose.get_transform3d();
01314       _default_pose.clear_transform();
01315       _default_pose.add_matrix4(inv1 * t * mat);
01316     }
01317 
01318     EggGroupNode::r_transform(mat1, inv1, to_cs);
01319   } else {
01320     EggGroupNode::r_transform(mat, inv, to_cs);
01321   }
01322 
01323   // Convert the LOD description too.
01324   if (has_lod()) {
01325     _lod->transform(mat);
01326   }
01327   if (has_billboard_center()) {
01328     _billboard_center = _billboard_center * mat;
01329   }
01330 }
01331 
01332 ////////////////////////////////////////////////////////////////////
01333 //     Function: EggGroup::r_flatten_transforms
01334 //       Access: Protected, Virtual
01335 //  Description: The recursive implementation of flatten_transforms().
01336 ////////////////////////////////////////////////////////////////////
01337 void EggGroup::
01338 r_flatten_transforms() {
01339   EggGroupNode::r_flatten_transforms();
01340 
01341   if (is_local_coord()) {
01342     LMatrix4d mat = get_vertex_frame();
01343     if (has_lod()) {
01344       _lod->transform(mat);
01345     }
01346 
01347     if (get_billboard_type() != BT_none && !has_billboard_center()) {
01348       // If we had a billboard without an explicit center, it was an
01349       // implicit instance.  Now it's not any more.
01350       set_billboard_center(LPoint3d(0.0, 0.0, 0.0) * mat);
01351 
01352     } else if (has_billboard_center()) {
01353       _billboard_center = _billboard_center * mat;
01354     }
01355   }
01356 
01357   if (get_group_type() == GT_instance) {
01358     set_group_type(GT_group);
01359   }
01360 
01361   if (get_group_type() != GT_joint) {
01362     internal_clear_transform();
01363   }
01364 }
01365 
01366 
01367 ////////////////////////////////////////////////////////////////////
01368 //     Function: EggGroup::transform_changed
01369 //       Access: Protected, Virtual
01370 //  Description: This virtual method is inherited by EggTransform3d;
01371 //               it is called whenever the transform is changed.
01372 ////////////////////////////////////////////////////////////////////
01373 void EggGroup::
01374 transform_changed() {
01375   // Recompute all of the cached transforms at this node and below.
01376   // We should probably make this smarter and do lazy evaluation of
01377   // these transforms, rather than having to recompute the whole tree
01378   // with every change to a parent node's transform.
01379   update_under(0);
01380 }
01381 
01382 
01383 
01384 ////////////////////////////////////////////////////////////////////
01385 //     Function: GroupType output operator
01386 //  Description:
01387 ////////////////////////////////////////////////////////////////////
01388 ostream &operator << (ostream &out, EggGroup::GroupType t) {
01389   switch (t) {
01390   case EggGroup::GT_invalid:
01391     return out << "invalid group";
01392   case EggGroup::GT_group:
01393     return out << "group";
01394   case EggGroup::GT_instance:
01395     return out << "instance";
01396   case EggGroup::GT_joint:
01397     return out << "joint";
01398   }
01399 
01400   nassertr(false, out);
01401   return out << "(**invalid**)";
01402 }
01403 
01404 ////////////////////////////////////////////////////////////////////
01405 //     Function: DartType output operator
01406 //  Description:
01407 ////////////////////////////////////////////////////////////////////
01408 ostream &operator << (ostream &out, EggGroup::DartType t) {
01409   switch (t) {
01410   case EggGroup::DT_none:
01411     return out << "none";
01412   case EggGroup::DT_sync:
01413     return out << "sync";
01414   case EggGroup::DT_nosync:
01415     return out << "nosync";
01416   case EggGroup::DT_structured:
01417     return out << "structured";
01418   case EggGroup::DT_default:
01419     return out << "1";
01420   }
01421 
01422   nassertr(false, out);
01423   return out << "(**invalid**)";
01424 }
01425 
01426 ////////////////////////////////////////////////////////////////////
01427 //     Function: DCSType output operator
01428 //  Description:
01429 ////////////////////////////////////////////////////////////////////
01430 ostream &operator << (ostream &out, EggGroup::DCSType t) {
01431   switch (t) {
01432   case EggGroup::DC_unspecified:
01433     return out << "unspecified";
01434   case EggGroup::DC_none:
01435     return out << "none";
01436   case EggGroup::DC_local:
01437     return out << "local";
01438   case EggGroup::DC_net:
01439     return out << "net";
01440   case EggGroup::DC_no_touch:
01441     return out << "no_touch";
01442   case EggGroup::DC_default:
01443     return out << "1";
01444   }
01445 
01446   nassertr(false, out);
01447   return out << "(**invalid**)";
01448 }
01449 
01450 ////////////////////////////////////////////////////////////////////
01451 //     Function: BillboardType output operator
01452 //  Description:
01453 ////////////////////////////////////////////////////////////////////
01454 ostream &operator << (ostream &out, EggGroup::BillboardType t) {
01455   switch (t) {
01456   case EggGroup::BT_none:
01457     return out << "none";
01458   case EggGroup::BT_axis:
01459     return out << "axis";
01460   case EggGroup::BT_point_camera_relative:
01461     return out << "point_eye";
01462   case EggGroup::BT_point_world_relative:
01463     return out << "point_world";
01464   }
01465 
01466   nassertr(false, out);
01467   return out << "(**invalid**)";
01468 }
01469 
01470 ////////////////////////////////////////////////////////////////////
01471 //     Function: CollisionSolidType output operator
01472 //  Description:
01473 ////////////////////////////////////////////////////////////////////
01474 ostream &operator << (ostream &out, EggGroup::CollisionSolidType t) {
01475   switch (t) {
01476   case EggGroup::CST_none:
01477     return out << "None";
01478   case EggGroup::CST_plane:
01479     return out << "Plane";
01480   case EggGroup::CST_polygon:
01481     return out << "Polygon";
01482   case EggGroup::CST_polyset:
01483     return out << "Polyset";
01484   case EggGroup::CST_sphere:
01485     return out << "Sphere";
01486   case EggGroup::CST_inv_sphere:
01487     return out << "InvSphere";
01488   case EggGroup::CST_tube:
01489     return out << "Tube";
01490   }
01491 
01492   nassertr(false, out);
01493   return out << "(**invalid**)";
01494 }
01495 
01496 ////////////////////////////////////////////////////////////////////
01497 //     Function: CollideFlags output operator
01498 //  Description:
01499 ////////////////////////////////////////////////////////////////////
01500 ostream &operator << (ostream &out, EggGroup::CollideFlags t) {
01501   if (t == EggGroup::CF_none) {
01502     return out << "none";
01503   }
01504   int bits = (int)t;
01505   const char *space = "";
01506 
01507   if (bits & EggGroup::CF_intangible) {
01508     out << space << "intangible";
01509     space = " ";
01510   }
01511   if (bits & EggGroup::CF_event) {
01512     out << space << "event";
01513     space = " ";
01514   }
01515   if (bits & EggGroup::CF_descend) {
01516     out << space << "descend";
01517     space = " ";
01518   }
01519   if (bits & EggGroup::CF_keep) {
01520     out << space << "keep";
01521     space = " ";
01522   }
01523   if (bits & EggGroup::CF_solid) {
01524     out << space << "solid";
01525     space = " ";
01526   }
01527   if (bits & EggGroup::CF_center) {
01528     out << space << "center";
01529     space = " ";
01530   }
01531   if (bits & EggGroup::CF_turnstile) {
01532     out << space << "turnstile";
01533     space = " ";
01534   }
01535   if (bits & EggGroup::CF_level) {
01536     out << space << "level";
01537     space = " ";
01538   }
01539   return out;
01540 }
01541 
01542 ////////////////////////////////////////////////////////////////////
01543 //     Function: ostream << EggGroup::BlendMode
01544 //  Description: 
01545 ////////////////////////////////////////////////////////////////////
01546 ostream &
01547 operator << (ostream &out, EggGroup::BlendMode t) {
01548   switch (t) {
01549   case EggGroup::BM_unspecified:
01550     return out << "unspecified";
01551 
01552   case EggGroup::BM_none:
01553     return out << "none";
01554 
01555   case EggGroup::BM_add:
01556     return out << "add";
01557 
01558   case EggGroup::BM_subtract:
01559     return out << "subtract";
01560 
01561   case EggGroup::BM_inv_subtract:
01562     return out << "inv_subtract";
01563 
01564   case EggGroup::BM_min:
01565     return out << "min";
01566 
01567   case EggGroup::BM_max:
01568     return out << "max";
01569   }
01570 
01571   return out << "**invalid EggGroup::BlendMode(" << (int)t << ")**";
01572 }
01573 
01574 ////////////////////////////////////////////////////////////////////
01575 //     Function: ostream << EggGroup::BlendOperand
01576 //  Description: 
01577 ////////////////////////////////////////////////////////////////////
01578 ostream &
01579 operator << (ostream &out, EggGroup::BlendOperand t) {
01580   switch (t) {
01581   case EggGroup::BO_unspecified:
01582     return out << "unspecified";
01583 
01584   case EggGroup::BO_zero:
01585     return out << "zero";
01586 
01587   case EggGroup::BO_one:
01588     return out << "one";
01589 
01590   case EggGroup::BO_incoming_color:
01591     return out << "incomfing_color";
01592 
01593   case EggGroup::BO_one_minus_incoming_color:
01594     return out << "one_minus_incoming_color";
01595 
01596   case EggGroup::BO_fbuffer_color:
01597     return out << "fbuffer_color";
01598 
01599   case EggGroup::BO_one_minus_fbuffer_color:
01600     return out << "one_minus_fbuffer_color";
01601 
01602   case EggGroup::BO_incoming_alpha:
01603     return out << "incoming_alpha";
01604 
01605   case EggGroup::BO_one_minus_incoming_alpha:
01606     return out << "one_minus_incoming_alpha";
01607 
01608   case EggGroup::BO_fbuffer_alpha:
01609     return out << "fbuffer_alpha";
01610 
01611   case EggGroup::BO_one_minus_fbuffer_alpha:
01612     return out << "one_minus_fbuffer_alpha";
01613 
01614   case EggGroup::BO_constant_color:
01615     return out << "constant_color";
01616 
01617   case EggGroup::BO_one_minus_constant_color:
01618     return out << "one_minus_constant_color";
01619 
01620   case EggGroup::BO_constant_alpha:
01621     return out << "constant_alpha";
01622 
01623   case EggGroup::BO_one_minus_constant_alpha:
01624     return out << "one_minus_constant_alpha";
01625 
01626   case EggGroup::BO_incoming_color_saturate:
01627     return out << "incoming_color_saturate";
01628 
01629   case EggGroup::BO_color_scale:
01630     return out << "color_scale";
01631 
01632   case EggGroup::BO_one_minus_color_scale:
01633     return out << "one_minus_color_scale";
01634 
01635   case EggGroup::BO_alpha_scale:
01636     return out << "alpha_scale";
01637 
01638   case EggGroup::BO_one_minus_alpha_scale:
01639     return out << "one_minus_alpha_scale";
01640   }
01641 
01642   return out << "**invalid EggGroup::BlendOperand(" << (int)t << ")**";
01643 }
 All Classes Functions Variables Enumerations