Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

panda/src/egg/eggGroup.cxx

Go to the documentation of this file.
00001 // Filename: eggGroup.cxx
00002 // Created by:  drose (16Jan99)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
00008 //
00009 // All use of this software is subject to the terms of the Panda 3d
00010 // Software license.  You should have received a copy of this license
00011 // along with this source code; you will also find a current copy of
00012 // the license at http://www.panda3d.org/license.txt .
00013 //
00014 // To contact the maintainers of this program write to
00015 // panda3d@yahoogroups.com .
00016 //
00017 ////////////////////////////////////////////////////////////////////
00018 
00019 #include "eggGroup.h"
00020 #include "eggMiscFuncs.h"
00021 #include "eggVertexPool.h"
00022 #include "eggBin.h"
00023 #include "lexerDefs.h"
00024 
00025 #include "indent.h"
00026 #include "string_utils.h"
00027 #include "lmatrix.h"
00028 
00029 
00030 TypeHandle EggGroup::_type_handle;
00031 
00032 ////////////////////////////////////////////////////////////////////
00033 //     Function: EggGroup::Constructor
00034 //       Access: Public
00035 //  Description:
00036 ////////////////////////////////////////////////////////////////////
00037 EggGroup::
00038 EggGroup(const string &name) : EggGroupNode(name) {
00039   _flags = 0;
00040   _flags2 = 0;
00041   _fps = 0.0;
00042 }
00043 
00044 ////////////////////////////////////////////////////////////////////
00045 //     Function: EggGroup::Copy Constructor
00046 //       Access: Public
00047 //  Description:
00048 ////////////////////////////////////////////////////////////////////
00049 EggGroup::
00050 EggGroup(const EggGroup &copy) {
00051   (*this) = copy;
00052 }
00053 
00054 ////////////////////////////////////////////////////////////////////
00055 //     Function: EggGroup::Copy assignment operator
00056 //       Access: Public
00057 //  Description:
00058 ////////////////////////////////////////////////////////////////////
00059 EggGroup &EggGroup::
00060 operator = (const EggGroup &copy) {
00061   EggTransform3d::operator = (copy);
00062   _flags = copy._flags;
00063   _flags2 = copy._flags2;
00064   _object_types = copy._object_types;
00065   _collision_name = copy._collision_name;
00066   _fps = copy._fps;
00067 
00068   unref_all_vertices();
00069   _vref = copy._vref;
00070 
00071   // We must walk through the vertex ref list, and flag each vertex as
00072   // now reffed by this group.
00073   VertexRef::iterator vri;
00074   for (vri = _vref.begin(); vri != _vref.end(); ++vri) {
00075     EggVertex *vert = (*vri).first;
00076 
00077     bool inserted = vert->_gref.insert(this).second;
00078     // Did the group not exist previously in the vertex's gref list?
00079     // If it was there already, we must be out of sync between
00080     // vertices and groups.
00081     nassertr(inserted, *this);
00082   }
00083 
00084   // These must be down here, because the EggNode assignment operator
00085   // will force an update_under().  Therefore, we can't call it until
00086   // all the attributes that affect adjust_under() are in place.
00087   EggGroupNode::operator = (copy);
00088   EggRenderMode::operator = (copy);
00089 
00090   return *this;
00091 }
00092 
00093 
00094 ////////////////////////////////////////////////////////////////////
00095 //     Function: EggGroup::Destructor
00096 //       Access: Public
00097 //  Description:
00098 ////////////////////////////////////////////////////////////////////
00099 EggGroup::
00100 ~EggGroup() {
00101   unref_all_vertices();
00102 }
00103 
00104 ////////////////////////////////////////////////////////////////////
00105 //     Function: EggGroup::set_group_type
00106 //       Access: Public
00107 //  Description:
00108 ////////////////////////////////////////////////////////////////////
00109 void EggGroup::
00110 set_group_type(GroupType type) {
00111   if (type != get_group_type()) {
00112     // Make sure the user didn't give us any stray bits.
00113     nassertv((type & ~F_group_type)==0);
00114     _flags = (_flags & ~F_group_type) | type;
00115 
00116     // Now we might have changed the type to or from an instance node,
00117     // so we have to recompute the under_flags.
00118     update_under(0);
00119   }
00120 }
00121 
00122 ////////////////////////////////////////////////////////////////////
00123 //     Function: EggGroup::has_object_type
00124 //       Access: Public
00125 //  Description: Returns true if the indicated object type has been
00126 //               added to the group, or false otherwise.
00127 ////////////////////////////////////////////////////////////////////
00128 bool EggGroup::
00129 has_object_type(const string &object_type) const {
00130   vector_string::const_iterator oi;
00131   for (oi = _object_types.begin(); oi != _object_types.end(); ++oi) {
00132     if (cmp_nocase_uh((*oi), object_type) == 0) {
00133       return true;
00134     }
00135   }
00136   return false;
00137 }
00138 
00139 ////////////////////////////////////////////////////////////////////
00140 //     Function: EggGroup::remove_object_type
00141 //       Access: Public
00142 //  Description: Removes the first instance of the indicated object
00143 //               type from the group if it is present.  Returns true
00144 //               if the object type was found and removed, false
00145 //               otherwise.
00146 ////////////////////////////////////////////////////////////////////
00147 bool EggGroup::
00148 remove_object_type(const string &object_type) {
00149   vector_string::iterator oi;
00150   for (oi = _object_types.begin(); oi != _object_types.end(); ++oi) {
00151     if (cmp_nocase_uh((*oi), object_type) == 0) {
00152       _object_types.erase(oi);
00153       return true;
00154     }
00155   }
00156   return false;
00157 }
00158 
00159 ////////////////////////////////////////////////////////////////////
00160 //     Function: EggGroup::write
00161 //       Access: Public, Virtual
00162 //  Description: Writes the group and all of its children to the
00163 //               indicated output stream in Egg format.
00164 ////////////////////////////////////////////////////////////////////
00165 void EggGroup::
00166 write(ostream &out, int indent_level) const {
00167   test_under_integrity();
00168 
00169   switch (get_group_type()) {
00170   case GT_group:
00171     write_header(out, indent_level, "<Group>");
00172     break;
00173 
00174   case GT_instance:
00175     write_header(out, indent_level, "<Instance>");
00176     break;
00177 
00178   case GT_joint:
00179     write_header(out, indent_level, "<Joint>");
00180     break;
00181 
00182   default:
00183     // invalid group type
00184     nassertv(false);
00185   }
00186 
00187   if (is_of_type(EggBin::get_class_type())) {
00188     indent(out, indent_level + 2)
00189       << "// Bin " << DCAST(EggBin, this)->get_bin_number() << "\n";
00190   }
00191 
00192   if (has_lod()) {
00193     get_lod().write(out, indent_level + 2);
00194   }
00195 
00196   if (get_billboard_type() != BT_none) {
00197     indent(out, indent_level + 2)
00198       << "<Billboard> { " << get_billboard_type() << " }\n";
00199   }
00200 
00201   if (has_billboard_center()) {
00202     indent(out, indent_level + 2)
00203       << "<BillboardCenter> { " << get_billboard_center() << " }\n";
00204   }
00205 
00206   if (get_cs_type() != CST_none) {
00207     indent(out, indent_level + 2) << "<Collide> ";
00208     if (has_collision_name()) {
00209       enquote_string(out, get_collision_name()) << " ";
00210     }
00211     out << "{ " << get_cs_type();
00212     if (get_collide_flags() != CF_none) {
00213       out << " " << get_collide_flags();
00214     }
00215     out << " }\n";
00216   }
00217 
00218   if (has_collide_mask()) {
00219     indent(out, indent_level + 2)
00220       << "<Scalar> collide-mask { 0x";
00221     get_collide_mask().output_hex(out, 0);
00222     out << " }\n";
00223   }
00224 
00225   if (has_from_collide_mask()) {
00226     indent(out, indent_level + 2)
00227       << "<Scalar> from-collide-mask { 0x";
00228     get_from_collide_mask().output_hex(out, 0);
00229     out << " }\n";
00230   }
00231 
00232   if (has_into_collide_mask()) {
00233     indent(out, indent_level + 2)
00234       << "<Scalar> into-collide-mask { 0x";
00235     get_into_collide_mask().output_hex(out, 0);
00236     out << " }\n";
00237   }
00238 
00239   if (get_dcs_type() != DC_none) {
00240     indent(out, indent_level + 2) 
00241       << "<DCS> { " << get_dcs_type() << " }\n";
00242   }
00243 
00244   if (get_dart_type() != DT_none) {
00245     indent(out, indent_level + 2)
00246       << "<Dart> { " << get_dart_type() << " }\n";
00247   }
00248 
00249   if (get_switch_flag()) {
00250     indent(out, indent_level + 2) << "<Switch> { 1 }\n";
00251     if (get_switch_fps() != 0.0) {
00252       indent(out, indent_level + 2)
00253         << "<Scalar> fps { " << get_switch_fps() << " }\n";
00254     }
00255   }
00256 
00257   if (has_transform()) {
00258     EggTransform3d::write(out, indent_level + 2);
00259   }
00260 
00261   vector_string::const_iterator oi;
00262   for (oi = _object_types.begin(); oi != _object_types.end(); ++oi) {
00263     indent(out, indent_level + 2)
00264       << "<ObjectType> { ";
00265     enquote_string(out, (*oi)) << " }\n";
00266   }
00267 
00268   if (get_model_flag()) {
00269     indent(out, indent_level + 2) << "<Model> { 1 }\n";
00270   }
00271 
00272   if (get_texlist_flag()) {
00273     indent(out, indent_level + 2) << "<TexList> { 1 }\n";
00274   }
00275 
00276   if (get_nofog_flag()) {
00277     indent(out, indent_level + 2) << "<Scalar> no-fog { 1 }\n";
00278   }
00279 
00280   if (get_decal_flag()) {
00281     indent(out, indent_level + 2) << "<Scalar> decal { 1 }\n";
00282   }
00283 
00284   if (get_direct_flag()) {
00285     indent(out, indent_level + 2) << "<Scalar> direct { 1 }\n";
00286   }
00287 
00288   EggRenderMode::write(out, indent_level + 2);
00289 
00290   EggGroupNode::write(out, indent_level + 2);
00291 
00292   write_vertex_ref(out, indent_level + 2);
00293 
00294   indent(out, indent_level) << "}\n";
00295 }
00296 
00297 ////////////////////////////////////////////////////////////////////
00298 //     Function: EggGroup::determine_alpha_mode
00299 //       Access: Public, Virtual
00300 //  Description: Walks back up the hierarchy, looking for an EggGroup
00301 //               or EggPrimitive or some such object at this level or
00302 //               above this group that has an alpha_mode other than
00303 //               AM_unspecified.  Returns a valid EggRenderMode pointer
00304 //               if one is found, or NULL otherwise.
00305 ////////////////////////////////////////////////////////////////////
00306 EggRenderMode *EggGroup::
00307 determine_alpha_mode() {
00308   if (get_alpha_mode() != AM_unspecified) {
00309     return this;
00310   }
00311   return EggGroupNode::determine_alpha_mode();
00312 }
00313 
00314 ////////////////////////////////////////////////////////////////////
00315 //     Function: EggGroup::determine_depth_write_mode
00316 //       Access: Public, Virtual
00317 //  Description: Walks back up the hierarchy, looking for an EggGroup
00318 //               or EggPrimitive or some such object at this level or
00319 //               above this group that has an depth_write_mode other
00320 //               than DWM_unspecified.  Returns a valid EggRenderMode
00321 //               pointer if one is found, or NULL otherwise.
00322 ////////////////////////////////////////////////////////////////////
00323 EggRenderMode *EggGroup::
00324 determine_depth_write_mode() {
00325   if (get_depth_write_mode() != DWM_unspecified) {
00326     return this;
00327   }
00328   return EggGroupNode::determine_depth_write_mode();
00329 }
00330 
00331 ////////////////////////////////////////////////////////////////////
00332 //     Function: EggGroup::determine_depth_test_mode
00333 //       Access: Public, Virtual
00334 //  Description: Walks back up the hierarchy, looking for an EggGroup
00335 //               or EggPrimitive or some such object at this level or
00336 //               above this group that has an depth_test_mode other
00337 //               than DTM_unspecified.  Returns a valid EggRenderMode
00338 //               pointer if one is found, or NULL otherwise.
00339 ////////////////////////////////////////////////////////////////////
00340 EggRenderMode *EggGroup::
00341 determine_depth_test_mode() {
00342   if (get_depth_test_mode() != DTM_unspecified) {
00343     return this;
00344   }
00345   return EggGroupNode::determine_depth_test_mode();
00346 }
00347 
00348 ////////////////////////////////////////////////////////////////////
00349 //     Function: EggGroup::determine_draw_order
00350 //       Access: Public, Virtual
00351 //  Description: Walks back up the hierarchy, looking for an EggGroup
00352 //               or EggPrimitive or some such object at this level or
00353 //               above this group that has a draw_order specified.
00354 //               Returns a valid EggRenderMode pointer if one is found,
00355 //               or NULL otherwise.
00356 ////////////////////////////////////////////////////////////////////
00357 EggRenderMode *EggGroup::
00358 determine_draw_order() {
00359   if (has_draw_order()) {
00360     return this;
00361   }
00362   return EggGroupNode::determine_draw_order();
00363 }
00364 
00365 ////////////////////////////////////////////////////////////////////
00366 //     Function: EggGroup::determine_bin
00367 //       Access: Public, Virtual
00368 //  Description: Walks back up the hierarchy, looking for an EggGroup
00369 //               or EggPrimitive or some such object at this level or
00370 //               above this group that has a bin specified.  Returns a
00371 //               valid EggRenderMode pointer if one is found, or NULL
00372 //               otherwise.
00373 ////////////////////////////////////////////////////////////////////
00374 EggRenderMode *EggGroup::
00375 determine_bin() {
00376   if (has_bin()) {
00377     return this;
00378   }
00379   return EggGroupNode::determine_bin();
00380 }
00381 
00382 ////////////////////////////////////////////////////////////////////
00383 //     Function: EggGroup::ref_vertex
00384 //       Access: Public
00385 //  Description: Adds the vertex to the set of those referenced by the
00386 //               group, at the indicated membership level.  If the
00387 //               vertex is already being referenced, increases the
00388 //               membership amount by the indicated amount.
00389 ////////////////////////////////////////////////////////////////////
00390 void EggGroup::
00391 ref_vertex(EggVertex *vert, double membership) {
00392   VertexRef::iterator vri = _vref.find(vert);
00393 
00394   if (vri != _vref.end()) {
00395     // The vertex was already being reffed; increment its membership
00396     // amount.
00397     (*vri).second += membership;
00398 
00399     // If that takes us down to zero, go ahead and unref the vertex.
00400     if ((*vri).second == 0.0) {
00401       unref_vertex(vert);
00402     }
00403 
00404   } else {
00405     // The vertex was not already reffed; ref it.
00406     if (membership != 0.0) {
00407       _vref[vert] = membership;
00408 
00409       bool inserted = vert->_gref.insert(this).second;
00410       // Did the group not exist previously in the vertex's gref list?
00411       // If it was there already, we must be out of sync between
00412       // vertices and groups.
00413       nassertv(inserted);
00414     }
00415   }
00416 }
00417 
00418 
00419 ////////////////////////////////////////////////////////////////////
00420 //     Function: EggGroup::unref_vertex
00421 //       Access: Public
00422 //  Description: Removes the vertex from the set of those referenced
00423 //               by the group.  Does nothing if the vertex is not
00424 //               already reffed.
00425 ////////////////////////////////////////////////////////////////////
00426 void EggGroup::
00427 unref_vertex(EggVertex *vert) {
00428   VertexRef::iterator vri = _vref.find(vert);
00429 
00430   if (vri != _vref.end()) {
00431     _vref.erase(vri);
00432     int count = vert->_gref.erase(this);
00433     // Did the group exist in the vertex's gref list?  If it didn't,
00434     // we must be out of sync between vertices and groups.
00435     nassertv(count == 1);
00436   }
00437 }
00438 
00439 ////////////////////////////////////////////////////////////////////
00440 //     Function: EggGroup::unref_all_vertices
00441 //       Access: Public
00442 //  Description: Removes all vertices from the reference list.
00443 ////////////////////////////////////////////////////////////////////
00444 void EggGroup::
00445 unref_all_vertices() {
00446   // We must walk through the vertex ref list, and flag each vertex as
00447   // unreffed in its own structure.
00448   VertexRef::iterator vri;
00449   for (vri = _vref.begin(); vri != _vref.end(); ++vri) {
00450     EggVertex *vert = (*vri).first;
00451     int count = vert->_gref.erase(this);
00452     // Did the group exist in the vertex's gref list?  If it didn't,
00453     // we must be out of sync between vertices and groups.
00454     nassertv(count == 1);
00455   }
00456 
00457   _vref.clear();
00458 }
00459 
00460 
00461 ////////////////////////////////////////////////////////////////////
00462 //     Function: EggGroup::get_vertex_membership
00463 //       Access: Public
00464 //  Description: Returns the amount of membership of the indicated
00465 //               vertex in this group.  If the vertex is not reffed by
00466 //               the group, returns 0.
00467 ////////////////////////////////////////////////////////////////////
00468 double EggGroup::
00469 get_vertex_membership(const EggVertex *vert) const {
00470   VertexRef::const_iterator vri = _vref.find((EggVertex *)vert);
00471 
00472   if (vri != _vref.end()) {
00473     return (*vri).second;
00474   } else {
00475     return 0.0;
00476   }
00477 }
00478 
00479 
00480 #ifndef NDEBUG
00481 
00482 ////////////////////////////////////////////////////////////////////
00483 //     Function: EggGroup::test_vref_integrity
00484 //       Access: Public
00485 //  Description: Verifies that each vertex in the group exists and
00486 //               that it knows it is referenced by the group.
00487 ////////////////////////////////////////////////////////////////////
00488 void EggGroup::
00489 test_vref_integrity() const {
00490   test_ref_count_integrity();
00491 
00492   VertexRef::const_iterator vri;
00493   for (vri = vref_begin(); vri != vref_end(); ++vri) {
00494     const EggVertex *vert = (*vri).first;
00495     vert->test_ref_count_integrity();
00496 
00497     nassertv(vert->has_gref(this));
00498   }
00499 }
00500 
00501 #endif  // NDEBUG
00502 
00503 
00504 
00505 
00506 ////////////////////////////////////////////////////////////////////
00507 //     Function: EggGroup::string_group_type
00508 //       Access: Public, Static
00509 //  Description: Returns the GroupType value associated with the given
00510 //               string representation, or GT_invalid if the string
00511 //               does not match any known GroupType value.
00512 ////////////////////////////////////////////////////////////////////
00513 EggGroup::GroupType EggGroup::
00514 string_group_type(const string &string) {
00515   if (cmp_nocase_uh(string, "group") == 0) {
00516     return GT_group;
00517   } else if (cmp_nocase_uh(string, "instance") == 0) {
00518     return GT_instance;
00519   } else if (cmp_nocase_uh(string, "joint") == 0) {
00520     return GT_joint;
00521   } else {
00522     return GT_invalid;
00523   }
00524 }
00525 
00526 ////////////////////////////////////////////////////////////////////
00527 //     Function: EggGroup::string_dart_type
00528 //       Access: Public, Static
00529 //  Description: Returns the DartType value associated with the given
00530 //               string representation, or DT_none if the string
00531 //               does not match any known DartType value.
00532 ////////////////////////////////////////////////////////////////////
00533 EggGroup::DartType EggGroup::
00534 string_dart_type(const string &string) {
00535   if (cmp_nocase_uh(string, "sync") == 0) {
00536     return DT_sync;
00537   } else if (cmp_nocase_uh(string, "nosync") == 0) {
00538     return DT_nosync;
00539   } else if (cmp_nocase_uh(string, "default") == 0) {
00540     return DT_default;
00541   } else {
00542     return DT_none;
00543   }
00544 }
00545 
00546 ////////////////////////////////////////////////////////////////////
00547 //     Function: EggGroup::string_dcs_type
00548 //       Access: Public, Static
00549 //  Description: Returns the DCSType value associated with the given
00550 //               string representation, or DC_none if the string
00551 //               does not match any known DCSType value.
00552 ////////////////////////////////////////////////////////////////////
00553 EggGroup::DCSType EggGroup::
00554 string_dcs_type(const string &string) {
00555   if (cmp_nocase_uh(string, "local") == 0) {
00556     return DC_local;
00557   } else if (cmp_nocase_uh(string, "net") == 0) {
00558     return DC_net;
00559   } else if (cmp_nocase_uh(string, "default") == 0) {
00560     return DC_default;
00561   } else {
00562     return DC_none;
00563   }
00564 }
00565 
00566 ////////////////////////////////////////////////////////////////////
00567 //     Function: EggGroup::string_billboard_type
00568 //       Access: Public, Static
00569 //  Description: Returns the BillboardType value associated with the
00570 //               given string representation, or BT_none if the string
00571 //               does not match any known BillboardType value.
00572 ////////////////////////////////////////////////////////////////////
00573 EggGroup::BillboardType EggGroup::
00574 string_billboard_type(const string &string) {
00575   if (cmp_nocase_uh(string, "axis") == 0) {
00576     return BT_axis;
00577   } else if (cmp_nocase_uh(string, "point_eye") == 0) {
00578     return BT_point_camera_relative;
00579   } else if (cmp_nocase_uh(string, "point_world") == 0) {
00580     return BT_point_world_relative;
00581   } else if (cmp_nocase_uh(string, "point") == 0) {
00582     return BT_point_world_relative;
00583   } else {
00584     return BT_none;
00585   }
00586 }
00587 
00588 ////////////////////////////////////////////////////////////////////
00589 //     Function: EggGroup::string_cs_type
00590 //       Access: Public, Static
00591 //  Description: Returns the CollisionSolidType value associated with the
00592 //               given string representation, or CST_none if the string
00593 //               does not match any known CollisionSolidType value.
00594 ////////////////////////////////////////////////////////////////////
00595 EggGroup::CollisionSolidType EggGroup::
00596 string_cs_type(const string &string) {
00597   if (cmp_nocase_uh(string, "plane") == 0) {
00598     return CST_plane;
00599   } else if (cmp_nocase_uh(string, "polygon") == 0) {
00600     return CST_polygon;
00601   } else if (cmp_nocase_uh(string, "polyset") == 0) {
00602     return CST_polyset;
00603   } else if (cmp_nocase_uh(string, "sphere") == 0) {
00604     return CST_sphere;
00605   } else if (cmp_nocase_uh(string, "inversesphere") == 0) {
00606     return CST_inverse_sphere;
00607   } else if (cmp_nocase_uh(string, "geode") == 0) {
00608     return CST_geode;
00609   } else {
00610     return CST_none;
00611   }
00612 }
00613 
00614 ////////////////////////////////////////////////////////////////////
00615 //     Function: EggGroup::string_collide_flags
00616 //       Access: Public, Static
00617 //  Description: Returns the CollideFlags value associated with the
00618 //               given string representation, or CF_none if the string
00619 //               does not match any known CollideFlags value.  This
00620 //               only recognizes a single keyword; it does not attempt
00621 //               to parse a string of keywords.
00622 ////////////////////////////////////////////////////////////////////
00623 EggGroup::CollideFlags EggGroup::
00624 string_collide_flags(const string &string) {
00625   if (cmp_nocase_uh(string, "intangible") == 0) {
00626     return CF_intangible;
00627   } else if (cmp_nocase_uh(string, "event") == 0) {
00628     return CF_event;
00629   } else if (cmp_nocase_uh(string, "descend") == 0) {
00630     return CF_descend;
00631   } else if (cmp_nocase_uh(string, "keep") == 0) {
00632     return CF_keep;
00633   } else if (cmp_nocase_uh(string, "solid") == 0) {
00634     return CF_solid;
00635   } else if (cmp_nocase_uh(string, "center") == 0) {
00636     return CF_center;
00637   } else if (cmp_nocase_uh(string, "turnstile") == 0) {
00638     return CF_turnstile;
00639   } else {
00640     return CF_none;
00641   }
00642 }
00643 
00644 
00645 
00646 ////////////////////////////////////////////////////////////////////
00647 //     Function: EggGroup::write_vertex_ref
00648 //       Access: Protected
00649 //  Description: Writes out the vertex ref component of the group body
00650 //               only.  This may consist of a number of <VertexRef>
00651 //               entries, each with its own membership value.
00652 ////////////////////////////////////////////////////////////////////
00653 void EggGroup::
00654 write_vertex_ref(ostream &out, int indent_level) const {
00655   // We want to put the vertices together into groups first by vertex
00656   // pool, then by membership value.  Each of these groups becomes a
00657   // separate VertexRef entry.  Within each group, we'll sort the
00658   // vertices by index number.
00659 
00660   typedef pset<int> Indices;
00661   typedef pmap<double, Indices> Memberships;
00662   typedef pmap<EggVertexPool *, Memberships> Pools;
00663 
00664   Pools _entries;
00665   bool all_membership_one = true;
00666 
00667   VertexRef::const_iterator vri;
00668   for (vri = _vref.begin(); vri != _vref.end(); ++vri) {
00669     EggVertex *vert = (*vri).first;
00670     double membership = (*vri).second;
00671 
00672     if (membership != 1.0) {
00673       all_membership_one = false;
00674     }
00675 
00676     _entries[vert->get_pool()][membership].insert(vert->get_index());
00677   }
00678 
00679   // Now that we've reordered them, we can simply traverse the entries
00680   // and write them out.
00681   Pools::const_iterator pi;
00682   for (pi = _entries.begin(); pi != _entries.end(); ++pi) {
00683     EggVertexPool *pool = (*pi).first;
00684     const Memberships &memberships = (*pi).second;
00685     Memberships::const_iterator mi;
00686     for (mi = memberships.begin(); mi != memberships.end(); ++mi) {
00687       double membership = (*mi).first;
00688       const Indices &indices = (*mi).second;
00689 
00690       indent(out, indent_level)
00691         << "<VertexRef> {\n";
00692       write_long_list(out, indent_level+2, indices.begin(), indices.end(),
00693                       "", "", 72);
00694 
00695       // If all vrefs in this group have membership of 1, don't bother
00696       // to write out the membership scalar.
00697       if (!all_membership_one) {
00698         indent(out, indent_level + 2)
00699           << "<Scalar> membership { " << membership << " }\n";
00700       }
00701       if (pool == (EggVertexPool *)NULL) {
00702         indent(out, indent_level + 2)
00703           << "// Invalid NULL vertex pool.\n";
00704       } else {
00705         indent(out, indent_level + 2)
00706           << "<Ref> { " << pool->get_name() << " }\n";
00707       }
00708       indent(out, indent_level)
00709         << "}\n";
00710     }
00711   }
00712 }
00713 
00714 ////////////////////////////////////////////////////////////////////
00715 //     Function: EggGroup::egg_start_parse_body
00716 //       Access: Protected, Virtual
00717 //  Description: This function is called within parse_egg().  It
00718 //               should call the appropriate function on the lexer to
00719 //               initialize the parser into the state associated with
00720 //               this object.  If the object cannot be parsed into
00721 //               directly, it should return false.
00722 ////////////////////////////////////////////////////////////////////
00723 bool EggGroup::
00724 egg_start_parse_body() {
00725   egg_start_group_body();
00726   return true;
00727 }
00728 
00729 ////////////////////////////////////////////////////////////////////
00730 //     Function: EggGroup::adjust_under
00731 //       Access: Protected, Virtual
00732 //  Description: This is called within update_under() after all the
00733 //               various under settings have been inherited directly
00734 //               from the parent node.  It is responsible for
00735 //               adjusting these settings to reflect states local to
00736 //               the current node; for instance, an <Instance> node
00737 //               will force the UF_under_instance bit on.
00738 ////////////////////////////////////////////////////////////////////
00739 void EggGroup::
00740 adjust_under() {
00741   // If we have our own transform, it carries forward.
00742 
00743   // As of 4/18/01, this now also affects the local_coord flag, below.
00744   // This means that a <Transform> entry within an <Instance> node
00745   // transforms the instance itself.
00746   if (has_transform()) {
00747     _under_flags |= UF_under_transform;
00748 
00749     // Our own transform also affects our node frame.
00750     _node_frame =
00751       new MatrixFrame(get_transform() * get_node_frame());
00752     _node_frame_inv =
00753       new MatrixFrame(invert(get_node_frame()));
00754     _vertex_to_node =
00755       new MatrixFrame(get_vertex_frame() * get_node_frame_inv());
00756     _node_to_vertex =
00757       new MatrixFrame(get_node_frame() * get_vertex_frame_inv());
00758   }
00759 
00760   if (is_instance_type()) {
00761     _under_flags |= UF_under_instance;
00762     if (_under_flags & UF_under_transform) {
00763       // If we've reached an instance node and we're under a
00764       // transform, that means we've just defined a local coordinate
00765       // system.
00766       _under_flags |= UF_local_coord;
00767     }
00768 
00769     // An instance node means that from this point and below, vertices
00770     // are defined relative to this node.  Thus, the node frame
00771     // becomes the vertex frame.
00772     _vertex_frame = _node_frame;
00773     _vertex_frame_inv = _node_frame_inv;
00774     _vertex_to_node = NULL;
00775     _node_to_vertex = NULL;
00776   }
00777 }
00778 
00779 ////////////////////////////////////////////////////////////////////
00780 //     Function: EggGroup::r_transform
00781 //       Access: Protected, Virtual
00782 //  Description: This is called from within the egg code by
00783 //               transform().  It applies a transformation matrix
00784 //               to the current node in some sensible way, then
00785 //               continues down the tree.
00786 //
00787 //               The first matrix is the transformation to apply; the
00788 //               second is its inverse.  The third parameter is the
00789 //               coordinate system we are changing to, or CS_default
00790 //               if we are not changing coordinate systems.
00791 ////////////////////////////////////////////////////////////////////
00792 void EggGroup::
00793 r_transform(const LMatrix4d &mat, const LMatrix4d &inv,
00794             CoordinateSystem to_cs) {
00795   if (!transform_is_identity()) {
00796     // Since we want to apply this transform to all matrices,
00797     // including nested matrices, we can't simply premult it in and
00798     // leave it, because that would leave the rotational component in
00799     // the scene graph's matrix, and all nested matrices would inherit
00800     // the same rotational component.  So we have to premult and then
00801     // postmult by the inverse to undo the rotational component each
00802     // time.
00803 
00804     LMatrix4d mat1 = mat;
00805     LMatrix4d inv1 = inv;
00806 
00807     // If we have a translation component, we should only apply
00808     // it to the top matrix.  All subsequent matrices get just the
00809     // rotational component.
00810     mat1.set_row(3, LVector3d(0.0, 0.0, 0.0));
00811     inv1.set_row(3, LVector3d(0.0, 0.0, 0.0));
00812 
00813     internal_set_transform(inv1 * get_transform() * mat);
00814 
00815     EggGroupNode::r_transform(mat1, inv1, to_cs);
00816   } else {
00817     EggGroupNode::r_transform(mat, inv, to_cs);
00818   }
00819 
00820   // Convert the LOD description too.
00821   if (has_lod()) {
00822     _lod->transform(mat);
00823   }
00824   if (has_billboard_center()) {
00825     _billboard_center = _billboard_center * mat;
00826   }
00827 }
00828 
00829 ////////////////////////////////////////////////////////////////////
00830 //     Function: EggGroup::r_flatten_transforms
00831 //       Access: Protected, Virtual
00832 //  Description: The recursive implementation of flatten_transforms().
00833 ////////////////////////////////////////////////////////////////////
00834 void EggGroup::
00835 r_flatten_transforms() {
00836   EggGroupNode::r_flatten_transforms();
00837 
00838   if (is_local_coord()) {
00839     LMatrix4d mat = get_vertex_frame();
00840     if (has_lod()) {
00841       _lod->transform(mat);
00842     }
00843 
00844     if (get_billboard_type() != BT_none && !has_billboard_center()) {
00845       // If we had a billboard without an explicit center, it was an
00846       // implicit instance.  Now it's not any more.
00847       set_billboard_center(LPoint3d(0.0, 0.0, 0.0) * mat);
00848 
00849     } else if (has_billboard_center()) {
00850       _billboard_center = _billboard_center * mat;
00851     }
00852   }
00853 
00854   if (get_group_type() == GT_instance) {
00855     set_group_type(GT_group);
00856   }
00857 
00858   if (get_group_type() != GT_joint) {
00859     internal_clear_transform();
00860   }
00861 }
00862 
00863 
00864 ////////////////////////////////////////////////////////////////////
00865 //     Function: EggGroup::transform_changed
00866 //       Access: Protected, Virtual
00867 //  Description: This virtual method is inherited by EggTransform3d;
00868 //               it is called whenever the transform is changed.
00869 ////////////////////////////////////////////////////////////////////
00870 void EggGroup::
00871 transform_changed() {
00872   // Recompute all of the cached transforms at this node and below.
00873   // We should probably make this smarter and do lazy evaluation of
00874   // these transforms, rather than having to recompute the whole tree
00875   // with every change to a parent node's transform.
00876   update_under(0);
00877 }
00878 
00879 
00880 
00881 ////////////////////////////////////////////////////////////////////
00882 //     Function: GroupType output operator
00883 //  Description:
00884 ////////////////////////////////////////////////////////////////////
00885 ostream &operator << (ostream &out, EggGroup::GroupType t) {
00886   switch (t) {
00887   case EggGroup::GT_invalid:
00888     return out << "invalid group";
00889   case EggGroup::GT_group:
00890     return out << "group";
00891   case EggGroup::GT_instance:
00892     return out << "instance";
00893   case EggGroup::GT_joint:
00894     return out << "joint";
00895   }
00896 
00897   nassertr(false, out);
00898   return out << "(**invalid**)";
00899 }
00900 
00901 ////////////////////////////////////////////////////////////////////
00902 //     Function: DartType output operator
00903 //  Description:
00904 ////////////////////////////////////////////////////////////////////
00905 ostream &operator << (ostream &out, EggGroup::DartType t) {
00906   switch (t) {
00907   case EggGroup::DT_none:
00908     return out << "none";
00909   case EggGroup::DT_sync:
00910     return out << "sync";
00911   case EggGroup::DT_nosync:
00912     return out << "nosync";
00913   case EggGroup::DT_default:
00914     return out << "1";
00915   }
00916 
00917   nassertr(false, out);
00918   return out << "(**invalid**)";
00919 }
00920 
00921 ////////////////////////////////////////////////////////////////////
00922 //     Function: DCSType output operator
00923 //  Description:
00924 ////////////////////////////////////////////////////////////////////
00925 ostream &operator << (ostream &out, EggGroup::DCSType t) {
00926   switch (t) {
00927   case EggGroup::DC_none:
00928     return out << "none";
00929   case EggGroup::DC_local:
00930     return out << "local";
00931   case EggGroup::DC_net:
00932     return out << "net";
00933   case EggGroup::DC_default:
00934     return out << "1";
00935   }
00936 
00937   nassertr(false, out);
00938   return out << "(**invalid**)";
00939 }
00940 
00941 ////////////////////////////////////////////////////////////////////
00942 //     Function: BillboardType output operator
00943 //  Description:
00944 ////////////////////////////////////////////////////////////////////
00945 ostream &operator << (ostream &out, EggGroup::BillboardType t) {
00946   switch (t) {
00947   case EggGroup::BT_none:
00948     return out << "none";
00949   case EggGroup::BT_axis:
00950     return out << "axis";
00951   case EggGroup::BT_point_camera_relative:
00952     return out << "point_eye";
00953   case EggGroup::BT_point_world_relative:
00954     return out << "point_world";
00955   }
00956 
00957   nassertr(false, out);
00958   return out << "(**invalid**)";
00959 }
00960 
00961 ////////////////////////////////////////////////////////////////////
00962 //     Function: CollisionSolidType output operator
00963 //  Description:
00964 ////////////////////////////////////////////////////////////////////
00965 ostream &operator << (ostream &out, EggGroup::CollisionSolidType t) {
00966   switch (t) {
00967   case EggGroup::CST_none:
00968     return out << "None";
00969   case EggGroup::CST_plane:
00970     return out << "Plane";
00971   case EggGroup::CST_polygon:
00972     return out << "Polygon";
00973   case EggGroup::CST_polyset:
00974     return out << "Polyset";
00975   case EggGroup::CST_sphere:
00976     return out << "Sphere";
00977   case EggGroup::CST_inverse_sphere:
00978     return out << "InverseSphere";
00979   case EggGroup::CST_geode:
00980     return out << "Geode";
00981   }
00982 
00983   nassertr(false, out);
00984   return out << "(**invalid**)";
00985 }
00986 
00987 ////////////////////////////////////////////////////////////////////
00988 //     Function: CollideFlags output operator
00989 //  Description:
00990 ////////////////////////////////////////////////////////////////////
00991 ostream &operator << (ostream &out, EggGroup::CollideFlags t) {
00992   if (t == EggGroup::CF_none) {
00993     return out << "none";
00994   }
00995   int bits = (int)t;
00996   const char *space = "";
00997 
00998   if (bits & EggGroup::CF_intangible) {
00999     out << space << "intangible";
01000     space = " ";
01001   }
01002   if (bits & EggGroup::CF_event) {
01003     out << space << "event";
01004     space = " ";
01005   }
01006   if (bits & EggGroup::CF_descend) {
01007     out << space << "descend";
01008     space = " ";
01009   }
01010   if (bits & EggGroup::CF_keep) {
01011     out << space << "keep";
01012     space = " ";
01013   }
01014   if (bits & EggGroup::CF_solid) {
01015     out << space << "solid";
01016     space = " ";
01017   }
01018   if (bits & EggGroup::CF_center) {
01019     out << space << "center";
01020     space = " ";
01021   }
01022   if (bits & EggGroup::CF_turnstile) {
01023     out << space << "turnstile";
01024     space = " ";
01025   }
01026   return out;
01027 }

Generated on Fri May 2 00:37:36 2003 for Panda by doxygen1.3