Panda3D
 All Classes Functions Variables Enumerations
collisionVisualizer.cxx
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
 All Classes Functions Variables Enumerations