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