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