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 }
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
134 CPT(TransformState) wrt_space = entry.get_wrt_space();
135 LPoint3 from_origin = ray->get_origin() * wrt_space->get_mat();
136
137 double fx = from_origin[0];
138 double fy = from_origin[1];
139
140 CollisionFloorMesh::Triangles::const_iterator ti;
141 for (ti = _triangles.begin(); ti < _triangles.end(); ++ti) {
142 TriangleIndices tri = *ti;
143 // First do a naive bounding box check on the triangle
144 if (fx < tri.min_x || fx >= tri.max_x || fy < tri.min_y || fy >= tri.max_y) {
145 continue;
146 }
147
148 // okay, there's a good chance we'll be colliding
149 LPoint3 p0 = _vertices[tri.p1];
150 LPoint3 p1 = _vertices[tri.p2];
151 LPoint3 p2 = _vertices[tri.p3];
152 PN_stdfloat p0x = p0[0];
153 PN_stdfloat p0y = p0[1];
154 PN_stdfloat e0x, e0y, e1x, e1y, e2x, e2y;
155 PN_stdfloat u, v;
156
157 e0x = fx - p0x; e0y = fy - p0y;
158 e1x = p1[0] - p0x; e1y = p1[1] - p0y;
159 e2x = p2[0] - p0x; e2y = p2[1] - p0y;
160 if (e1x == 0.0) {
161 if (e2x == 0.0) continue;
162 u = e0x / e2x;
163 if (u < 0.0 || u > 1.0) continue;
164 if (e1y == 0) continue;
165 v = (e0y - (e2y * u)) / e1y;
166 if (v < 0.0) continue;
167 } else {
168 PN_stdfloat d = (e2y * e1x) - (e2x * e1y);
169 if (d == 0.0) continue;
170 u = ((e0y * e1x) - (e0x * e1y)) / d;
171 if (u < 0.0 || u > 1.0) continue;
172 v = (e0x - (e2x * u)) / e1x;
173 if (v < 0.0) continue;
174 }
175 if (u + v <= 0.0 || u + v > 1.0) continue;
176 // we collided!!
177 PN_stdfloat mag = u + v;
178 PN_stdfloat p0z = p0[2];
179
180 PN_stdfloat uz = (p2[2] - p0z) * mag;
181 PN_stdfloat vz = (p1[2] - p0z) * mag;
182 PN_stdfloat finalz = p0z + vz + (((uz - vz) * u) / (u + v));
183 PT(CollisionEntry) new_entry = new CollisionEntry(entry);
184
185 new_entry->set_surface_normal(LPoint3(0, 0, 1));
186 new_entry->set_surface_point(LPoint3(fx, fy, finalz));
187 return new_entry;
188 }
189 return nullptr;
190}
191
192
193/**
194 *
195 */
196PT(CollisionEntry) CollisionFloorMesh::
197test_intersection_from_sphere(const CollisionEntry &entry) const {
198 const CollisionSphere *sphere;
199 DCAST_INTO_R(sphere, entry.get_from(), nullptr);
200
201 CPT(TransformState) wrt_space = entry.get_wrt_space();
202 LPoint3 from_origin = sphere->get_center() * wrt_space->get_mat();
203
204 double fx = from_origin[0];
205 double fy = from_origin[1];
206
207 PN_stdfloat fz = PN_stdfloat(from_origin[2]);
208 PN_stdfloat rad = sphere->get_radius();
209 CollisionFloorMesh::Triangles::const_iterator ti;
210 for (ti = _triangles.begin(); ti < _triangles.end(); ++ti) {
211 TriangleIndices tri = *ti;
212 // First do a naive bounding box check on the triangle
213 if (fx < tri.min_x || fx >= tri.max_x || fy < tri.min_y || fy >= tri.max_y) {
214 continue;
215 }
216
217 // okay, there's a good chance we'll be colliding
218 LPoint3 p0 = _vertices[tri.p1];
219 LPoint3 p1 = _vertices[tri.p2];
220 LPoint3 p2 = _vertices[tri.p3];
221 PN_stdfloat p0x = p0[0];
222 PN_stdfloat p0y = p0[1];
223 PN_stdfloat e0x, e0y, e1x, e1y, e2x, e2y;
224 PN_stdfloat u, v;
225
226 e0x = fx - p0x; e0y = fy - p0y;
227 e1x = p1[0] - p0x; e1y = p1[1] - p0y;
228 e2x = p2[0] - p0x; e2y = p2[1] - p0y;
229 if (e1x == 0.0) {
230 if (e2x == 0.0) continue;
231 u = e0x / e2x;
232 if (u < 0.0 || u > 1.0) continue;
233 if (e1y == 0) continue;
234 v = (e0y - (e2y * u)) / e1y;
235 if (v < 0.0) continue;
236 } else {
237 PN_stdfloat d = (e2y * e1x) - (e2x * e1y);
238 if (d == 0.0) continue;
239 u = ((e0y * e1x) - (e0x * e1y)) / d;
240 if (u < 0.0 || u > 1.0) continue;
241 v = (e0x - (e2x * u)) / e1x;
242 if (v < 0.0) continue;
243 }
244 if (u + v <= 0.0 || u + v > 1.0) continue;
245 // we collided!!
246 PN_stdfloat mag = u + v;
247 PN_stdfloat p0z = p0[2];
248
249 PN_stdfloat uz = (p2[2] - p0z) * mag;
250 PN_stdfloat vz = (p1[2] - p0z) * mag;
251 PN_stdfloat finalz = p0z+vz+(((uz - vz) *u)/(u+v));
252 PN_stdfloat dz = fz - finalz;
253 if(dz > rad)
254 return nullptr;
255 PT(CollisionEntry) new_entry = new CollisionEntry(entry);
256
257 new_entry->set_surface_normal(LPoint3(0, 0, 1));
258 new_entry->set_surface_point(LPoint3(fx, fy, finalz));
259 return new_entry;
260 }
261 return nullptr;
262}
263
264
265
266/**
267 * Fills the _viz_geom GeomNode up with Geoms suitable for rendering this
268 * solid.
269 */
270void CollisionFloorMesh::
271fill_viz_geom() {
272 if (collide_cat.is_debug()) {
273 collide_cat.debug()
274 << "Recomputing viz for " << *this << "\n";
275 }
276
277 PT(GeomVertexData) vdata = new GeomVertexData
278 ("collision", GeomVertexFormat::get_v3(),
279 Geom::UH_static);
280 GeomVertexWriter vertex(vdata, InternalName::get_vertex());
281
282
283 PT(GeomTriangles) mesh = new GeomTriangles(Geom::UH_static);
284 PT(GeomLinestrips) wire = new GeomLinestrips(Geom::UH_static);
285 Triangles::iterator ti;
286 Vertices::iterator vi;
287 for (vi = _vertices.begin(); vi != _vertices.end(); vi++) {
288 LPoint3 vert = *vi;
289 vertex.add_data3(vert);
290 }
291 for (ti = _triangles.begin(); ti != _triangles.end(); ++ti) {
292 CollisionFloorMesh::TriangleIndices tri = *ti;
293 mesh->add_vertex(tri.p1);
294 mesh->add_vertex(tri.p2);
295 mesh->add_vertex(tri.p3);
296 wire->add_vertex(tri.p1);
297 wire->add_vertex(tri.p2);
298 wire->add_vertex(tri.p3);
299 wire->add_vertex(tri.p1);
300 wire->close_primitive();
301 mesh->close_primitive();
302 }
303
304 PT(Geom) geom = new Geom(vdata);
305 PT(Geom) geom2 = new Geom(vdata);
306 geom->add_primitive(mesh);
307 geom2->add_primitive(wire);
308 _viz_geom->add_geom(geom, ((CollisionFloorMesh *)this)->get_solid_viz_state());
309 _viz_geom->add_geom(geom2, ((CollisionFloorMesh *)this)->get_wireframe_viz_state());
310
311 _bounds_viz_geom->add_geom(geom, get_solid_bounds_viz_state());
312 _bounds_viz_geom->add_geom(geom2, get_wireframe_bounds_viz_state());
313}
314
315/**
316 * Returns a PStatCollector that is used to count the number of bounding
317 * volume tests made against a solid of this type in a given frame.
318 */
321 return _volume_pcollector;
322}
323
324/**
325 * Returns a PStatCollector that is used to count the number of intersection
326 * tests made against a solid of this type in a given frame.
327 */
330 return _test_pcollector;
331}
332
333/**
334 * Function to write the important information in the particular object to a
335 * Datagram
336 */
338write_datagram(BamWriter *manager, Datagram &me)
339{
341 me.add_uint16(_vertices.size());
342 for (size_t i = 0; i < _vertices.size(); i++) {
343 _vertices[i].write_datagram(me);
344 }
345 me.add_uint16(_triangles.size());
346 for (size_t i = 0; i < _triangles.size(); i++) {
347 me.add_uint32(_triangles[i].p1);
348 me.add_uint32(_triangles[i].p2);
349 me.add_uint32(_triangles[i].p3);
350 me.add_stdfloat(_triangles[i].min_x);
351 me.add_stdfloat(_triangles[i].max_x);
352 me.add_stdfloat(_triangles[i].min_y);
353 me.add_stdfloat(_triangles[i].max_y);
354
355 }
356}
357
358/**
359 * Function that reads out of the datagram (or asks manager to read) all of
360 * the data that is needed to re-create this object and stores it in the
361 * appropiate place
362 */
363void CollisionFloorMesh::
364fillin(DatagramIterator& scan, BamReader* manager)
365{
366 CollisionSolid::fillin(scan, manager);
367 unsigned int num_verts = scan.get_uint16();
368 for (size_t i = 0; i < num_verts; i++) {
369 LPoint3 vert;
370 vert.read_datagram(scan);
371
372 _vertices.push_back(vert);
373 }
374 unsigned int num_tris = scan.get_uint16();
375 for (size_t i = 0; i < num_tris; i++) {
376 CollisionFloorMesh::TriangleIndices tri;
377
378 tri.p1 = scan.get_uint32();
379 tri.p2 = scan.get_uint32();
380 tri.p3 = scan.get_uint32();
381
382 tri.min_x=scan.get_stdfloat();
383 tri.max_x=scan.get_stdfloat();
384 tri.min_y=scan.get_stdfloat();
385 tri.max_y=scan.get_stdfloat();
386 _triangles.push_back(tri);
387 }
388}
389
390/**
391 * Factory method to generate a CollisionPolygon object
392 */
396 DatagramIterator scan;
397 BamReader *manager;
398
399 parse_params(params, scan, manager);
400 me->fillin(scan, manager);
401 return me;
402}
403
404/**
405 * Factory method to generate a CollisionPolygon object
406 */
411
412
413/**
414 *
415 */
416void CollisionFloorMesh::
417write(std::ostream &out, int indent_level) const {
418 indent(out, indent_level) << (*this) << "\n";
419}
420
421/**
422 * store a triangle for processing
423 */
425add_triangle(unsigned int pointA, unsigned int pointB, unsigned int pointC) {
426 CollisionFloorMesh::TriangleIndices tri;
427 tri.p1 = pointA;
428 tri.p2 = pointB;
429 tri.p3 = pointC;
430 LPoint3 v1 = _vertices[pointA];
431 LPoint3 v2 = _vertices[pointB];
432 LPoint3 v3 = _vertices[pointC];
433
434 tri.min_x=min(min(v1[0],v2[0]),v3[0]);
435 tri.max_x=max(max(v1[0],v2[0]),v3[0]);
436 tri.min_y=min(min(v1[1],v2[1]),v3[1]);
437 tri.max_y=max(max(v1[1],v2[1]),v3[1]);
438
439 _triangles.push_back(tri);
440}
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
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.
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.
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.
virtual void xform(const LMatrix4 &mat)
Transforms the solid by the indicated matrix.
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
static const GeomVertexFormat * get_v3()
Returns a standard vertex format with just a 3-component vertex position.
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.
STTransform::operator CPT TransformState() const
This is used internally to convert an STTransform into a TransformState pointer.
Definition stTransform.I:98