Panda3D
collisionFloorMesh.cxx
Go to the documentation of this file.
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 collisionFloorMesh.cxx
10  * @author drose
11  * @date 2000-04-25
12  */
13 
14 #include "collisionFloorMesh.h"
15 #include "collisionHandler.h"
16 #include "collisionEntry.h"
17 #include "collisionSphere.h"
18 #include "collisionLine.h"
19 #include "collisionRay.h"
20 #include "collisionSegment.h"
21 #include "config_collide.h"
22 #include "pointerToArray.h"
23 #include "geomNode.h"
24 #include "geom.h"
25 #include "datagram.h"
26 #include "datagramIterator.h"
27 #include "bamReader.h"
28 #include "bamWriter.h"
29 #include "boundingBox.h"
30 #include "boundingPlane.h"
31 #include "geom.h"
32 #include "geomTriangles.h"
33 #include "geomLinestrips.h"
34 #include "geomVertexWriter.h"
35 #include <algorithm>
36 
37 using std::max;
38 using std::min;
39 
40 PStatCollector CollisionFloorMesh::_volume_pcollector("Collision Volumes:CollisionFloorMesh");
41 PStatCollector CollisionFloorMesh::_test_pcollector("Collision Tests:CollisionFloorMesh");
42 TypeHandle CollisionFloorMesh::_type_handle;
43 
44 /**
45  *
46  */
47 CollisionSolid *CollisionFloorMesh::
48 make_copy() {
49  return new CollisionFloorMesh(*this);
50 }
51 
52 /**
53  * Transforms the solid by the indicated matrix.
54  */
56 xform(const LMatrix4 &mat) {
57  Vertices::iterator vi;
58  for (vi=_vertices.begin();vi!=_vertices.end();++vi) {
59  LPoint3 pt = (*vi) * mat;
60  (*vi).set(pt[0],pt[1],pt[2]);
61  }
62  Triangles::iterator ti;
63  for (ti=_triangles.begin();ti!=_triangles.end();++ti) {
64  CollisionFloorMesh::TriangleIndices tri = *ti;
65  LPoint3 v1 = _vertices[tri.p1];
66  LPoint3 v2 = _vertices[tri.p2];
67  LPoint3 v3 = _vertices[tri.p3];
68 
69  tri.min_x=min(min(v1[0],v2[0]),v3[0]);
70  tri.max_x=max(max(v1[0],v2[0]),v3[0]);
71  tri.min_y=min(min(v1[1],v2[1]),v3[1]);
72  tri.max_y=max(max(v1[1],v2[1]),v3[1]);
73  }
74  CollisionSolid::xform(mat);
75 }
76 
77 /**
78  * Returns the point in space deemed to be the "origin" of the solid for
79  * collision purposes. The closest intersection point to this origin point is
80  * considered to be the most significant.
81  */
84  // No real sensible origin exists for a plane. We return 0, 0, 0, without
85  // even bothering to ensure that that point exists on the plane.
86  return LPoint3::origin();
87 }
88 
89 /**
90  *
91  */
92 void CollisionFloorMesh::
93 output(std::ostream &out) const {
94  out << "cfloor";
95 }
96 
97 /**
98  *
99  */
100 PT(BoundingVolume) CollisionFloorMesh::
101 compute_internal_bounds() const {
102  if (_vertices.empty()) {
103  return new BoundingBox;
104  }
105 
106  Vertices::const_iterator pi = _vertices.begin();
107  LPoint3 p = (*pi);
108 
109  LPoint3 x = p;
110  LPoint3 n = p;
111 
112  for (++pi; pi != _vertices.end(); ++pi) {
113  p = *pi;
114 
115  n.set(min(n[0], p[0]),
116  min(n[1], p[1]),
117  min(n[2], p[2]));
118  x.set(max(x[0], p[0]),
119  max(x[1], p[1]),
120  max(x[2], p[2]));
121  }
122 
123  return new BoundingBox(n, x);
124 }
125 
126 /**
127  * must be a vertical Ray!!!
128  */
129 PT(CollisionEntry) CollisionFloorMesh::
130 test_intersection_from_ray(const CollisionEntry &entry) const {
131  const CollisionRay *ray;
132  DCAST_INTO_R(ray, entry.get_from(), nullptr);
133  LPoint3 from_origin = ray->get_origin() * entry.get_wrt_mat();
134 
135  double fx = from_origin[0];
136  double fy = from_origin[1];
137 
138  CollisionFloorMesh::Triangles::const_iterator ti;
139  for (ti = _triangles.begin(); ti < _triangles.end(); ++ti) {
140  TriangleIndices tri = *ti;
141  // First do a naive bounding box check on the triangle
142  if (fx < tri.min_x || fx >= tri.max_x || fy < tri.min_y || fy >= tri.max_y) {
143  continue;
144  }
145 
146  // okay, there's a good chance we'll be colliding
147  LPoint3 p0 = _vertices[tri.p1];
148  LPoint3 p1 = _vertices[tri.p2];
149  LPoint3 p2 = _vertices[tri.p3];
150  PN_stdfloat p0x = p0[0];
151  PN_stdfloat p0y = p0[1];
152  PN_stdfloat e0x, e0y, e1x, e1y, e2x, e2y;
153  PN_stdfloat u, v;
154 
155  e0x = fx - p0x; e0y = fy - p0y;
156  e1x = p1[0] - p0x; e1y = p1[1] - p0y;
157  e2x = p2[0] - p0x; e2y = p2[1] - p0y;
158  if (e1x == 0.0) {
159  if (e2x == 0.0) continue;
160  u = e0x / e2x;
161  if (u < 0.0 || u > 1.0) continue;
162  if (e1y == 0) continue;
163  v = (e0y - (e2y * u)) / e1y;
164  if (v < 0.0) continue;
165  } else {
166  PN_stdfloat d = (e2y * e1x) - (e2x * e1y);
167  if (d == 0.0) continue;
168  u = ((e0y * e1x) - (e0x * e1y)) / d;
169  if (u < 0.0 || u > 1.0) continue;
170  v = (e0x - (e2x * u)) / e1x;
171  if (v < 0.0) continue;
172  }
173  if (u + v <= 0.0 || u + v > 1.0) continue;
174  // we collided!!
175  PN_stdfloat mag = u + v;
176  PN_stdfloat p0z = p0[2];
177 
178  PN_stdfloat uz = (p2[2] - p0z) * mag;
179  PN_stdfloat vz = (p1[2] - p0z) * mag;
180  PN_stdfloat finalz = p0z + vz + (((uz - vz) * u) / (u + v));
181  PT(CollisionEntry) new_entry = new CollisionEntry(entry);
182 
183  new_entry->set_surface_normal(LPoint3(0, 0, 1));
184  new_entry->set_surface_point(LPoint3(fx, fy, finalz));
185  return new_entry;
186  }
187  return nullptr;
188 }
189 
190 
191 /**
192  *
193  */
194 PT(CollisionEntry) CollisionFloorMesh::
195 test_intersection_from_sphere(const CollisionEntry &entry) const {
196  const CollisionSphere *sphere;
197  DCAST_INTO_R(sphere, entry.get_from(), nullptr);
198  LPoint3 from_origin = sphere->get_center() * entry.get_wrt_mat();
199 
200  double fx = from_origin[0];
201  double fy = from_origin[1];
202 
203  PN_stdfloat fz = PN_stdfloat(from_origin[2]);
204  PN_stdfloat rad = sphere->get_radius();
205  CollisionFloorMesh::Triangles::const_iterator ti;
206  for (ti = _triangles.begin(); ti < _triangles.end(); ++ti) {
207  TriangleIndices tri = *ti;
208  // First do a naive bounding box check on the triangle
209  if (fx < tri.min_x || fx >= tri.max_x || fy < tri.min_y || fy >= tri.max_y) {
210  continue;
211  }
212 
213  // okay, there's a good chance we'll be colliding
214  LPoint3 p0 = _vertices[tri.p1];
215  LPoint3 p1 = _vertices[tri.p2];
216  LPoint3 p2 = _vertices[tri.p3];
217  PN_stdfloat p0x = p0[0];
218  PN_stdfloat p0y = p0[1];
219  PN_stdfloat e0x, e0y, e1x, e1y, e2x, e2y;
220  PN_stdfloat u, v;
221 
222  e0x = fx - p0x; e0y = fy - p0y;
223  e1x = p1[0] - p0x; e1y = p1[1] - p0y;
224  e2x = p2[0] - p0x; e2y = p2[1] - p0y;
225  if (e1x == 0.0) {
226  if (e2x == 0.0) continue;
227  u = e0x / e2x;
228  if (u < 0.0 || u > 1.0) continue;
229  if (e1y == 0) continue;
230  v = (e0y - (e2y * u)) / e1y;
231  if (v < 0.0) continue;
232  } else {
233  PN_stdfloat d = (e2y * e1x) - (e2x * e1y);
234  if (d == 0.0) continue;
235  u = ((e0y * e1x) - (e0x * e1y)) / d;
236  if (u < 0.0 || u > 1.0) continue;
237  v = (e0x - (e2x * u)) / e1x;
238  if (v < 0.0) continue;
239  }
240  if (u + v <= 0.0 || u + v > 1.0) continue;
241  // we collided!!
242  PN_stdfloat mag = u + v;
243  PN_stdfloat p0z = p0[2];
244 
245  PN_stdfloat uz = (p2[2] - p0z) * mag;
246  PN_stdfloat vz = (p1[2] - p0z) * mag;
247  PN_stdfloat finalz = p0z+vz+(((uz - vz) *u)/(u+v));
248  PN_stdfloat dz = fz - finalz;
249  if(dz > rad)
250  return nullptr;
251  PT(CollisionEntry) new_entry = new CollisionEntry(entry);
252 
253  new_entry->set_surface_normal(LPoint3(0, 0, 1));
254  new_entry->set_surface_point(LPoint3(fx, fy, finalz));
255  return new_entry;
256  }
257  return nullptr;
258 }
259 
260 
261 
262 /**
263  * Fills the _viz_geom GeomNode up with Geoms suitable for rendering this
264  * solid.
265  */
266 void CollisionFloorMesh::
267 fill_viz_geom() {
268  if (collide_cat.is_debug()) {
269  collide_cat.debug()
270  << "Recomputing viz for " << *this << "\n";
271  }
272 
273  PT(GeomVertexData) vdata = new GeomVertexData
274  ("collision", GeomVertexFormat::get_v3(),
275  Geom::UH_static);
276  GeomVertexWriter vertex(vdata, InternalName::get_vertex());
277 
278 
279  PT(GeomTriangles) mesh = new GeomTriangles(Geom::UH_static);
280  PT(GeomLinestrips) wire = new GeomLinestrips(Geom::UH_static);
281  Triangles::iterator ti;
282  Vertices::iterator vi;
283  for (vi = _vertices.begin(); vi != _vertices.end(); vi++) {
284  LPoint3 vert = *vi;
285  vertex.add_data3(vert);
286  }
287  for (ti = _triangles.begin(); ti != _triangles.end(); ++ti) {
288  CollisionFloorMesh::TriangleIndices tri = *ti;
289  mesh->add_vertex(tri.p1);
290  mesh->add_vertex(tri.p2);
291  mesh->add_vertex(tri.p3);
292  wire->add_vertex(tri.p1);
293  wire->add_vertex(tri.p2);
294  wire->add_vertex(tri.p3);
295  wire->add_vertex(tri.p1);
296  wire->close_primitive();
297  mesh->close_primitive();
298  }
299 
300  PT(Geom) geom = new Geom(vdata);
301  PT(Geom) geom2 = new Geom(vdata);
302  geom->add_primitive(mesh);
303  geom2->add_primitive(wire);
304  _viz_geom->add_geom(geom, ((CollisionFloorMesh *)this)->get_solid_viz_state());
305  _viz_geom->add_geom(geom2, ((CollisionFloorMesh *)this)->get_wireframe_viz_state());
306 
307  _bounds_viz_geom->add_geom(geom, get_solid_bounds_viz_state());
308  _bounds_viz_geom->add_geom(geom2, get_wireframe_bounds_viz_state());
309 }
310 
311 /**
312  * Returns a PStatCollector that is used to count the number of bounding
313  * volume tests made against a solid of this type in a given frame.
314  */
317  return _volume_pcollector;
318 }
319 
320 /**
321  * Returns a PStatCollector that is used to count the number of intersection
322  * tests made against a solid of this type in a given frame.
323  */
326  return _test_pcollector;
327 }
328 
329 /**
330  * Function to write the important information in the particular object to a
331  * Datagram
332  */
335 {
336  CollisionSolid::write_datagram(manager, me);
337  me.add_uint16(_vertices.size());
338  for (size_t i = 0; i < _vertices.size(); i++) {
339  _vertices[i].write_datagram(me);
340  }
341  me.add_uint16(_triangles.size());
342  for (size_t i = 0; i < _triangles.size(); i++) {
343  me.add_uint32(_triangles[i].p1);
344  me.add_uint32(_triangles[i].p2);
345  me.add_uint32(_triangles[i].p3);
346  me.add_stdfloat(_triangles[i].min_x);
347  me.add_stdfloat(_triangles[i].max_x);
348  me.add_stdfloat(_triangles[i].min_y);
349  me.add_stdfloat(_triangles[i].max_y);
350 
351  }
352 }
353 
354 /**
355  * Function that reads out of the datagram (or asks manager to read) all of
356  * the data that is needed to re-create this object and stores it in the
357  * appropiate place
358  */
359 void CollisionFloorMesh::
360 fillin(DatagramIterator& scan, BamReader* manager)
361 {
362  CollisionSolid::fillin(scan, manager);
363  unsigned int num_verts = scan.get_uint16();
364  for (size_t i = 0; i < num_verts; i++) {
365  LPoint3 vert;
366  vert.read_datagram(scan);
367 
368  _vertices.push_back(vert);
369  }
370  unsigned int num_tris = scan.get_uint16();
371  for (size_t i = 0; i < num_tris; i++) {
372  CollisionFloorMesh::TriangleIndices tri;
373 
374  tri.p1 = scan.get_uint32();
375  tri.p2 = scan.get_uint32();
376  tri.p3 = scan.get_uint32();
377 
378  tri.min_x=scan.get_stdfloat();
379  tri.max_x=scan.get_stdfloat();
380  tri.min_y=scan.get_stdfloat();
381  tri.max_y=scan.get_stdfloat();
382  _triangles.push_back(tri);
383  }
384 }
385 
386 /**
387  * Factory method to generate a CollisionPolygon object
388  */
392  DatagramIterator scan;
393  BamReader *manager;
394 
395  parse_params(params, scan, manager);
396  me->fillin(scan, manager);
397  return me;
398 }
399 
400 /**
401  * Factory method to generate a CollisionPolygon object
402  */
406 }
407 
408 
409 /**
410  *
411  */
412 void CollisionFloorMesh::
413 write(std::ostream &out, int indent_level) const {
414  indent(out, indent_level) << (*this) << "\n";
415 }
416 
417 /**
418  * store a triangle for processing
419  */
421 add_triangle(unsigned int pointA, unsigned int pointB, unsigned int pointC) {
422  CollisionFloorMesh::TriangleIndices tri;
423  tri.p1 = pointA;
424  tri.p2 = pointB;
425  tri.p3 = pointC;
426  LPoint3 v1 = _vertices[pointA];
427  LPoint3 v2 = _vertices[pointB];
428  LPoint3 v3 = _vertices[pointC];
429 
430  tri.min_x=min(min(v1[0],v2[0]),v3[0]);
431  tri.max_x=max(max(v1[0],v2[0]),v3[0]);
432  tri.min_y=min(min(v1[1],v2[1]),v3[1]);
433  tri.max_y=max(max(v1[1],v2[1]),v3[1]);
434 
435  _triangles.push_back(tri);
436 }
void add_triangle(unsigned int pointA, unsigned int pointB, unsigned int pointC)
store a triangle for processing
This object provides a high-level interface for quickly writing a sequence of numeric values from a v...
An axis-aligned bounding box; that is, a minimum and maximum coordinate triple.
Definition: boundingBox.h:29
An infinite ray, with a specific origin and direction.
Definition: collisionRay.h:27
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PN_stdfloat get_stdfloat()
Extracts either a 32-bit or a 64-bit floating-point number, according to Datagram::set_stdfloat_doubl...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:110
The abstract base class for all things that can collide with other things in the world,...
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
PT(BoundingVolume) CollisionFloorMesh
must be a vertical Ray!!!
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual PStatCollector & get_test_pcollector()
Returns a PStatCollector that is used to count the number of intersection tests made against a solid ...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:63
A spherical collision volume or object.
virtual void write_datagram(BamWriter *manager, Datagram &me)
Function to write the important information in the particular object to a Datagram.
CollisionFloorMesh()
This is only for the convenience of CollisionPolygon.
void add_uint32(uint32_t value)
Adds an unsigned 32-bit integer to the datagram.
Definition: datagram.I:94
static TypedWritable * make_CollisionFloorMesh(const FactoryParams &params)
Factory method to generate a CollisionPolygon object.
void add_stdfloat(PN_stdfloat value)
Adds either a 32-bit or a 64-bit floating-point number, according to set_stdfloat_double().
Definition: datagram.I:133
This is an abstract class for any volume in any sense which can be said to define the locality of ref...
A lightweight class that represents a single element that may be timed and/or counted via stats.
void parse_params(const FactoryParams &params, DatagramIterator &scan, BamReader *&manager)
Takes in a FactoryParams, passed from a WritableFactory into any TypedWritable's make function,...
Definition: bamReader.I:275
void add_uint16(uint16_t value)
Adds an unsigned 16-bit integer to the datagram.
Definition: datagram.I:85
virtual void xform(const LMatrix4 &mat)
Transforms the solid by the indicated matrix.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition: indent.cxx:20
Defines a single collision event.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A container for geometry primitives.
Definition: geom.h:54
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:36
uint32_t get_uint32()
Extracts an unsigned 32-bit integer.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void register_factory(TypeHandle handle, CreateFunc *func, void *user_data=nullptr)
Registers a new kind of thing the Factory will be able to create.
Definition: factory.I:73
virtual void write_datagram(BamWriter *manager, Datagram &me)
Function to write the important information in the particular object to a Datagram.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual LPoint3 get_collision_origin() const
Returns the point in space deemed to be the "origin" of the solid for collision purposes.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This object represents a solid made entirely of triangles, which will only be tested again z axis ali...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
static void register_with_read_factory()
Factory method to generate a CollisionPolygon object.
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:177
uint16_t get_uint16()
Extracts an unsigned 16-bit integer.
get_from
Returns the CollisionSolid pointer for the particular solid that triggered this collision.
Defines a series of line strips.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Defines a series of disconnected triangles.
Definition: geomTriangles.h:23
A class to retrieve the individual data elements previously stored in a Datagram.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
virtual PStatCollector & get_volume_pcollector()
Returns a PStatCollector that is used to count the number of bounding volume tests made against a sol...
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
static const GeomVertexFormat * get_v3()
Returns a standard vertex format with just a 3-component vertex position.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.