Panda3D
|
00001 // Filename: collisionVisualizer.cxx 00002 // Created by: drose (16Apr03) 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 "collisionVisualizer.h" 00016 #include "collisionEntry.h" 00017 #include "cullTraverser.h" 00018 #include "cullTraverserData.h" 00019 #include "cullableObject.h" 00020 #include "cullHandler.h" 00021 #include "renderState.h" 00022 #include "renderModeAttrib.h" 00023 #include "geomVertexData.h" 00024 #include "geomVertexFormat.h" 00025 #include "geomVertexArrayFormat.h" 00026 #include "geom.h" 00027 #include "geomPoints.h" 00028 #include "geomLines.h" 00029 #include "omniBoundingVolume.h" 00030 #include "depthOffsetAttrib.h" 00031 #include "colorScaleAttrib.h" 00032 #include "transparencyAttrib.h" 00033 #include "clipPlaneAttrib.h" 00034 #include "geomVertexWriter.h" 00035 00036 00037 #ifdef DO_COLLISION_RECORDING 00038 00039 TypeHandle CollisionVisualizer::_type_handle; 00040 00041 //////////////////////////////////////////////////////////////////// 00042 // Function: CollisionVisualizer::Constructor 00043 // Access: Published 00044 // Description: 00045 //////////////////////////////////////////////////////////////////// 00046 CollisionVisualizer:: 00047 CollisionVisualizer(const string &name) : PandaNode(name) { 00048 set_cull_callback(); 00049 00050 // We always want to render the CollisionVisualizer node itself 00051 // (even if it doesn't appear to have any geometry within it). 00052 set_internal_bounds(new OmniBoundingVolume()); 00053 _point_scale = 1.0f; 00054 _normal_scale = 1.0f; 00055 } 00056 00057 //////////////////////////////////////////////////////////////////// 00058 // Function: CollisionVisualizer::Destructor 00059 // Access: Published, Virtual 00060 // Description: 00061 //////////////////////////////////////////////////////////////////// 00062 CollisionVisualizer:: 00063 ~CollisionVisualizer() { 00064 } 00065 00066 //////////////////////////////////////////////////////////////////// 00067 // Function: CollisionVisualizer::clear 00068 // Access: Published 00069 // Description: Removes all the visualization data from a previous 00070 // traversal and resets the visualizer to empty. 00071 //////////////////////////////////////////////////////////////////// 00072 void CollisionVisualizer:: 00073 clear() { 00074 _data.clear(); 00075 } 00076 00077 //////////////////////////////////////////////////////////////////// 00078 // Function: CollisionVisualizer::make_copy 00079 // Access: Public, Virtual 00080 // Description: Returns a newly-allocated Node that is a shallow copy 00081 // of this one. It will be a different Node pointer, 00082 // but its internal data may or may not be shared with 00083 // that of the original Node. 00084 //////////////////////////////////////////////////////////////////// 00085 PandaNode *CollisionVisualizer:: 00086 make_copy() const { 00087 return new CollisionVisualizer(*this); 00088 } 00089 00090 //////////////////////////////////////////////////////////////////// 00091 // Function: CollisionVisualizer::cull_callback 00092 // Access: Public, Virtual 00093 // Description: This function will be called during the cull 00094 // traversal to perform any additional operations that 00095 // should be performed at cull time. This may include 00096 // additional manipulation of render state or additional 00097 // visible/invisible decisions, or any other arbitrary 00098 // operation. 00099 // 00100 // Note that this function will *not* be called unless 00101 // set_cull_callback() is called in the constructor of 00102 // the derived class. It is necessary to call 00103 // set_cull_callback() to indicated that we require 00104 // cull_callback() to be called. 00105 // 00106 // By the time this function is called, the node has 00107 // already passed the bounding-volume test for the 00108 // viewing frustum, and the node's transform and state 00109 // have already been applied to the indicated 00110 // CullTraverserData object. 00111 // 00112 // The return value is true if this node should be 00113 // visible, or false if it should be culled. 00114 //////////////////////////////////////////////////////////////////// 00115 bool CollisionVisualizer:: 00116 cull_callback(CullTraverser *trav, CullTraverserData &data) { 00117 // Now we go through and actually draw our visualized collision solids. 00118 00119 Data::const_iterator di; 00120 for (di = _data.begin(); di != _data.end(); ++di) { 00121 const TransformState *net_transform = (*di).first; 00122 const VizInfo &viz_info = (*di).second; 00123 00124 CullTraverserData xform_data(data); 00125 00126 // We don't want to inherit the transform from above! We ignore 00127 // whatever transforms were above the CollisionVisualizer node; it 00128 // always renders its objects according to their appropriate net 00129 // transform. 00130 xform_data._net_transform = TransformState::make_identity(); 00131 xform_data._view_frustum = trav->get_view_frustum(); 00132 xform_data.apply_transform_and_state(trav, net_transform, 00133 RenderState::make_empty(), 00134 RenderEffects::make_empty(), 00135 ClipPlaneAttrib::make()); 00136 00137 // Draw all the collision solids. 00138 Solids::const_iterator si; 00139 for (si = viz_info._solids.begin(); si != viz_info._solids.end(); ++si) { 00140 // Note that we don't preserve the clip plane attribute from the 00141 // collision solid. We always draw the whole polygon (or 00142 // whatever) in the CollisionVisualizer. This is a deliberate 00143 // decision; clipping the polygons may obscure many collision 00144 // tests that are being made. 00145 const CollisionSolid *solid = (*si).first; 00146 const SolidInfo &solid_info = (*si).second; 00147 bool was_detected = (solid_info._detected_count > 0); 00148 PT(PandaNode) node = solid->get_viz(trav, xform_data, !was_detected); 00149 if (node != (PandaNode *)NULL) { 00150 CullTraverserData next_data(xform_data, node); 00151 00152 // We don't want to inherit the render state from above for 00153 // these guys. 00154 next_data._state = get_viz_state(); 00155 trav->traverse(next_data); 00156 } 00157 } 00158 00159 // Now draw all of the detected points. 00160 if (!viz_info._points.empty()) { 00161 CPT(RenderState) empty_state = RenderState::make_empty(); 00162 CPT(RenderState) point_state = RenderState::make(RenderModeAttrib::make(RenderModeAttrib::M_unchanged, 1.0f, false)); 00163 00164 PT(GeomVertexArrayFormat) point_array_format = 00165 new GeomVertexArrayFormat(InternalName::get_vertex(), 3, 00166 Geom::NT_stdfloat, Geom::C_point, 00167 InternalName::get_color(), 1, 00168 Geom::NT_packed_dabc, Geom::C_color, 00169 InternalName::get_size(), 1, 00170 Geom::NT_stdfloat, Geom::C_other); 00171 CPT(GeomVertexFormat) point_format = 00172 GeomVertexFormat::register_format(point_array_format); 00173 00174 Points::const_iterator pi; 00175 for (pi = viz_info._points.begin(); pi != viz_info._points.end(); ++pi) { 00176 const CollisionPoint &point = (*pi); 00177 00178 // Draw a small red point at the surface point, and a smaller 00179 // white point at the interior point. 00180 { 00181 PT(GeomVertexData) point_vdata = 00182 new GeomVertexData("viz", point_format, Geom::UH_stream); 00183 00184 PT(GeomPoints) points = new GeomPoints(Geom::UH_stream); 00185 00186 GeomVertexWriter vertex(point_vdata, InternalName::get_vertex()); 00187 GeomVertexWriter color(point_vdata, InternalName::get_color()); 00188 GeomVertexWriter size(point_vdata, InternalName::get_size()); 00189 00190 vertex.add_data3(point._surface_point); 00191 color.add_data4(1.0f, 0.0f, 0.0f, 1.0f); 00192 size.add_data1f(16.0f * _point_scale); 00193 points->add_next_vertices(1); 00194 points->close_primitive(); 00195 00196 if (point._interior_point != point._surface_point) { 00197 vertex.add_data3(point._interior_point); 00198 color.add_data4(1.0f, 1.0f, 1.0f, 1.0f); 00199 size.add_data1f(8.0f * _point_scale); 00200 points->add_next_vertices(1); 00201 points->close_primitive(); 00202 } 00203 00204 PT(Geom) geom = new Geom(point_vdata); 00205 geom->add_primitive(points); 00206 00207 CullableObject *object = 00208 new CullableObject(geom, point_state, 00209 xform_data.get_net_transform(trav), 00210 xform_data.get_modelview_transform(trav), 00211 trav->get_gsg()); 00212 00213 trav->get_cull_handler()->record_object(object, trav); 00214 } 00215 00216 // Draw the normal vector at the surface point. 00217 if (!point._surface_normal.almost_equal(LVector3::zero())) { 00218 PT(GeomVertexData) line_vdata = 00219 new GeomVertexData("viz", GeomVertexFormat::get_v3cp(), 00220 Geom::UH_stream); 00221 00222 PT(GeomLines) lines = new GeomLines(Geom::UH_stream); 00223 00224 GeomVertexWriter vertex(line_vdata, InternalName::get_vertex()); 00225 GeomVertexWriter color(line_vdata, InternalName::get_color()); 00226 00227 vertex.add_data3(point._surface_point); 00228 vertex.add_data3(point._surface_point + 00229 point._surface_normal * _normal_scale); 00230 color.add_data4(1.0f, 0.0f, 0.0f, 1.0f); 00231 color.add_data4(1.0f, 1.0f, 1.0f, 1.0f); 00232 lines->add_next_vertices(2); 00233 lines->close_primitive(); 00234 00235 PT(Geom) geom = new Geom(line_vdata); 00236 geom->add_primitive(lines); 00237 00238 CullableObject *object = 00239 new CullableObject(geom, empty_state, 00240 xform_data.get_net_transform(trav), 00241 xform_data.get_modelview_transform(trav), 00242 trav->get_gsg()); 00243 00244 trav->get_cull_handler()->record_object(object, trav); 00245 } 00246 } 00247 } 00248 } 00249 00250 // Now carry on to render our child nodes. 00251 return true; 00252 } 00253 00254 //////////////////////////////////////////////////////////////////// 00255 // Function: CollisionVisualizer::is_renderable 00256 // Access: Public, Virtual 00257 // Description: Returns true if there is some value to visiting this 00258 // particular node during the cull traversal for any 00259 // camera, false otherwise. This will be used to 00260 // optimize the result of get_net_draw_show_mask(), so 00261 // that any subtrees that contain only nodes for which 00262 // is_renderable() is false need not be visited. 00263 //////////////////////////////////////////////////////////////////// 00264 bool CollisionVisualizer:: 00265 is_renderable() const { 00266 return true; 00267 } 00268 00269 00270 //////////////////////////////////////////////////////////////////// 00271 // Function: CollisionVisualizer::output 00272 // Access: Public, Virtual 00273 // Description: Writes a brief description of the node to the 00274 // indicated output stream. This is invoked by the << 00275 // operator. It may be overridden in derived classes to 00276 // include some information relevant to the class. 00277 //////////////////////////////////////////////////////////////////// 00278 void CollisionVisualizer:: 00279 output(ostream &out) const { 00280 PandaNode::output(out); 00281 out << " "; 00282 CollisionRecorder::output(out); 00283 } 00284 00285 //////////////////////////////////////////////////////////////////// 00286 // Function: CollisionVisualizer::begin_traversal 00287 // Access: Public, Virtual 00288 // Description: This method is called at the beginning of a 00289 // CollisionTraverser::traverse() call. It is provided 00290 // as a hook for the derived class to reset its state as 00291 // appropriate. 00292 //////////////////////////////////////////////////////////////////// 00293 void CollisionVisualizer:: 00294 begin_traversal() { 00295 CollisionRecorder::begin_traversal(); 00296 _data.clear(); 00297 } 00298 00299 //////////////////////////////////////////////////////////////////// 00300 // Function: CollisionVisualizer::collision_tested 00301 // Access: Public, Virtual 00302 // Description: This method is called when a pair of collision solids 00303 // have passed all bounding-volume tests and have been 00304 // tested for a collision. The detected value is set 00305 // true if a collision was detected, false otherwise. 00306 //////////////////////////////////////////////////////////////////// 00307 void CollisionVisualizer:: 00308 collision_tested(const CollisionEntry &entry, bool detected) { 00309 CollisionRecorder::collision_tested(entry, detected); 00310 00311 NodePath node_path = entry.get_into_node_path(); 00312 CPT(TransformState) net_transform = node_path.get_net_transform(); 00313 const CollisionSolid *solid = entry.get_into(); 00314 nassertv(solid != (CollisionSolid *)NULL); 00315 00316 VizInfo &viz_info = _data[net_transform]; 00317 if (detected) { 00318 viz_info._solids[solid]._detected_count++; 00319 00320 if (entry.has_surface_point()) { 00321 CollisionPoint p; 00322 entry.get_all(entry.get_into_node_path(), 00323 p._surface_point, p._surface_normal, p._interior_point); 00324 viz_info._points.push_back(p); 00325 } 00326 00327 } else { 00328 viz_info._solids[solid]._missed_count++; 00329 } 00330 } 00331 00332 00333 //////////////////////////////////////////////////////////////////// 00334 // Function: CollisionVisualizer::get_viz_state 00335 // Access: Private 00336 // Description: Returns a RenderState suitable for rendering the 00337 // collision solids with which a collision was detected. 00338 //////////////////////////////////////////////////////////////////// 00339 CPT(RenderState) CollisionVisualizer:: 00340 get_viz_state() { 00341 // Once someone asks for this pointer, we hold its reference count 00342 // and never free it. 00343 static CPT(RenderState) state = (const RenderState *)NULL; 00344 if (state == (const RenderState *)NULL) { 00345 state = RenderState::make 00346 (DepthOffsetAttrib::make()); 00347 } 00348 00349 return state; 00350 } 00351 00352 #endif // DO_COLLISION_RECORDING