00001 // Filename: collisionLevelState.cxx 00002 // Created by: drose (16Mar02) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved 00008 // 00009 // All use of this software is subject to the terms of the Panda 3d 00010 // Software license. You should have received a copy of this license 00011 // along with this source code; you will also find a current copy of 00012 // the license at http://www.panda3d.org/license.txt . 00013 // 00014 // To contact the maintainers of this program write to 00015 // panda3d@yahoogroups.com . 00016 // 00017 //////////////////////////////////////////////////////////////////// 00018 00019 #include "collisionLevelState.h" 00020 #include "collisionSolid.h" 00021 #include "dcast.h" 00022 00023 //////////////////////////////////////////////////////////////////// 00024 // Function: CollisionLevelState::clear 00025 // Access: Public 00026 // Description: 00027 //////////////////////////////////////////////////////////////////// 00028 void CollisionLevelState:: 00029 clear() { 00030 _colliders.clear(); 00031 _local_bounds.clear(); 00032 _parent_bounds.clear(); 00033 _current = 0; 00034 _colliders_with_geom = 0; 00035 } 00036 00037 //////////////////////////////////////////////////////////////////// 00038 // Function: CollisionLevelState::reserve 00039 // Access: Public 00040 // Description: 00041 //////////////////////////////////////////////////////////////////// 00042 void CollisionLevelState:: 00043 reserve(int max_colliders) { 00044 _colliders.reserve(max_colliders); 00045 _local_bounds.reserve(max_colliders); 00046 } 00047 00048 //////////////////////////////////////////////////////////////////// 00049 // Function: CollisionLevelState::prepare_collider 00050 // Access: Public 00051 // Description: Adds the indicated Collider to the set of Colliders 00052 // in the current level state. 00053 //////////////////////////////////////////////////////////////////// 00054 void CollisionLevelState:: 00055 prepare_collider(const ColliderDef &def) { 00056 int index = (int)_colliders.size(); 00057 _colliders.push_back(def); 00058 00059 CollisionSolid *collider = def._collider; 00060 const BoundingVolume &bv = collider->get_bound(); 00061 if (!bv.is_of_type(GeometricBoundingVolume::get_class_type())) { 00062 _local_bounds.push_back((GeometricBoundingVolume *)NULL); 00063 } else { 00064 GeometricBoundingVolume *gbv; 00065 DCAST_INTO_V(gbv, bv.make_copy()); 00066 00067 if (def._node->has_velocity()) { 00068 // If the node has a velocity, we have to include the starting 00069 // point in the volume as well. 00070 00071 // Strictly speaking, we should actually transform gbv backward 00072 // by get_velocity(), and extend by *that* volume, instead of 00073 // just extending by the single point at -get_velocity(). 00074 // However, assuming the solids within a moving CollisionNode 00075 // tend to be near the origin, this will generally produce the 00076 // same results, and is much easier to compute. 00077 gbv->extend_by(LPoint3f(-def._node->get_velocity())); 00078 } 00079 00080 gbv->xform(def._space); 00081 _local_bounds.push_back(gbv); 00082 } 00083 00084 _current |= get_mask(index); 00085 00086 if (def._node->get_collide_geom()) { 00087 _colliders_with_geom |= get_mask(index); 00088 } 00089 _parent_bounds = _local_bounds; 00090 } 00091 00092 //////////////////////////////////////////////////////////////////// 00093 // Function: CollisionLevelState::any_in_bounds 00094 // Access: Public 00095 // Description: Checks the bounding volume of the current node 00096 // against each of our colliders. Eliminates from the 00097 // current collider list any that are outside of the 00098 // bounding volume. Returns true if any colliders 00099 // remain, false if all of them fall outside this node's 00100 // bounding volume. 00101 //////////////////////////////////////////////////////////////////// 00102 bool CollisionLevelState:: 00103 any_in_bounds() { 00104 #ifndef NDEBUG 00105 int indent_level = 0; 00106 if (collide_cat.is_spam()) { 00107 indent_level = _node_path.get_num_nodes() * 2; 00108 collide_cat.spam(); 00109 indent(collide_cat.spam(false), indent_level) 00110 << "Considering " << _node_path.get_node_path() << "\n"; 00111 } 00112 #endif // NDEBUG 00113 00114 const BoundingVolume &node_bv = node()->get_bound(); 00115 if (node_bv.is_of_type(GeometricBoundingVolume::get_class_type())) { 00116 const GeometricBoundingVolume *node_gbv; 00117 DCAST_INTO_R(node_gbv, &node_bv, false); 00118 00119 int num_colliders = get_num_colliders(); 00120 for (int c = 0; c < num_colliders; c++) { 00121 if (has_collider(c)) { 00122 CollisionNode *collider = get_node(c); 00123 bool is_in = false; 00124 00125 // Don't even bother testing the bounding volume if there are 00126 // no collide bits in common between our collider and this 00127 // node. 00128 CollideMask from_mask = collider->get_from_collide_mask(); 00129 if (collider->get_collide_geom() || 00130 (from_mask & node()->get_net_collide_mask()) != 0) { 00131 // There are bits in common, so go ahead and try the 00132 // bounding volume. 00133 const GeometricBoundingVolume *col_gbv = 00134 get_local_bound(c); 00135 if (col_gbv != (GeometricBoundingVolume *)NULL) { 00136 is_in = (node_gbv->contains(col_gbv) != 0); 00137 00138 #ifndef NDEBUG 00139 if (collide_cat.is_spam()) { 00140 collide_cat.spam(); 00141 indent(collide_cat.spam(false), indent_level) 00142 << "Comparing " << c << ": " << *col_gbv 00143 << " to " << *node_gbv << ", is_in = " << is_in << "\n"; 00144 } 00145 #endif // NDEBUG 00146 } 00147 } 00148 00149 if (!is_in) { 00150 // This collider cannot intersect with any geometry at 00151 // this node or below. 00152 omit_collider(c); 00153 } 00154 } 00155 } 00156 } 00157 00158 #ifndef NDEBUG 00159 if (collide_cat.is_spam()) { 00160 int num_active_colliders = 0; 00161 int num_colliders = get_num_colliders(); 00162 for (int c = 0; c < num_colliders; c++) { 00163 if (has_collider(c)) { 00164 num_active_colliders++; 00165 } 00166 } 00167 00168 collide_cat.spam(); 00169 indent(collide_cat.spam(false), indent_level) 00170 << _node_path.get_node_path() << " has " << num_active_colliders 00171 << " interested colliders.\n"; 00172 } 00173 #endif // NDEBUG 00174 return has_any_collider(); 00175 } 00176 00177 //////////////////////////////////////////////////////////////////// 00178 // Function: CollisionLevelState::apply_transform 00179 // Access: Public 00180 // Description: Applies the inverse transform from the current node, 00181 // if any, onto all the colliders in the level state. 00182 //////////////////////////////////////////////////////////////////// 00183 void CollisionLevelState:: 00184 apply_transform() { 00185 // The "parent" bounds list remembers the bounds list of the 00186 // previous node. 00187 _parent_bounds = _local_bounds; 00188 00189 // Recompute the bounds list of this node (if we have a transform). 00190 const TransformState *node_transform = node()->get_transform(); 00191 if (!node_transform->is_identity()) { 00192 CPT(TransformState) inv_transform = 00193 node_transform->invert_compose(TransformState::make_identity()); 00194 const LMatrix4f &mat = inv_transform->get_mat(); 00195 00196 // Now build the new bounding volumes list. 00197 BoundingVolumes new_bounds; 00198 00199 int num_colliders = get_num_colliders(); 00200 new_bounds.reserve(num_colliders); 00201 for (int c = 0; c < num_colliders; c++) { 00202 if (!has_collider(c) || 00203 get_local_bound(c) == (GeometricBoundingVolume *)NULL) { 00204 new_bounds.push_back((GeometricBoundingVolume *)NULL); 00205 } else { 00206 const GeometricBoundingVolume *old_bound = get_local_bound(c); 00207 GeometricBoundingVolume *new_bound = 00208 DCAST(GeometricBoundingVolume, old_bound->make_copy()); 00209 new_bound->xform(mat); 00210 new_bounds.push_back(new_bound); 00211 } 00212 } 00213 00214 _local_bounds = new_bounds; 00215 } 00216 }