Panda3D
 All Classes Functions Variables Enumerations
collisionVisualizer.cxx
1 // Filename: collisionVisualizer.cxx
2 // Created by: drose (16Apr03)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "collisionVisualizer.h"
16 #include "collisionEntry.h"
17 #include "cullTraverser.h"
18 #include "cullTraverserData.h"
19 #include "cullableObject.h"
20 #include "cullHandler.h"
21 #include "renderState.h"
22 #include "renderModeAttrib.h"
23 #include "geomVertexData.h"
24 #include "geomVertexFormat.h"
25 #include "geomVertexArrayFormat.h"
26 #include "geom.h"
27 #include "geomPoints.h"
28 #include "geomLines.h"
29 #include "omniBoundingVolume.h"
30 #include "depthOffsetAttrib.h"
31 #include "colorScaleAttrib.h"
32 #include "transparencyAttrib.h"
33 #include "clipPlaneAttrib.h"
34 #include "geomVertexWriter.h"
35 
36 
37 #ifdef DO_COLLISION_RECORDING
38 
39 TypeHandle CollisionVisualizer::_type_handle;
40 
41 ////////////////////////////////////////////////////////////////////
42 // Function: CollisionVisualizer::Constructor
43 // Access: Published
44 // Description:
45 ////////////////////////////////////////////////////////////////////
46 CollisionVisualizer::
47 CollisionVisualizer(const string &name) : PandaNode(name) {
48  set_cull_callback();
49 
50  // We always want to render the CollisionVisualizer node itself
51  // (even if it doesn't appear to have any geometry within it).
52  set_internal_bounds(new OmniBoundingVolume());
53  _point_scale = 1.0f;
54  _normal_scale = 1.0f;
55 }
56 
57 ////////////////////////////////////////////////////////////////////
58 // Function: CollisionVisualizer::Destructor
59 // Access: Published, Virtual
60 // Description:
61 ////////////////////////////////////////////////////////////////////
62 CollisionVisualizer::
63 ~CollisionVisualizer() {
64 }
65 
66 ////////////////////////////////////////////////////////////////////
67 // Function: CollisionVisualizer::clear
68 // Access: Published
69 // Description: Removes all the visualization data from a previous
70 // traversal and resets the visualizer to empty.
71 ////////////////////////////////////////////////////////////////////
72 void CollisionVisualizer::
73 clear() {
74  _data.clear();
75 }
76 
77 ////////////////////////////////////////////////////////////////////
78 // Function: CollisionVisualizer::make_copy
79 // Access: Public, Virtual
80 // Description: Returns a newly-allocated Node that is a shallow copy
81 // of this one. It will be a different Node pointer,
82 // but its internal data may or may not be shared with
83 // that of the original Node.
84 ////////////////////////////////////////////////////////////////////
85 PandaNode *CollisionVisualizer::
86 make_copy() const {
87  return new CollisionVisualizer(*this);
88 }
89 
90 ////////////////////////////////////////////////////////////////////
91 // Function: CollisionVisualizer::cull_callback
92 // Access: Public, Virtual
93 // Description: This function will be called during the cull
94 // traversal to perform any additional operations that
95 // should be performed at cull time. This may include
96 // additional manipulation of render state or additional
97 // visible/invisible decisions, or any other arbitrary
98 // operation.
99 //
100 // Note that this function will *not* be called unless
101 // set_cull_callback() is called in the constructor of
102 // the derived class. It is necessary to call
103 // set_cull_callback() to indicated that we require
104 // cull_callback() to be called.
105 //
106 // By the time this function is called, the node has
107 // already passed the bounding-volume test for the
108 // viewing frustum, and the node's transform and state
109 // have already been applied to the indicated
110 // CullTraverserData object.
111 //
112 // The return value is true if this node should be
113 // visible, or false if it should be culled.
114 ////////////////////////////////////////////////////////////////////
115 bool CollisionVisualizer::
116 cull_callback(CullTraverser *trav, CullTraverserData &data) {
117  // Now we go through and actually draw our visualized collision solids.
118 
119  Data::const_iterator di;
120  for (di = _data.begin(); di != _data.end(); ++di) {
121  const TransformState *net_transform = (*di).first;
122  const VizInfo &viz_info = (*di).second;
123 
124  CullTraverserData xform_data(data);
125 
126  // We don't want to inherit the transform from above! We ignore
127  // whatever transforms were above the CollisionVisualizer node; it
128  // always renders its objects according to their appropriate net
129  // transform.
130  xform_data._net_transform = TransformState::make_identity();
131  xform_data._view_frustum = trav->get_view_frustum();
132  xform_data.apply_transform_and_state(trav, net_transform,
133  RenderState::make_empty(),
134  RenderEffects::make_empty(),
135  ClipPlaneAttrib::make());
136 
137  // Draw all the collision solids.
138  Solids::const_iterator si;
139  for (si = viz_info._solids.begin(); si != viz_info._solids.end(); ++si) {
140  // Note that we don't preserve the clip plane attribute from the
141  // collision solid. We always draw the whole polygon (or
142  // whatever) in the CollisionVisualizer. This is a deliberate
143  // decision; clipping the polygons may obscure many collision
144  // tests that are being made.
145  const CollisionSolid *solid = (*si).first;
146  const SolidInfo &solid_info = (*si).second;
147  bool was_detected = (solid_info._detected_count > 0);
148  PT(PandaNode) node = solid->get_viz(trav, xform_data, !was_detected);
149  if (node != (PandaNode *)NULL) {
150  CullTraverserData next_data(xform_data, node);
151 
152  // We don't want to inherit the render state from above for
153  // these guys.
154  next_data._state = get_viz_state();
155  trav->traverse(next_data);
156  }
157  }
158 
159  // Now draw all of the detected points.
160  if (!viz_info._points.empty()) {
161  CPT(RenderState) empty_state = RenderState::make_empty();
162  CPT(RenderState) point_state = RenderState::make(RenderModeAttrib::make(RenderModeAttrib::M_unchanged, 1.0f, false));
163 
164  PT(GeomVertexArrayFormat) point_array_format =
165  new GeomVertexArrayFormat(InternalName::get_vertex(), 3,
166  Geom::NT_stdfloat, Geom::C_point,
167  InternalName::get_color(), 1,
168  Geom::NT_packed_dabc, Geom::C_color,
169  InternalName::get_size(), 1,
170  Geom::NT_stdfloat, Geom::C_other);
171  CPT(GeomVertexFormat) point_format =
172  GeomVertexFormat::register_format(point_array_format);
173 
174  Points::const_iterator pi;
175  for (pi = viz_info._points.begin(); pi != viz_info._points.end(); ++pi) {
176  const CollisionPoint &point = (*pi);
177 
178  // Draw a small red point at the surface point, and a smaller
179  // white point at the interior point.
180  {
181  PT(GeomVertexData) point_vdata =
182  new GeomVertexData("viz", point_format, Geom::UH_stream);
183 
184  PT(GeomPoints) points = new GeomPoints(Geom::UH_stream);
185 
186  GeomVertexWriter vertex(point_vdata, InternalName::get_vertex());
187  GeomVertexWriter color(point_vdata, InternalName::get_color());
188  GeomVertexWriter size(point_vdata, InternalName::get_size());
189 
190  vertex.add_data3(point._surface_point);
191  color.add_data4(1.0f, 0.0f, 0.0f, 1.0f);
192  size.add_data1f(16.0f * _point_scale);
193  points->add_next_vertices(1);
194  points->close_primitive();
195 
196  if (point._interior_point != point._surface_point) {
197  vertex.add_data3(point._interior_point);
198  color.add_data4(1.0f, 1.0f, 1.0f, 1.0f);
199  size.add_data1f(8.0f * _point_scale);
200  points->add_next_vertices(1);
201  points->close_primitive();
202  }
203 
204  PT(Geom) geom = new Geom(point_vdata);
205  geom->add_primitive(points);
206 
207  CullableObject *object =
208  new CullableObject(geom, point_state,
209  xform_data.get_internal_transform(trav));
210 
211  trav->get_cull_handler()->record_object(object, trav);
212  }
213 
214  // Draw the normal vector at the surface point.
215  if (!point._surface_normal.almost_equal(LVector3::zero())) {
216  PT(GeomVertexData) line_vdata =
217  new GeomVertexData("viz", GeomVertexFormat::get_v3cp(),
218  Geom::UH_stream);
219 
220  PT(GeomLines) lines = new GeomLines(Geom::UH_stream);
221 
222  GeomVertexWriter vertex(line_vdata, InternalName::get_vertex());
223  GeomVertexWriter color(line_vdata, InternalName::get_color());
224 
225  vertex.add_data3(point._surface_point);
226  vertex.add_data3(point._surface_point +
227  point._surface_normal * _normal_scale);
228  color.add_data4(1.0f, 0.0f, 0.0f, 1.0f);
229  color.add_data4(1.0f, 1.0f, 1.0f, 1.0f);
230  lines->add_next_vertices(2);
231  lines->close_primitive();
232 
233  PT(Geom) geom = new Geom(line_vdata);
234  geom->add_primitive(lines);
235 
236  CullableObject *object =
237  new CullableObject(geom, empty_state,
238  xform_data.get_internal_transform(trav));
239 
240  trav->get_cull_handler()->record_object(object, trav);
241  }
242  }
243  }
244  }
245 
246  // Now carry on to render our child nodes.
247  return true;
248 }
249 
250 ////////////////////////////////////////////////////////////////////
251 // Function: CollisionVisualizer::is_renderable
252 // Access: Public, Virtual
253 // Description: Returns true if there is some value to visiting this
254 // particular node during the cull traversal for any
255 // camera, false otherwise. This will be used to
256 // optimize the result of get_net_draw_show_mask(), so
257 // that any subtrees that contain only nodes for which
258 // is_renderable() is false need not be visited.
259 ////////////////////////////////////////////////////////////////////
260 bool CollisionVisualizer::
261 is_renderable() const {
262  return true;
263 }
264 
265 
266 ////////////////////////////////////////////////////////////////////
267 // Function: CollisionVisualizer::output
268 // Access: Public, Virtual
269 // Description: Writes a brief description of the node to the
270 // indicated output stream. This is invoked by the <<
271 // operator. It may be overridden in derived classes to
272 // include some information relevant to the class.
273 ////////////////////////////////////////////////////////////////////
274 void CollisionVisualizer::
275 output(ostream &out) const {
276  PandaNode::output(out);
277  out << " ";
278  CollisionRecorder::output(out);
279 }
280 
281 ////////////////////////////////////////////////////////////////////
282 // Function: CollisionVisualizer::begin_traversal
283 // Access: Public, Virtual
284 // Description: This method is called at the beginning of a
285 // CollisionTraverser::traverse() call. It is provided
286 // as a hook for the derived class to reset its state as
287 // appropriate.
288 ////////////////////////////////////////////////////////////////////
289 void CollisionVisualizer::
290 begin_traversal() {
291  CollisionRecorder::begin_traversal();
292  _data.clear();
293 }
294 
295 ////////////////////////////////////////////////////////////////////
296 // Function: CollisionVisualizer::collision_tested
297 // Access: Public, Virtual
298 // Description: This method is called when a pair of collision solids
299 // have passed all bounding-volume tests and have been
300 // tested for a collision. The detected value is set
301 // true if a collision was detected, false otherwise.
302 ////////////////////////////////////////////////////////////////////
303 void CollisionVisualizer::
304 collision_tested(const CollisionEntry &entry, bool detected) {
305  CollisionRecorder::collision_tested(entry, detected);
306 
307  NodePath node_path = entry.get_into_node_path();
308  CPT(TransformState) net_transform = node_path.get_net_transform();
309  const CollisionSolid *solid = entry.get_into();
310  nassertv(solid != (CollisionSolid *)NULL);
311 
312  VizInfo &viz_info = _data[net_transform];
313  if (detected) {
314  viz_info._solids[solid]._detected_count++;
315 
316  if (entry.has_surface_point()) {
317  CollisionPoint p;
318  entry.get_all(entry.get_into_node_path(),
319  p._surface_point, p._surface_normal, p._interior_point);
320  viz_info._points.push_back(p);
321  }
322 
323  } else {
324  viz_info._solids[solid]._missed_count++;
325  }
326 }
327 
328 
329 ////////////////////////////////////////////////////////////////////
330 // Function: CollisionVisualizer::get_viz_state
331 // Access: Private
332 // Description: Returns a RenderState suitable for rendering the
333 // collision solids with which a collision was detected.
334 ////////////////////////////////////////////////////////////////////
335 CPT(RenderState) CollisionVisualizer::
336 get_viz_state() {
337  // Once someone asks for this pointer, we hold its reference count
338  // and never free it.
339  static CPT(RenderState) state = (const RenderState *)NULL;
340  if (state == (const RenderState *)NULL) {
341  state = RenderState::make
342  (DepthOffsetAttrib::make());
343  }
344 
345  return state;
346 }
347 
348 #endif // DO_COLLISION_RECORDING
A basic node of the scene graph or data graph.
Definition: pandaNode.h:72
This object provides a high-level interface for quickly writing a sequence of numeric values from a v...
Defines a series of disconnected points.
Definition: geomPoints.h:25
The abstract base class for all things that can collide with other things in the world, and all the things they can collide with (except geometry).
This collects together the pieces of data that are accumulated for each node while walking the scene ...
This is a three-component vector distance (as opposed to a three-component point, which represents a ...
Definition: lvector3.h:100
The smallest atom of cull.
Defines a single collision event.
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
A container for geometry primitives.
Definition: geom.h:58
bool has_surface_point() const
Returns true if the surface point has been specified, false otherwise.
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition: renderState.h:53
Defines a series of disconnected line segments.
Definition: geomLines.h:25
NodePath get_into_node_path() const
Returns the NodePath that represents the specific CollisionNode or GeomNode instance that was collide...
GeometricBoundingVolume * get_view_frustum() const
Returns the bounding volume that corresponds to the view frustum, or NULL if the view frustum is not ...
Specifies how polygons are to be drawn.
This is a special kind of GeometricBoundingVolume that fills all of space.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:165
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling...
Definition: cullTraverser.h:48
bool get_all(const NodePath &space, LPoint3 &surface_point, LVector3 &surface_normal, LPoint3 &interior_point) const
Simultaneously transforms the surface point, surface normal, and interior point of the collision into...