Panda3D
Loading...
Searching...
No Matches
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
37using std::max;
38using std::min;
39
40PStatCollector CollisionFloorMesh::_volume_pcollector("Collision Volumes:CollisionFloorMesh");
41PStatCollector CollisionFloorMesh::_test_pcollector("Collision Tests:CollisionFloorMesh");
42TypeHandle CollisionFloorMesh::_type_handle;
43
44/**
45 *
46 */
47CollisionSolid *CollisionFloorMesh::
48make_copy() {
49 return new CollisionFloorMesh(*this);
50}
51
52/**
53 * Transforms the solid by the indicated matrix.
54 */
56xform(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 */
92void CollisionFloorMesh::
93output(std::ostream &out) const {
94 out << "cfloor";
95}
96
97/**
98 *
99 */
100PT(BoundingVolume) CollisionFloorMesh::
101compute_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 */
129PT(CollisionEntry) CollisionFloorMesh::
130test_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 */
194PT(CollisionEntry) CollisionFloorMesh::
195test_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 */
266void CollisionFloorMesh::
267fill_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 */
334write_datagram(BamWriter *manager, Datagram &me)
335{
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 */
359void CollisionFloorMesh::
360fillin(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 */
407
408
409/**
410 *
411 */
412void CollisionFloorMesh::
413write(std::ostream &out, int indent_level) const {
414 indent(out, indent_level) << (*this) << "\n";
415}
416
417/**
418 * store a triangle for processing
419 */
421add_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}
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition bamReader.I:177
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition bamWriter.h:63
An axis-aligned bounding box; that is, a minimum and maximum coordinate triple.
Definition boundingBox.h:29
This is an abstract class for any volume in any sense which can be said to define the locality of ref...
Defines a single collision event.
get_from
Returns the CollisionSolid pointer for the particular solid that triggered this collision.
This object represents a solid made entirely of triangles, which will only be tested again z axis ali...
static TypedWritable * make_CollisionFloorMesh(const FactoryParams &params)
Factory method to generate a CollisionPolygon object.
void add_triangle(unsigned int pointA, unsigned int pointB, unsigned int pointC)
store a triangle for processing
virtual PStatCollector & get_volume_pcollector()
Returns a PStatCollector that is used to count the number of bounding volume tests made against a sol...
virtual void write_datagram(BamWriter *manager, Datagram &me)
Function to write the important information in the particular object to a Datagram.
virtual LPoint3 get_collision_origin() const
Returns the point in space deemed to be the "origin" of the solid for collision purposes.
virtual void xform(const LMatrix4 &mat)
Transforms the solid by the indicated matrix.
virtual PStatCollector & get_test_pcollector()
Returns a PStatCollector that is used to count the number of intersection tests made against a solid ...
static void register_with_read_factory()
Factory method to generate a CollisionPolygon object.
CollisionFloorMesh()
This is only for the convenience of CollisionPolygon.
An infinite ray, with a specific origin and direction.
The abstract base class for all things that can collide with other things in the world,...
virtual void write_datagram(BamWriter *manager, Datagram &me)
Function to write the important information in the particular object to a Datagram.
A spherical collision volume or object.
A class to retrieve the individual data elements previously stored in a Datagram.
PN_stdfloat get_stdfloat()
Extracts either a 32-bit or a 64-bit floating-point number, according to Datagram::set_stdfloat_doubl...
uint16_t get_uint16()
Extracts an unsigned 16-bit integer.
uint32_t get_uint32()
Extracts an unsigned 32-bit integer.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition datagram.h:38
void add_uint32(uint32_t value)
Adds an unsigned 32-bit integer to the datagram.
Definition datagram.I:94
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
void add_uint16(uint16_t value)
Adds an unsigned 16-bit integer to the datagram.
Definition datagram.I:85
An instance of this class is passed to the Factory when requesting it to do its business and construc...
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
Defines a series of line strips.
Defines a series of disconnected triangles.
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
static const GeomVertexFormat * get_v3()
Returns a standard vertex format with just a 3-component vertex position.
This object provides a high-level interface for quickly writing a sequence of numeric values from a v...
A container for geometry primitives.
Definition geom.h:54
A lightweight class that represents a single element that may be timed and/or counted via stats.
TypeHandle is the identifier used to differentiate C++ class types.
Definition typeHandle.h:81
Base class for objects that can be written to and read from Bam files.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.