Panda3D
Loading...
Searching...
No Matches
portalNode.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 portalNode.cxx
10 * @author drose
11 * @date 2002-03-16
12 */
13
14#include "portalNode.h"
15
16#include "geomNode.h"
17#include "cullTraverserData.h"
18#include "cullTraverser.h"
19#include "renderState.h"
20#include "portalClipper.h"
21#include "transformState.h"
22#include "clipPlaneAttrib.h"
23#include "colorScaleAttrib.h"
24#include "transparencyAttrib.h"
25#include "datagram.h"
26#include "datagramIterator.h"
27#include "bamReader.h"
28#include "bamWriter.h"
29#include "boundingSphere.h"
30
31#include "plane.h"
32
33using std::endl;
34
35TypeHandle PortalNode::_type_handle;
36
37
38/**
39 * Default constructor, just an empty node, no geo This is used to read portal
40 * from model. You can also use this from python to create an empty portal.
41 * Then you can set the vertices yourself, with addVertex.
42 */
44PortalNode(const std::string &name) :
45 PandaNode(name),
46 _from_portal_mask(PortalMask::all_on()),
47 _into_portal_mask(PortalMask::all_on()),
48 _flags(0)
49{
50 set_cull_callback();
51
52 _visible = false;
53 _open = true;
54 _clip_plane = false;
55 _max_depth = 10;
56}
57
58/**
59 * Create a default rectangle as portal. Use this to create an arbitrary
60 * portal and setup from Python
61 */
63PortalNode(const std::string &name, LPoint3 pos, PN_stdfloat scale) :
64 PandaNode(name),
65 _from_portal_mask(PortalMask::all_on()),
66 _into_portal_mask(PortalMask::all_on()),
67 _flags(0)
68{
69 set_cull_callback();
70
71 add_vertex(LPoint3(pos[0]-1.0*scale, pos[1], pos[2]-1.0*scale));
72 add_vertex(LPoint3(pos[0]+1.0*scale, pos[1], pos[2]-1.0*scale));
73 add_vertex(LPoint3(pos[0]+1.0*scale, pos[1], pos[2]+1.0*scale));
74 add_vertex(LPoint3(pos[0]-1.0*scale, pos[1], pos[2]+1.0*scale));
75
76 _visible = false;
77 _open = true;
78 _clip_plane = false;
79 _max_depth = 10;
80}
81
82/**
83 *
84 */
86PortalNode(const PortalNode &copy) :
87 PandaNode(copy),
88 _from_portal_mask(copy._from_portal_mask),
89 _into_portal_mask(copy._into_portal_mask),
90 _flags(copy._flags),
91 _vertices(copy._vertices),
92 _cell_in(copy._cell_in),
93 _cell_out(copy._cell_out),
94 _clip_plane(copy._clip_plane),
95 _visible(copy._visible),
96 _open(copy._open),
97 _max_depth(copy._max_depth)
98{
99}
100
101/**
102 *
103 */
104PortalNode::
105~PortalNode() {
106}
107
108/**
109 * Returns a newly-allocated Node that is a shallow copy of this one. It will
110 * be a different Node pointer, but its internal data may or may not be shared
111 * with that of the original Node.
112 */
114make_copy() const {
115 return new PortalNode(*this);
116}
117
118/**
119 * Returns true if the node's name has extrinsic meaning and must be preserved
120 * across a flatten operation, false otherwise.
121 */
123preserve_name() const {
124 return true;
125}
126
127/**
128 * initialize the clipping planes and renderstate
129 */
132 _top_plane_node = new PlaneNode("top");
133 NodePath top_plane_np = NodePath(this).attach_new_node(_top_plane_node);
134
135 _bottom_plane_node = new PlaneNode("bottom");
136 NodePath bottom_plane_np = NodePath(this).attach_new_node(_bottom_plane_node);
137
138 _left_plane_node = new PlaneNode("left");
139 NodePath left_plane_np = NodePath(this).attach_new_node(_left_plane_node);
140
141 _right_plane_node = new PlaneNode("right");
142 NodePath right_plane_np = NodePath(this).attach_new_node(_right_plane_node);
143
144 CPT(RenderAttrib) plane_attrib = ClipPlaneAttrib::make();
145 plane_attrib = DCAST(ClipPlaneAttrib, plane_attrib)->add_on_plane(NodePath(top_plane_np));
146 plane_attrib = DCAST(ClipPlaneAttrib, plane_attrib)->add_on_plane(NodePath(bottom_plane_np));
147 plane_attrib = DCAST(ClipPlaneAttrib, plane_attrib)->add_on_plane(NodePath(left_plane_np));
148 plane_attrib = DCAST(ClipPlaneAttrib, plane_attrib)->add_on_plane(NodePath(right_plane_np));
149
150 _clip_state = RenderState::make(plane_attrib);
151}
152
153/**
154 * Transforms the contents of this node by the indicated matrix, if it means
155 * anything to do so. For most kinds of nodes, this does nothing.
156 */
158xform(const LMatrix4 &mat) {
159 nassertv(!mat.is_nan());
160
161}
162
163/**
164 * Collapses this node with the other node, if possible, and returns a pointer
165 * to the combined node, or NULL if the two nodes cannot safely be combined.
166 *
167 * The return value may be this, other, or a new node altogether.
168 *
169 * This function is called from GraphReducer::flatten(), and need not deal
170 * with children; its job is just to decide whether to collapse the two nodes
171 * and what the collapsed node should look like.
172 */
174combine_with(PandaNode *other) {
175 if (is_exact_type(get_class_type()) &&
176 other->is_exact_type(get_class_type())) {
177 // Two PortalNodes can combine, but only if they have the same name,
178 // because the name is often meaningful.
179 PortalNode *cother = DCAST(PortalNode, other);
180 if (get_name() == cother->get_name()) {
181 return this;
182 }
183
184 // Two PortalNodes with different names can't combine.
185 return nullptr;
186 }
187
188 return PandaNode::combine_with(other);
189}
190
191/**
192 * This function will be called during the cull traversal to perform reduced
193 * frustum culling. Basically, once the scenegraph comes across a portal
194 * node, it calculates a CulltraverserData with which cell, this portal leads
195 * out to and the new frustum. Then it traverses that child
196 *
197 * The return value is true if this node should be visible, or false if it
198 * should be culled.
199 */
202 Thread *current_thread = trav->get_current_thread();
203
204 PortalClipper *portal_viewer = trav->get_portal_clipper();
205 set_visible(false);
206 if (is_open() && !_cell_out.is_empty() && portal_viewer && data._portal_depth <= _max_depth) {
207 portal_cat.debug() << "checking portal node " << *this << endl;
208 portal_cat.debug() << "portal_depth is " << data._portal_depth << endl;
210 PT(BoundingVolume) reduced_frustum;
211
212 // remember old viewport and frustum, so we can restore them for the
213 // siblings. (it gets changed by the prepare_portal call)
214 LPoint2 old_reduced_viewport_min, old_reduced_viewport_max;
215 portal_viewer->get_reduced_viewport(old_reduced_viewport_min, old_reduced_viewport_max);
216 PT(BoundingHexahedron) old_bh = portal_viewer->get_reduced_frustum();
217
218 if (portal_viewer->prepare_portal(data.get_node_path())) {
219 if ((reduced_frustum = portal_viewer->get_reduced_frustum())) {
220 // remember current clip state, we might change it
221 CPT(RenderState) old_clip_state = portal_viewer->get_clip_state();
222
223 set_visible(true);
224 // The frustum is in camera space
225 vf = DCAST(GeometricBoundingVolume, reduced_frustum);
226
227 // create a copy of this reduced frustum, we'll transform it from
228 // camera space to the cell_out space
229 PT(BoundingHexahedron) new_bh = DCAST(BoundingHexahedron, vf->make_copy());
230
231 // Get the net trasform of the _cell_out as seen from the camera.
232 CPT(TransformState) cell_transform = _cell_out.get_net_transform();
233 CPT(TransformState) frustum_transform = cell_transform ->invert_compose(portal_viewer->_scene_setup->get_cull_center().get_net_transform());
234
235 // transform to _cell_out space
236 new_bh->xform(frustum_transform->get_mat());
237
238 CPT(RenderState) next_state = data._state;
239
240 // set clipping planes, if desired..
241 if (_clip_plane) {
242 // create a copy of this reduced frustum, we'll transform it from
243 // camera space to this portal node's space (because the clip planes
244 // are attached to this node)
245 PT(BoundingHexahedron) temp_bh = DCAST(BoundingHexahedron, vf->make_copy());
246 CPT(TransformState) temp_frustum_transform = data.get_node_path().get_net_transform()->invert_compose(portal_viewer->_scene_setup->get_cull_center().get_net_transform());
247
248 portal_cat.spam() << "clipping plane frustum transform " << *temp_frustum_transform << endl;
249 portal_cat.spam() << "frustum before transform " << *temp_bh << endl;
250 // transform to portalNode space
251 temp_bh->xform(temp_frustum_transform->get_mat());
252
253 portal_cat.spam() << "frustum after transform " << *temp_bh << endl;
254
255 _left_plane_node->set_plane(-temp_bh->get_plane(4)); // left plane of bh
256 _right_plane_node->set_plane(-temp_bh->get_plane(2));// right plane of bh
257 _top_plane_node->set_plane(-temp_bh->get_plane(3)); // top plane of bh
258 _bottom_plane_node->set_plane(-temp_bh->get_plane(1));// bottom plane of bh
259
260 portal_cat.spam() << "left plane " << *_left_plane_node << endl;
261 portal_cat.spam() << "right plane " << *_right_plane_node << endl;
262 portal_cat.spam() << "top plane " << *_top_plane_node << endl;
263 portal_cat.spam() << "bottom plane " << *_bottom_plane_node << endl;
264
265 // remember the clip state we just generated
266 portal_viewer->set_clip_state(_clip_state);
267
268 if (old_clip_state) {
269 portal_cat.spam() << "parent clip state " << *old_clip_state << endl;
270 } else {
271 portal_cat.spam() << "parent clip state None" << endl;
272 }
273 portal_cat.spam() << "own clip state " << *_clip_state << endl;
274 portal_cat.spam() << "next state " << *next_state << endl;
275
276 // undo parent clip state and compose our new clip state ito the new
277 // state
278 if (old_clip_state != nullptr) {
279 next_state = old_clip_state->invert_compose(next_state);
280 portal_cat.spam() << "next state after removing parent state " << *next_state << endl;
281 }
282 next_state = next_state->compose(_clip_state);
283 portal_cat.spam() << "next state after composition " << *next_state << endl;
284 }
285
286 CullTraverserData next_data(_cell_out,
287 cell_transform,
288 next_state, new_bh,
289 current_thread);
290 next_data._portal_depth = data._portal_depth + 1;
291
292 portal_viewer->set_reduced_frustum(new_bh);
293 portal_cat.spam() << "cull_callback: before traversing " << _cell_out.get_name() << endl;
294 trav->traverse_below(next_data);
295 portal_cat.spam() << "cull_callback: after traversing " << _cell_out.get_name() << endl;
296
297 // restore clip state
298 portal_viewer->set_clip_state(old_clip_state);
299 }
300 }
301 // reset portal viewer frustum for the siblings;
302 portal_viewer->set_reduced_frustum(old_bh);
303 // reset portal viewer viewport for the siblings;
304 portal_viewer->set_reduced_viewport(old_reduced_viewport_min, old_reduced_viewport_max);
305 }
306 // Now carry on to render our child nodes.
307 return true;
308}
309
310/**
311 * Returns true if there is some value to visiting this particular node during
312 * the cull traversal for any camera, false otherwise. This will be used to
313 * optimize the result of get_net_draw_show_mask(), so that any subtrees that
314 * contain only nodes for which is_renderable() is false need not be visited.
315 */
317is_renderable() const {
318 return true;
319}
320
321
322/**
323 * Writes a brief description of the node to the indicated output stream.
324 * This is invoked by the << operator. It may be overridden in derived
325 * classes to include some information relevant to the class.
326 */
328output(std::ostream &out) const {
329 PandaNode::output(out);
330}
331
332/**
333 * Draws the vertices of this portal rectangle to the screen with a line
334 */
335/*
336void PortalNode::
337draw() const {
338 move_to(get_vertex(0));
339 draw_to(get_vertex(1));
340 draw_to(get_vertex(2));
341 draw_to(get_vertex(3));
342}
343*/
344
345/**
346 * Called when needed to recompute the node's _internal_bound object. Nodes
347 * that contain anything of substance should redefine this to do the right
348 * thing.
349 */
350void PortalNode::
351compute_internal_bounds(CPT(BoundingVolume) &internal_bounds,
352 int &internal_vertices,
353 int pipeline_stage,
354 Thread *current_thread) const {
355 // First, get ourselves a fresh, empty bounding volume.
356 PT(BoundingVolume) bound = new BoundingSphere;
358
359 // Now actually compute the bounding volume by putting it around all of our
360 // vertices.
361
362 const LPoint3 *vertices_begin = &_vertices[0];
363 const LPoint3 *vertices_end = vertices_begin + _vertices.size();
364
365 // Now actually compute the bounding volume by putting it around all
366 gbv->around(vertices_begin, vertices_end);
367
368 internal_bounds = bound;
369 internal_vertices = 0;
370}
371
372/**
373 * Returns a RenderState for rendering the ghosted portal rectangle that
374 * represents the previous frame's position, for those collision nodes that
375 * indicate a velocity.
376 */
377CPT(RenderState) PortalNode::
378get_last_pos_state() {
379 // Once someone asks for this pointer, we hold its reference count and never
380 // free it.
381 static CPT(RenderState) state = nullptr;
382 if (state == nullptr) {
383 state = RenderState::make
384 (ColorScaleAttrib::make(LVecBase4(1.0f, 1.0f, 1.0f, 0.5f)),
385 TransparencyAttrib::make(TransparencyAttrib::M_alpha));
386 }
387
388 return state;
389}
390
391
392/**
393 * Tells the BamReader how to create objects of type PortalNode.
394 */
397 BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
398}
399
400/**
401 * Writes the contents of this object to the datagram for shipping out to a
402 * Bam file.
403 */
405write_datagram(BamWriter *manager, Datagram &dg) {
406 PandaNode::write_datagram(manager, dg);
407
408 dg.add_uint16(_vertices.size());
409 for (Vertices::const_iterator vi = _vertices.begin();
410 vi != _vertices.end();
411 ++vi) {
412 (*vi).write_datagram(dg);
413 }
414}
415
416/**
417 * Receives an array of pointers, one for each time manager->read_pointer()
418 * was called in fillin(). Returns the number of pointers processed.
419 */
421complete_pointers(TypedWritable **p_list, BamReader *manager) {
422 int pi = PandaNode::complete_pointers(p_list, manager);
423
424 return pi;
425}
426
427/**
428 * This function is called by the BamReader's factory when a new object of
429 * type PortalNode is encountered in the Bam file. It should create the
430 * PortalNode and extract its information from the file.
431 */
432TypedWritable *PortalNode::
433make_from_bam(const FactoryParams &params) {
434 PortalNode *node = new PortalNode("");
435 DatagramIterator scan;
436 BamReader *manager;
437
438 parse_params(params, scan, manager);
439 node->fillin(scan, manager);
440
441 return node;
442}
443
444/**
445 * This internal function is called by make_from_bam to read in all of the
446 * relevant data from the BamFile for the new PortalNode.
447 */
448void PortalNode::
449fillin(DatagramIterator &scan, BamReader *manager) {
450 PandaNode::fillin(scan, manager);
451
452 int num_vertices = scan.get_uint16();
453 _vertices.reserve(num_vertices);
454 for (int i = 0; i < num_vertices; i++) {
455 LPoint3 vertex;
456 vertex.read_datagram(scan);
457 _vertices.push_back(vertex);
458 }
459
460 /*
461 _from_portal_mask.set_word(scan.get_uint32());
462 _into_portal_mask.set_word(scan.get_uint32());
463 _flags = scan.get_uint8();
464 */
465}
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.
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 defines a bounding convex hexahedron.
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...
This functions similarly to a LightAttrib.
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,...
PortalClipper * get_portal_clipper() const
Returns the _portal_clipper pointer.
Thread * get_current_thread() const
Returns the currently-executing thread object, as passed to the CullTraverser constructor.
virtual void traverse_below(CullTraverserData &data)
Traverses all the children of the indicated node, with the given data, which has been converted into ...
GeometricBoundingVolume * get_view_frustum() const
Returns the bounding volume that corresponds to the view frustum, or NULL if the view frustum is not ...
A class to retrieve the individual data elements previously stored in a Datagram.
uint16_t get_uint16()
Extracts an unsigned 16-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_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 ...
bool around(const GeometricBoundingVolume **first, const GeometricBoundingVolume **last)
Resets the volume to enclose only the volumes indicated.
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition nodePath.h:159
bool is_empty() const
Returns true if the NodePath contains no nodes.
Definition nodePath.I:188
NodePath attach_new_node(PandaNode *node, int sort=0, Thread *current_thread=Thread::get_current_thread()) const
Attaches a new node, with or without existing parents, to the scene graph below the referenced node o...
Definition nodePath.cxx:599
get_name
Returns the name of the referenced node.
Definition nodePath.h:951
A basic node of the scene graph or data graph.
Definition pandaNode.h:65
virtual PandaNode * combine_with(PandaNode *other)
Collapses this PandaNode with the other PandaNode, if possible, and returns a pointer to the combined...
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
A node that contains a plane.
Definition planeNode.h:36
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling,...
const RenderState * get_clip_state() const
Returns the stored clip state.
void get_reduced_viewport(LPoint2 &min, LPoint2 &max) const
Return the reduced viewport.
BoundingHexahedron * get_reduced_frustum() const
Return the reduced frustum.
void set_reduced_viewport(const LPoint2 &min, const LPoint2 &max)
Set the current viewport that is being used by the portal clipper.
void set_reduced_frustum(BoundingHexahedron *bh)
Set the current view frustum that is being calculated by the portal clipper.
bool prepare_portal(const NodePath &node_path)
Given the portal draw the frustum with line segs for now.
void set_clip_state(const RenderState *clip_state)
Set the clip state of the current portal node This is done to remember the state for the child portal...
A node in the scene graph that can hold a Portal Polygon, which is a rectangle.
Definition portalNode.h:30
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 * make_copy() const
Returns a newly-allocated Node that is a shallow copy of this one.
virtual bool is_renderable() const
Returns true if there is some value to visiting this particular node during the cull traversal for an...
virtual void xform(const LMatrix4 &mat)
Transforms the contents of this node by the indicated matrix, if it means anything to do so.
static void register_with_read_factory()
Tells the BamReader how to create objects of type PortalNode.
virtual bool preserve_name() const
Returns true if the node's name has extrinsic meaning and must be preserved across a flatten operatio...
void add_vertex(const LPoint3 &vertex)
Adds a new vertex to the portal polygon.
Definition portalNode.I:109
virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data)
This function will be called during the cull traversal to perform reduced frustum culling.
virtual void enable_clipping_planes()
initialize the clipping planes and renderstate
virtual PandaNode * combine_with(PandaNode *other)
Collapses this node with the other node, if possible, and returns a pointer to the combined node,...
set_visible
this is set if the portal is facing camera
Definition portalNode.h:96
PortalNode(const std::string &name)
Default constructor, just an empty node, no geo This is used to read portal from model.
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
is_open
Is this portal open from current camera zone.
Definition portalNode.h:98
virtual void output(std::ostream &out) const
Writes a brief description of the node to the indicated output stream.
This is the base class for a number of render attributes (other than transform) that may be set on sc...
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition renderState.h:47
const NodePath & get_cull_center() const
Returns the point from which the culling operations will be performed.
Definition sceneSetup.I:161
A thread; that is, a lightweight process.
Definition thread.h:46
Indicates a coordinate-system transform on vertices.
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().
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.