00001 // Filename: collisionVisualizer.cxx 00002 // Created by: drose (16Apr03) 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 "collisionVisualizer.h" 00020 #include "collisionEntry.h" 00021 #include "cullTraverser.h" 00022 #include "cullTraverserData.h" 00023 #include "cullableObject.h" 00024 #include "cullHandler.h" 00025 #include "renderState.h" 00026 #include "omniBoundingVolume.h" 00027 #include "depthOffsetAttrib.h" 00028 #include "colorScaleAttrib.h" 00029 #include "transparencyAttrib.h" 00030 00031 00032 #ifdef DO_COLLISION_RECORDING 00033 00034 TypeHandle CollisionVisualizer::_type_handle; 00035 00036 //////////////////////////////////////////////////////////////////// 00037 // Function: CollisionVisualizer::Constructor 00038 // Access: Published 00039 // Description: 00040 //////////////////////////////////////////////////////////////////// 00041 CollisionVisualizer:: 00042 CollisionVisualizer(const string &name) : PandaNode(name) { 00043 // We always want to render the CollisionVisualizer node itself 00044 // (even if it doesn't appear to have any geometry within it). 00045 set_bound(OmniBoundingVolume()); 00046 } 00047 00048 //////////////////////////////////////////////////////////////////// 00049 // Function: CollisionVisualizer::Destructor 00050 // Access: Published, Virtual 00051 // Description: 00052 //////////////////////////////////////////////////////////////////// 00053 CollisionVisualizer:: 00054 ~CollisionVisualizer() { 00055 } 00056 00057 //////////////////////////////////////////////////////////////////// 00058 // Function: CollisionVisualizer::clear 00059 // Access: Published 00060 // Description: Removes all the visualization data from a previous 00061 // traversal and resets the visualizer to empty. 00062 //////////////////////////////////////////////////////////////////// 00063 void CollisionVisualizer:: 00064 clear() { 00065 _data.clear(); 00066 } 00067 00068 //////////////////////////////////////////////////////////////////// 00069 // Function: CollisionVisualizer::make_copy 00070 // Access: Public, Virtual 00071 // Description: Returns a newly-allocated Node that is a shallow copy 00072 // of this one. It will be a different Node pointer, 00073 // but its internal data may or may not be shared with 00074 // that of the original Node. 00075 //////////////////////////////////////////////////////////////////// 00076 PandaNode *CollisionVisualizer:: 00077 make_copy() const { 00078 return new CollisionVisualizer(*this); 00079 } 00080 00081 //////////////////////////////////////////////////////////////////// 00082 // Function: CollisionVisualizer::has_cull_callback 00083 // Access: Public, Virtual 00084 // Description: Should be overridden by derived classes to return 00085 // true if cull_callback() has been defined. Otherwise, 00086 // returns false to indicate cull_callback() does not 00087 // need to be called for this node during the cull 00088 // traversal. 00089 //////////////////////////////////////////////////////////////////// 00090 bool CollisionVisualizer:: 00091 has_cull_callback() const { 00092 return true; 00093 } 00094 00095 //////////////////////////////////////////////////////////////////// 00096 // Function: CollisionVisualizer::cull_callback 00097 // Access: Public, Virtual 00098 // Description: If has_cull_callback() returns true, this function 00099 // will be called during the cull traversal to perform 00100 // any additional operations that should be performed at 00101 // cull time. This may include additional manipulation 00102 // of render state or additional visible/invisible 00103 // decisions, or any other arbitrary operation. 00104 // 00105 // By the time this function is called, the node has 00106 // already passed the bounding-volume test for the 00107 // viewing frustum, and the node's transform and state 00108 // have already been applied to the indicated 00109 // CullTraverserData object. 00110 // 00111 // The return value is true if this node should be 00112 // visible, or false if it should be culled. 00113 //////////////////////////////////////////////////////////////////// 00114 bool CollisionVisualizer:: 00115 cull_callback(CullTraverser *trav, CullTraverserData &data) { 00116 // Now we go through and actually draw our visualized collision solids. 00117 00118 Data::const_iterator di; 00119 for (di = _data.begin(); di != _data.end(); ++di) { 00120 const TransformState *net_transform = (*di).first; 00121 const VizInfo &viz_info = (*di).second; 00122 00123 CullTraverserData xform_data(data); 00124 00125 // We don't want to inherit the transform state! We ignore 00126 // whatever transforms were above the CollisionVisualizer node; it 00127 // always renders its objects according to their appropriate net 00128 // transform. 00129 xform_data._net_transform = TransformState::make_identity(); 00130 xform_data._render_transform = trav->get_render_transform(); 00131 xform_data.apply_transform_and_state(trav, net_transform, 00132 RenderState::make_empty(), 00133 RenderEffects::make_empty()); 00134 00135 // Draw all the collision solids. 00136 Solids::const_iterator si; 00137 for (si = viz_info._solids.begin(); si != viz_info._solids.end(); ++si) { 00138 const CollisionSolid *solid = (*si).first; 00139 const SolidInfo &solid_info = (*si).second; 00140 PandaNode *node = solid->get_viz(); 00141 00142 CullTraverserData next_data(xform_data, node); 00143 00144 // We don't want to inherit the render state from above for 00145 // these guys. Instead, we choose the state according to 00146 // whether a collision was detected or not. 00147 if (solid_info._detected_count > 0) { 00148 next_data._state = get_detected_state(); 00149 } else { 00150 next_data._state = get_tested_state(); 00151 } 00152 00153 trav->traverse(next_data); 00154 } 00155 00156 // Now draw all of the detected points. 00157 if (!viz_info._points.empty()) { 00158 CPT(RenderState) line_state = RenderState::make_empty(); 00159 00160 PTA_Colorf colors; 00161 colors.push_back(Colorf(1.0f, 0.0f, 0.0f, 1.0f)); 00162 colors.push_back(Colorf(1.0f, 1.0f, 1.0f, 1.0f)); 00163 00164 Points::const_iterator pi; 00165 for (pi = viz_info._points.begin(); pi != viz_info._points.end(); ++pi) { 00166 const CollisionPoint &point = (*pi); 00167 PT(GeomLine) line = new GeomLine; 00168 00169 PTA_Vertexf verts; 00170 verts.push_back(point._point); 00171 verts.push_back(point._point + point._normal); 00172 line->set_coords(verts); 00173 line->set_colors(colors, G_PER_VERTEX); 00174 line->set_num_prims(1); 00175 00176 CullableObject *object = 00177 new CullableObject(line, line_state, xform_data._render_transform); 00178 00179 trav->get_cull_handler()->record_object(object); 00180 } 00181 } 00182 00183 } 00184 00185 // Now carry on to render our child nodes. 00186 return true; 00187 } 00188 00189 00190 //////////////////////////////////////////////////////////////////// 00191 // Function: CollisionVisualizer::output 00192 // Access: Public, Virtual 00193 // Description: Writes a brief description of the node to the 00194 // indicated output stream. This is invoked by the << 00195 // operator. It may be overridden in derived classes to 00196 // include some information relevant to the class. 00197 //////////////////////////////////////////////////////////////////// 00198 void CollisionVisualizer:: 00199 output(ostream &out) const { 00200 PandaNode::output(out); 00201 out << " "; 00202 CollisionRecorder::output(out); 00203 } 00204 00205 //////////////////////////////////////////////////////////////////// 00206 // Function: CollisionVisualizer::begin_traversal 00207 // Access: Public, Virtual 00208 // Description: This method is called at the beginning of a 00209 // CollisionTraverser::traverse() call. It is provided 00210 // as a hook for the derived class to reset its state as 00211 // appropriate. 00212 //////////////////////////////////////////////////////////////////// 00213 void CollisionVisualizer:: 00214 begin_traversal() { 00215 CollisionRecorder::begin_traversal(); 00216 _data.clear(); 00217 } 00218 00219 //////////////////////////////////////////////////////////////////// 00220 // Function: CollisionVisualizer::collision_tested 00221 // Access: Public, Virtual 00222 // Description: This method is called when a pair of collision solids 00223 // have passed all bounding-volume tests and have been 00224 // tested for a collision. The detected value is set 00225 // true if a collision was detected, false otherwise. 00226 //////////////////////////////////////////////////////////////////// 00227 void CollisionVisualizer:: 00228 collision_tested(const CollisionEntry &entry, bool detected) { 00229 CollisionRecorder::collision_tested(entry, detected); 00230 00231 VizInfo &viz_info = _data[entry.get_into_node_path().get_net_transform()]; 00232 if (detected) { 00233 viz_info._solids[entry.get_into()]._detected_count++; 00234 00235 if (entry.has_into_intersection_point() && 00236 entry.has_into_surface_normal()) { 00237 CollisionPoint p; 00238 p._point = entry.get_into_intersection_point(); 00239 p._normal = entry.get_into_surface_normal(); 00240 viz_info._points.push_back(p); 00241 } 00242 00243 } else { 00244 viz_info._solids[entry.get_into()]._missed_count++; 00245 } 00246 } 00247 00248 00249 //////////////////////////////////////////////////////////////////// 00250 // Function: CollisionVisualizer::get_detected_state 00251 // Access: Private 00252 // Description: Returns a RenderState suitable for rendering the 00253 // collision solids with which a collision was detected. 00254 //////////////////////////////////////////////////////////////////// 00255 CPT(RenderState) CollisionVisualizer:: 00256 get_detected_state() { 00257 // Once someone asks for this pointer, we hold its reference count 00258 // and never free it. 00259 static CPT(RenderState) state = (const RenderState *)NULL; 00260 if (state == (const RenderState *)NULL) { 00261 state = RenderState::make 00262 (DepthOffsetAttrib::make()); 00263 } 00264 00265 return state; 00266 } 00267 00268 //////////////////////////////////////////////////////////////////// 00269 // Function: CollisionVisualizer::get_tested_state 00270 // Access: Private 00271 // Description: Returns a RenderState suitable for rendering the 00272 // collision solids with which a collision was tested, 00273 // but no collision was detected.. 00274 //////////////////////////////////////////////////////////////////// 00275 CPT(RenderState) CollisionVisualizer:: 00276 get_tested_state() { 00277 // Once someone asks for this pointer, we hold its reference count 00278 // and never free it. 00279 static CPT(RenderState) state = (const RenderState *)NULL; 00280 if (state == (const RenderState *)NULL) { 00281 state = RenderState::make 00282 (ColorScaleAttrib::make(LVecBase4f(1.0f, 1.0f, 0.5f, 0.5f)), 00283 DepthOffsetAttrib::make()); 00284 state = state->add_attrib 00285 (TransparencyAttrib::make(TransparencyAttrib::M_alpha), 1); 00286 } 00287 00288 return state; 00289 } 00290 00291 #endif // DO_COLLISION_RECORDING