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