Panda3D
Loading...
Searching...
No Matches
collisionNode.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 collisionNode.cxx
10 * @author drose
11 * @date 2002-03-16
12 */
13
14#include "collisionNode.h"
15#include "config_collide.h"
16
17#include "geomNode.h"
18#include "cullTraverserData.h"
19#include "cullTraverser.h"
20#include "renderState.h"
21#include "transformState.h"
22#include "colorScaleAttrib.h"
23#include "transparencyAttrib.h"
24#include "datagram.h"
25#include "datagramIterator.h"
26#include "bamReader.h"
27#include "bamWriter.h"
28#include "clockObject.h"
29#include "boundingSphere.h"
30#include "boundingBox.h"
31#include "config_mathutil.h"
32
33TypeHandle CollisionNode::_type_handle;
34
35
36/**
37 *
38 */
39CollisionNode::
40CollisionNode(const std::string &name) :
41 PandaNode(name),
42 _from_collide_mask(get_default_collide_mask()),
43 _collider_sort(0)
44{
45 set_cull_callback();
46
47 // CollisionNodes are hidden by default.
48 set_overall_hidden(true);
49
50 // CollisionNodes have a certain set of bits on by default.
51 set_into_collide_mask(get_default_collide_mask());
52}
53
54/**
55 *
56 */
57CollisionNode::
58CollisionNode(const CollisionNode &copy) :
59 PandaNode(copy),
60 _from_collide_mask(copy._from_collide_mask),
61 _collider_sort(copy._collider_sort),
62 _solids(copy._solids)
63{
64}
65
66/**
67 *
68 */
69CollisionNode::
70~CollisionNode() {
71}
72
73/**
74 * Returns a newly-allocated Node that is a shallow copy of this one. It will
75 * be a different Node pointer, but its internal data may or may not be shared
76 * with that of the original Node.
77 */
79make_copy() const {
80 return new CollisionNode(*this);
81}
82
83/**
84 * Returns true if the node's name has extrinsic meaning and must be preserved
85 * across a flatten operation, false otherwise.
86 */
88preserve_name() const {
89 return true;
90}
91
92/**
93 * Transforms the contents of this node by the indicated matrix, if it means
94 * anything to do so. For most kinds of nodes, this does nothing.
95 */
97xform(const LMatrix4 &mat) {
98 nassertv(!mat.is_nan());
99
100 if (mat.almost_equal(LMatrix4::ident_mat())) {
101 return;
102 }
103
104 Solids::iterator si;
105 for (si = _solids.begin(); si != _solids.end(); ++si) {
106 PT(CollisionSolid) solid = (*si).get_write_pointer();
107 solid->xform(mat);
108 }
109 mark_internal_bounds_stale();
110}
111
112/**
113 * Collapses this node with the other node, if possible, and returns a pointer
114 * to the combined node, or NULL if the two nodes cannot safely be combined.
115 *
116 * The return value may be this, other, or a new node altogether.
117 *
118 * This function is called from GraphReducer::flatten(), and need not deal
119 * with children; its job is just to decide whether to collapse the two nodes
120 * and what the collapsed node should look like.
121 */
123combine_with(PandaNode *other) {
124 if (flatten_collision_nodes) {
125 if (is_exact_type(get_class_type()) &&
126 other->is_exact_type(get_class_type())) {
127 // Two CollisionNodes can combine, but only if they have the same name,
128 // because the name is often meaningful, and only if they have the same
129 // collide masks.
130 CollisionNode *cother = DCAST(CollisionNode, other);
131 if (get_name() == cother->get_name() &&
134 const COWPT(CollisionSolid) *solids_begin = &cother->_solids[0];
135 const COWPT(CollisionSolid) *solids_end = solids_begin + cother->_solids.size();
136 _solids.insert(_solids.end(), solids_begin, solids_end);
137 mark_internal_bounds_stale();
138 return this;
139 }
140
141 // Two CollisionNodes with different names or different collide masks
142 // can't combine.
143 }
144 }
145
146 return nullptr;
147}
148
149/**
150 * Returns the subset of CollideMask bits that may be set for this particular
151 * type of PandaNode. For most nodes, this is 0; it doesn't make sense to set
152 * a CollideMask for most kinds of nodes.
153 *
154 * For nodes that can be collided with, such as GeomNode and CollisionNode,
155 * this returns all bits on.
156 */
161
162/**
163 * This function will be called during the cull traversal to perform any
164 * additional operations that should be performed at cull time. This may
165 * include additional manipulation of render state or additional
166 * visible/invisible decisions, or any other arbitrary operation.
167 *
168 * Note that this function will *not* be called unless set_cull_callback() is
169 * called in the constructor of the derived class. It is necessary to call
170 * set_cull_callback() to indicated that we require cull_callback() to be
171 * called.
172 *
173 * By the time this function is called, the node has already passed the
174 * bounding-volume test for the viewing frustum, and the node's transform and
175 * state have already been applied to the indicated CullTraverserData object.
176 *
177 * The return value is true if this node should be visible, or false if it
178 * should be culled.
179 */
182 // Append our collision vizzes to the drawing, even though they're not
183 // actually part of the scene graph.
184 Solids::const_iterator si;
185 for (si = _solids.begin(); si != _solids.end(); ++si) {
186 CPT(CollisionSolid) solid = (*si).get_read_pointer();
187 PT(PandaNode) node = solid->get_viz(trav, data, false);
188 if (node != nullptr) {
189 CullTraverserData next_data(data, node);
190
191 // We don't want to inherit the render state from above for these guys.
192 next_data._state = RenderState::make_empty();
193 trav->traverse(next_data);
194 }
195 }
196
197 if (respect_prev_transform) {
198 // Determine the previous frame's position, relative to the current
199 // position.
200 NodePath node_path = data.get_node_path();
201 CPT(TransformState) transform = node_path.get_net_transform()->invert_compose(node_path.get_net_prev_transform());
202
203 if (!transform->is_identity()) {
204 // If we have a velocity, also draw the previous frame's position,
205 // ghosted.
206
207 for (si = _solids.begin(); si != _solids.end(); ++si) {
208 CPT(CollisionSolid) solid = (*si).get_read_pointer();
209 PT(PandaNode) node = solid->get_viz(trav, data, false);
210 if (node != nullptr) {
211 CullTraverserData next_data(data, node);
212
213 next_data._net_transform =
214 next_data._net_transform->compose(transform);
215 next_data._state = get_last_pos_state();
216 trav->traverse(next_data);
217 }
218 }
219 }
220 }
221
222 // Now carry on to render our child nodes.
223 return true;
224}
225
226/**
227 * Returns true if there is some value to visiting this particular node during
228 * the cull traversal for any camera, false otherwise. This will be used to
229 * optimize the result of get_net_draw_show_mask(), so that any subtrees that
230 * contain only nodes for which is_renderable() is false need not be visited.
231 */
233is_renderable() const {
234 return true;
235}
236
237/**
238 * A simple downcast check. Returns true if this kind of node happens to
239 * inherit from CollisionNode, false otherwise.
240 *
241 * This is provided as a a faster alternative to calling
242 * is_of_type(CollisionNode::get_class_type()).
243 */
245is_collision_node() const {
246 return true;
247}
248
249
250/**
251 * Writes a brief description of the node to the indicated output stream.
252 * This is invoked by the << operator. It may be overridden in derived
253 * classes to include some information relevant to the class.
254 */
256output(std::ostream &out) const {
257 PandaNode::output(out);
258 out << " (" << _solids.size() << " solids)";
259}
260
261/**
262 * Sets the "from" CollideMask. In order for a collision to be detected from
263 * this object into another object, the intersection of this object's "from"
264 * mask and the other object's "into" mask must be nonzero.
265 */
268 _from_collide_mask = mask;
269}
270
271/**
272 * Called when needed to recompute the node's _internal_bound object. Nodes
273 * that contain anything of substance should redefine this to do the right
274 * thing.
275 */
276void CollisionNode::
277compute_internal_bounds(CPT(BoundingVolume) &internal_bounds,
278 int &internal_vertices,
279 int pipeline_stage,
280 Thread *current_thread) const {
281 pvector<CPT(BoundingVolume) > child_volumes_ref;
283 bool all_box = true;
284
285 Solids::const_iterator gi;
286 for (gi = _solids.begin(); gi != _solids.end(); ++gi) {
287 CPT(CollisionSolid) solid = (*gi).get_read_pointer();
288 CPT(BoundingVolume) volume = solid->get_bounds();
289
290 if (!volume->is_empty()) {
291 child_volumes_ref.push_back(volume);
292 child_volumes.push_back(volume);
293 if (!volume->is_exact_type(BoundingBox::get_class_type())) {
294 all_box = false;
295 }
296 }
297 }
298
300
301 BoundingVolume::BoundsType btype = get_bounds_type();
302 if (btype == BoundingVolume::BT_default) {
303 btype = bounds_type;
304 }
305
306 if (btype == BoundingVolume::BT_box ||
307 (btype != BoundingVolume::BT_sphere && all_box)) {
308 // If all of the child volumes are a BoundingBox, then our volume is also
309 // a BoundingBox.
310 gbv = new BoundingBox;
311 } else {
312 // Otherwise, it's a sphere.
313 gbv = new BoundingSphere;
314 }
315
316 if (child_volumes.size() > 0) {
317 const BoundingVolume **child_begin = &child_volumes[0];
318 const BoundingVolume **child_end = child_begin + child_volumes.size();
319 ((BoundingVolume *)gbv)->around(child_begin, child_end);
320 }
321
322 internal_bounds = gbv;
323 internal_vertices = 0;
324}
325
326/**
327 * Returns a RenderState for rendering the ghosted collision solid that
328 * represents the previous frame's position, for those collision nodes that
329 * indicate a velocity.
330 */
331CPT(RenderState) CollisionNode::
332get_last_pos_state() {
333 // Once someone asks for this pointer, we hold its reference count and never
334 // free it.
335 static CPT(RenderState) state = nullptr;
336 if (state == nullptr) {
337 state = RenderState::make
338 (ColorScaleAttrib::make(LVecBase4(1.0f, 1.0f, 1.0f, 0.5f)),
339 TransparencyAttrib::make(TransparencyAttrib::M_alpha));
340 }
341
342 return state;
343}
344
345
346/**
347 * Tells the BamReader how to create objects of type CollisionNode.
348 */
351 BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
352}
353
354/**
355 * Writes the contents of this object to the datagram for shipping out to a
356 * Bam file.
357 */
359write_datagram(BamWriter *manager, Datagram &dg) {
360 PandaNode::write_datagram(manager, dg);
361
362 int num_solids = _solids.size();
363 if (num_solids >= 0xffff) {
364 dg.add_uint16(0xffff);
365 dg.add_uint32(num_solids);
366 } else {
367 dg.add_uint16(num_solids);
368 }
369 for(int i = 0; i < num_solids; i++) {
370 manager->write_pointer(dg, _solids[i].get_read_pointer());
371 }
372
373 dg.add_uint32(_from_collide_mask.get_word());
374}
375
376/**
377 * Receives an array of pointers, one for each time manager->read_pointer()
378 * was called in fillin(). Returns the number of pointers processed.
379 */
381complete_pointers(TypedWritable **p_list, BamReader *manager) {
382 int pi = PandaNode::complete_pointers(p_list, manager);
383
384 int num_solids = _solids.size();
385 for (int i = 0; i < num_solids; i++) {
386 _solids[i] = DCAST(CollisionSolid, p_list[pi++]);
387 }
388
389 return pi;
390}
391
392/**
393 * This function is called by the BamReader's factory when a new object of
394 * type CollisionNode is encountered in the Bam file. It should create the
395 * CollisionNode and extract its information from the file.
396 */
397TypedWritable *CollisionNode::
398make_from_bam(const FactoryParams &params) {
399 CollisionNode *node = new CollisionNode("");
400 DatagramIterator scan;
401 BamReader *manager;
402
403 parse_params(params, scan, manager);
404 node->fillin(scan, manager);
405
406 return node;
407}
408
409/**
410 * This internal function is called by make_from_bam to read in all of the
411 * relevant data from the BamFile for the new CollisionNode.
412 */
413void CollisionNode::
414fillin(DatagramIterator &scan, BamReader *manager) {
415 PandaNode::fillin(scan, manager);
416
417 int num_solids = scan.get_uint16();
418 if (num_solids == 0xffff) {
419 num_solids = scan.get_uint32();
420 }
421 _solids.clear();
422 _solids.reserve(num_solids);
423 for(int i = 0; i < num_solids; i++) {
424 manager->read_pointer(scan);
425 // Push back a NULL for each solid, for now. We'll fill them in later.
426 _solids.push_back(nullptr);
427 }
428
429 _from_collide_mask.set_word(scan.get_uint32());
430}
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
bool read_pointer(DatagramIterator &scan)
The interface for reading a pointer to another object from a Bam file.
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
void write_pointer(Datagram &packet, const TypedWritable *dest)
The interface for writing a pointer to another object to a Bam file.
static BitMask< uint32_t, nbits > all_on()
Returns a BitMask whose bits are all on.
Definition bitMask.I:32
void set_word(WordType value)
Sets the entire BitMask to the value indicated by the given word.
Definition bitMask.I:255
WordType get_word() const
Returns the entire BitMask as a single word.
Definition bitMask.I:246
An axis-aligned bounding box; that is, a minimum and maximum coordinate triple.
Definition boundingBox.h:29
This defines a bounding sphere, consisting of a center and a radius.
This is an abstract class for any volume in any sense which can be said to define the locality of ref...
A node in the scene graph that can hold any number of CollisionSolids.
get_into_collide_mask
Returns the current "into" CollideMask.
virtual bool is_renderable() const
Returns true if there is some value to visiting this particular node during the cull traversal for an...
virtual bool preserve_name() const
Returns true if the node's name has extrinsic meaning and must be preserved across a flatten operatio...
static void register_with_read_factory()
Tells the BamReader how to create objects of type CollisionNode.
virtual PandaNode * make_copy() const
Returns a newly-allocated Node that is a shallow copy of this one.
get_from_collide_mask
Returns the current "from" CollideMask.
virtual bool is_collision_node() const
A simple downcast check.
virtual void xform(const LMatrix4 &mat)
Transforms the contents of this node by the indicated matrix, if it means anything to do so.
virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data)
This function will be called during the cull traversal to perform any additional operations that shou...
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
virtual CollideMask get_legal_collide_mask() const
Returns the subset of CollideMask bits that may be set for this particular type of PandaNode.
virtual int complete_pointers(TypedWritable **plist, BamReader *manager)
Receives an array of pointers, one for each time manager->read_pointer() was called in fillin().
virtual PandaNode * combine_with(PandaNode *other)
Collapses this node with the other node, if possible, and returns a pointer to the combined node,...
virtual void output(std::ostream &out) const
Writes a brief description of the node to the indicated output stream.
set_from_collide_mask
Sets the "from" CollideMask.
The abstract base class for all things that can collide with other things in the world,...
This collects together the pieces of data that are accumulated for each node while walking the scene ...
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling,...
void traverse(const NodePath &root)
Begins the traversal from the indicated node.
A class to retrieve the individual data elements previously stored in a Datagram.
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_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
This is another abstract class, for a general class of bounding volumes that actually enclose points ...
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition nodePath.h:159
A basic node of the scene graph or data graph.
Definition pandaNode.h:65
get_bounds_type
Returns the bounding volume type set with set_bounds_type().
Definition pandaNode.h:293
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition renderState.h:47
A thread; that is, a lightweight process.
Definition thread.h:46
Indicates a coordinate-system transform on vertices.
bool is_identity() const
Returns true if the transform represents the identity matrix, false otherwise.
TypeHandle is the identifier used to differentiate C++ class types.
Definition typeHandle.h:81
bool is_exact_type(TypeHandle handle) const
Returns true if the current object is the indicated type exactly.
Definition typedObject.I:38
Base class for objects that can be written to and read from Bam files.
virtual int complete_pointers(TypedWritable **p_list, BamReader *manager)
Receives an array of pointers, one for each time manager->read_pointer() was called in fillin().
This is our own Panda specialization on the default STL vector.
Definition pvector.h:42
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.