collisionVisualizer.cxx 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. /**
  2. * PANDA 3D SOFTWARE
  3. * Copyright (c) Carnegie Mellon University. All rights reserved.
  4. *
  5. * All use of this software is subject to the terms of the revised BSD
  6. * license. You should have received a copy of this license along
  7. * with this source code in a file named "LICENSE."
  8. *
  9. * @file collisionVisualizer.cxx
  10. * @author drose
  11. * @date 2003-04-16
  12. */
  13. #include "collisionVisualizer.h"
  14. #include "collisionEntry.h"
  15. #include "cullTraverser.h"
  16. #include "cullTraverserData.h"
  17. #include "cullableObject.h"
  18. #include "cullHandler.h"
  19. #include "renderState.h"
  20. #include "renderModeAttrib.h"
  21. #include "geomVertexData.h"
  22. #include "geomVertexFormat.h"
  23. #include "geomVertexArrayFormat.h"
  24. #include "geom.h"
  25. #include "geomPoints.h"
  26. #include "geomLines.h"
  27. #include "omniBoundingVolume.h"
  28. #include "depthOffsetAttrib.h"
  29. #include "colorScaleAttrib.h"
  30. #include "transparencyAttrib.h"
  31. #include "clipPlaneAttrib.h"
  32. #include "geomVertexWriter.h"
  33. #ifdef DO_COLLISION_RECORDING
  34. TypeHandle CollisionVisualizer::_type_handle;
  35. /**
  36. *
  37. */
  38. CollisionVisualizer::
  39. CollisionVisualizer(const string &name) : PandaNode(name) {
  40. set_cull_callback();
  41. // We always want to render the CollisionVisualizer node itself (even if it
  42. // doesn't appear to have any geometry within it).
  43. set_internal_bounds(new OmniBoundingVolume());
  44. _point_scale = 1.0f;
  45. _normal_scale = 1.0f;
  46. }
  47. /**
  48. *
  49. */
  50. CollisionVisualizer::
  51. ~CollisionVisualizer() {
  52. }
  53. /**
  54. * Removes all the visualization data from a previous traversal and resets the
  55. * visualizer to empty.
  56. */
  57. void CollisionVisualizer::
  58. clear() {
  59. _data.clear();
  60. }
  61. /**
  62. * Returns a newly-allocated Node that is a shallow copy of this one. It will
  63. * be a different Node pointer, but its internal data may or may not be shared
  64. * with that of the original Node.
  65. */
  66. PandaNode *CollisionVisualizer::
  67. make_copy() const {
  68. return new CollisionVisualizer(*this);
  69. }
  70. /**
  71. * This function will be called during the cull traversal to perform any
  72. * additional operations that should be performed at cull time. This may
  73. * include additional manipulation of render state or additional
  74. * visible/invisible decisions, or any other arbitrary operation.
  75. *
  76. * Note that this function will *not* be called unless set_cull_callback() is
  77. * called in the constructor of the derived class. It is necessary to call
  78. * set_cull_callback() to indicated that we require cull_callback() to be
  79. * called.
  80. *
  81. * By the time this function is called, the node has already passed the
  82. * bounding-volume test for the viewing frustum, and the node's transform and
  83. * state have already been applied to the indicated CullTraverserData object.
  84. *
  85. * The return value is true if this node should be visible, or false if it
  86. * should be culled.
  87. */
  88. bool CollisionVisualizer::
  89. cull_callback(CullTraverser *trav, CullTraverserData &data) {
  90. // Now we go through and actually draw our visualized collision solids.
  91. Data::const_iterator di;
  92. for (di = _data.begin(); di != _data.end(); ++di) {
  93. const TransformState *net_transform = (*di).first;
  94. const VizInfo &viz_info = (*di).second;
  95. CullTraverserData xform_data(data);
  96. // We don't want to inherit the transform from above! We ignore whatever
  97. // transforms were above the CollisionVisualizer node; it always renders
  98. // its objects according to their appropriate net transform.
  99. xform_data._net_transform = TransformState::make_identity();
  100. xform_data._view_frustum = trav->get_view_frustum();
  101. xform_data.apply_transform(net_transform);
  102. // Draw all the collision solids.
  103. Solids::const_iterator si;
  104. for (si = viz_info._solids.begin(); si != viz_info._solids.end(); ++si) {
  105. // Note that we don't preserve the clip plane attribute from the
  106. // collision solid. We always draw the whole polygon (or whatever) in
  107. // the CollisionVisualizer. This is a deliberate decision; clipping the
  108. // polygons may obscure many collision tests that are being made.
  109. const CollisionSolid *solid = (*si).first;
  110. const SolidInfo &solid_info = (*si).second;
  111. bool was_detected = (solid_info._detected_count > 0);
  112. PT(PandaNode) node = solid->get_viz(trav, xform_data, !was_detected);
  113. if (node != (PandaNode *)NULL) {
  114. CullTraverserData next_data(xform_data, node);
  115. // We don't want to inherit the render state from above for these
  116. // guys.
  117. next_data._state = get_viz_state();
  118. trav->traverse(next_data);
  119. }
  120. }
  121. // Now draw all of the detected points.
  122. if (!viz_info._points.empty()) {
  123. CPT(RenderState) empty_state = RenderState::make_empty();
  124. CPT(RenderState) point_state = RenderState::make(RenderModeAttrib::make(RenderModeAttrib::M_unchanged, 1.0f, false));
  125. PT(GeomVertexArrayFormat) point_array_format =
  126. new GeomVertexArrayFormat(InternalName::get_vertex(), 3,
  127. Geom::NT_stdfloat, Geom::C_point,
  128. InternalName::get_color(), 1,
  129. Geom::NT_packed_dabc, Geom::C_color,
  130. InternalName::get_size(), 1,
  131. Geom::NT_stdfloat, Geom::C_other);
  132. CPT(GeomVertexFormat) point_format =
  133. GeomVertexFormat::register_format(point_array_format);
  134. Points::const_iterator pi;
  135. for (pi = viz_info._points.begin(); pi != viz_info._points.end(); ++pi) {
  136. const CollisionPoint &point = (*pi);
  137. // Draw a small red point at the surface point, and a smaller white
  138. // point at the interior point.
  139. {
  140. PT(GeomVertexData) point_vdata =
  141. new GeomVertexData("viz", point_format, Geom::UH_stream);
  142. PT(GeomPoints) points = new GeomPoints(Geom::UH_stream);
  143. GeomVertexWriter vertex(point_vdata, InternalName::get_vertex());
  144. GeomVertexWriter color(point_vdata, InternalName::get_color());
  145. GeomVertexWriter size(point_vdata, InternalName::get_size());
  146. vertex.add_data3(point._surface_point);
  147. color.add_data4(1.0f, 0.0f, 0.0f, 1.0f);
  148. size.add_data1f(16.0f * _point_scale);
  149. points->add_next_vertices(1);
  150. points->close_primitive();
  151. if (point._interior_point != point._surface_point) {
  152. vertex.add_data3(point._interior_point);
  153. color.add_data4(1.0f, 1.0f, 1.0f, 1.0f);
  154. size.add_data1f(8.0f * _point_scale);
  155. points->add_next_vertices(1);
  156. points->close_primitive();
  157. }
  158. PT(Geom) geom = new Geom(point_vdata);
  159. geom->add_primitive(points);
  160. CullableObject *object =
  161. new CullableObject(geom, point_state,
  162. xform_data.get_internal_transform(trav));
  163. trav->get_cull_handler()->record_object(object, trav);
  164. }
  165. // Draw the normal vector at the surface point.
  166. if (!point._surface_normal.almost_equal(LVector3::zero())) {
  167. PT(GeomVertexData) line_vdata =
  168. new GeomVertexData("viz", GeomVertexFormat::get_v3cp(),
  169. Geom::UH_stream);
  170. PT(GeomLines) lines = new GeomLines(Geom::UH_stream);
  171. GeomVertexWriter vertex(line_vdata, InternalName::get_vertex());
  172. GeomVertexWriter color(line_vdata, InternalName::get_color());
  173. vertex.add_data3(point._surface_point);
  174. vertex.add_data3(point._surface_point +
  175. point._surface_normal * _normal_scale);
  176. color.add_data4(1.0f, 0.0f, 0.0f, 1.0f);
  177. color.add_data4(1.0f, 1.0f, 1.0f, 1.0f);
  178. lines->add_next_vertices(2);
  179. lines->close_primitive();
  180. PT(Geom) geom = new Geom(line_vdata);
  181. geom->add_primitive(lines);
  182. CullableObject *object =
  183. new CullableObject(geom, empty_state,
  184. xform_data.get_internal_transform(trav));
  185. trav->get_cull_handler()->record_object(object, trav);
  186. }
  187. }
  188. }
  189. }
  190. // Now carry on to render our child nodes.
  191. return true;
  192. }
  193. /**
  194. * Returns true if there is some value to visiting this particular node during
  195. * the cull traversal for any camera, false otherwise. This will be used to
  196. * optimize the result of get_net_draw_show_mask(), so that any subtrees that
  197. * contain only nodes for which is_renderable() is false need not be visited.
  198. */
  199. bool CollisionVisualizer::
  200. is_renderable() const {
  201. return true;
  202. }
  203. /**
  204. * Writes a brief description of the node to the indicated output stream.
  205. * This is invoked by the << operator. It may be overridden in derived
  206. * classes to include some information relevant to the class.
  207. */
  208. void CollisionVisualizer::
  209. output(ostream &out) const {
  210. PandaNode::output(out);
  211. out << " ";
  212. CollisionRecorder::output(out);
  213. }
  214. /**
  215. * This method is called at the beginning of a CollisionTraverser::traverse()
  216. * call. It is provided as a hook for the derived class to reset its state as
  217. * appropriate.
  218. */
  219. void CollisionVisualizer::
  220. begin_traversal() {
  221. CollisionRecorder::begin_traversal();
  222. _data.clear();
  223. }
  224. /**
  225. * This method is called when a pair of collision solids have passed all
  226. * bounding-volume tests and have been tested for a collision. The detected
  227. * value is set true if a collision was detected, false otherwise.
  228. */
  229. void CollisionVisualizer::
  230. collision_tested(const CollisionEntry &entry, bool detected) {
  231. CollisionRecorder::collision_tested(entry, detected);
  232. NodePath node_path = entry.get_into_node_path();
  233. CPT(TransformState) net_transform = node_path.get_net_transform();
  234. const CollisionSolid *solid = entry.get_into();
  235. nassertv(solid != (CollisionSolid *)NULL);
  236. VizInfo &viz_info = _data[net_transform];
  237. if (detected) {
  238. viz_info._solids[solid]._detected_count++;
  239. if (entry.has_surface_point()) {
  240. CollisionPoint p;
  241. entry.get_all(entry.get_into_node_path(),
  242. p._surface_point, p._surface_normal, p._interior_point);
  243. viz_info._points.push_back(p);
  244. }
  245. } else {
  246. viz_info._solids[solid]._missed_count++;
  247. }
  248. }
  249. /**
  250. * Returns a RenderState suitable for rendering the collision solids with
  251. * which a collision was detected.
  252. */
  253. CPT(RenderState) CollisionVisualizer::
  254. get_viz_state() {
  255. // Once someone asks for this pointer, we hold its reference count and never
  256. // free it.
  257. static CPT(RenderState) state = (const RenderState *)NULL;
  258. if (state == (const RenderState *)NULL) {
  259. state = RenderState::make
  260. (DepthOffsetAttrib::make());
  261. }
  262. return state;
  263. }
  264. #endif // DO_COLLISION_RECORDING