Panda3D
 All Classes Functions Variables Enumerations
cullTraverserData.cxx
1 // Filename: cullTraverserData.cxx
2 // Created by: drose (06Mar02)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "cullTraverserData.h"
16 #include "cullTraverser.h"
17 #include "config_pgraph.h"
18 #include "pandaNode.h"
19 #include "colorAttrib.h"
20 #include "textureAttrib.h"
21 #include "renderModeAttrib.h"
22 #include "clipPlaneAttrib.h"
23 #include "boundingPlane.h"
24 #include "billboardEffect.h"
25 #include "compassEffect.h"
26 #include "occluderEffect.h"
27 #include "polylightEffect.h"
28 #include "renderState.h"
29 
30 
31 ////////////////////////////////////////////////////////////////////
32 // Function: CullTraverserData::apply_transform_and_state
33 // Access: Published
34 // Description: Applies the transform and state from the current
35 // node onto the current data. This also evaluates
36 // billboards, etc.
37 ////////////////////////////////////////////////////////////////////
40  CPT(RenderState) node_state = _node_reader.get_state();
41 
42  if (trav->has_tag_state_key() &&
43  _node_reader.has_tag(trav->get_tag_state_key())) {
44  // Here's a node that has been tagged with the special key for our
45  // current camera. This indicates some special state transition
46  // for this node, which is unique to this camera.
47  const Camera *camera = trav->get_scene()->get_camera_node();
48  string tag_state = _node_reader.get_tag(trav->get_tag_state_key());
49  node_state = node_state->compose(camera->get_tag_state(tag_state));
50  }
51  _node_reader.compose_draw_mask(_draw_mask);
52 
53  apply_transform_and_state(trav, _node_reader.get_transform(),
54  node_state, _node_reader.get_effects(),
55  _node_reader.get_off_clip_planes());
56 }
57 
58 ////////////////////////////////////////////////////////////////////
59 // Function: CullTraverserData::apply_transform_and_state
60 // Access: Published
61 // Description: Applies the indicated transform and state changes
62 // (e.g. as extracted from a node) onto the current
63 // data. This also evaluates billboards, etc.
64 ////////////////////////////////////////////////////////////////////
67  CPT(TransformState) node_transform,
68  CPT(RenderState) node_state,
69  CPT(RenderEffects) node_effects,
70  const RenderAttrib *off_clip_planes) {
71  if (node_effects->has_cull_callback()) {
72  node_effects->cull_callback(trav, *this, node_transform, node_state);
73  }
74 
75  if (!node_transform->is_identity()) {
76  _net_transform = _net_transform->compose(node_transform);
77 
78  if ((_view_frustum != (GeometricBoundingVolume *)NULL) ||
79  (!_cull_planes->is_empty())) {
80  // We need to move the viewing frustums into the node's
81  // coordinate space by applying the node's inverse transform.
82  if (node_transform->is_singular()) {
83  // But we can't invert a singular transform! Instead of
84  // trying, we'll just give up on frustum culling from this
85  // point down.
86  _view_frustum = (GeometricBoundingVolume *)NULL;
87  _cull_planes = CullPlanes::make_empty();
88 
89  } else {
90  CPT(TransformState) inv_transform =
91  node_transform->invert_compose(TransformState::make_identity());
92 
93  // Copy the bounding volumes for the frustums so we can
94  // transform them.
95  if (_view_frustum != (GeometricBoundingVolume *)NULL) {
96  _view_frustum = DCAST(GeometricBoundingVolume, _view_frustum->make_copy());
97  _view_frustum->xform(inv_transform->get_mat());
98  }
99 
100  _cull_planes = _cull_planes->xform(inv_transform->get_mat());
101  }
102  }
103  }
104 
105  _state = _state->compose(node_state);
106 
107  if (clip_plane_cull) {
108  _cull_planes = _cull_planes->apply_state(trav, this,
109  DCAST(ClipPlaneAttrib, node_state->get_attrib(ClipPlaneAttrib::get_class_slot())),
110  DCAST(ClipPlaneAttrib, off_clip_planes),
111  DCAST(OccluderEffect, node_effects->get_effect(OccluderEffect::get_class_type())));
112  }
113 }
114 
115 ////////////////////////////////////////////////////////////////////
116 // Function: CullTraverserData::is_in_view_impl
117 // Access: Private
118 // Description: The private implementation of is_in_view().
119 ////////////////////////////////////////////////////////////////////
120 bool CullTraverserData::
121 is_in_view_impl() {
122  const GeometricBoundingVolume *node_gbv = NULL;
123 
124  if (_view_frustum != (GeometricBoundingVolume *)NULL) {
125  DCAST_INTO_R(node_gbv, _node_reader.get_bounds(), false)
126 
127  int result = _view_frustum->contains(node_gbv);
128 
129  if (pgraph_cat.is_spam()) {
130  pgraph_cat.spam()
131  << _node_path << " cull result = " << hex << result << dec << "\n";
132  }
133 
134  if (result == BoundingVolume::IF_no_intersection) {
135  // No intersection at all. Cull.
136 #ifdef NDEBUG
137  return false;
138 #else
139  if (!fake_view_frustum_cull) {
140  return false;
141  }
142 
143  // If we have fake view-frustum culling enabled, instead of
144  // actually culling an object we simply force it to be drawn in
145  // red wireframe.
146  _view_frustum = (GeometricBoundingVolume *)NULL;
147  CPT(RenderState) fake_state = get_fake_view_frustum_cull_state();
148  _state = _state->compose(fake_state);
149 #endif
150 
151  } else if ((result & BoundingVolume::IF_all) != 0) {
152  // The node and its descendents are completely enclosed within
153  // the frustum. No need to cull further.
154  _view_frustum = (GeometricBoundingVolume *)NULL;
155 
156  } else {
157  // The node is partially, but not completely, within the viewing
158  // frustum.
159  if (_node_reader.is_final()) {
160  // Normally we'd keep testing child bounding volumes as we
161  // continue down. But this node has the "final" flag, so the
162  // user is claiming that there is some important reason we
163  // should consider everything visible at this point. So be it.
164  _view_frustum = (GeometricBoundingVolume *)NULL;
165  }
166  }
167  }
168 
169  if (!_cull_planes->is_empty()) {
170  if (node_gbv == (const GeometricBoundingVolume *)NULL) {
171  DCAST_INTO_R(node_gbv, _node_reader.get_bounds(), false)
172  }
173 
174  // Also cull against the current clip planes.
175  int result;
176  _cull_planes = _cull_planes->do_cull(result, _state, node_gbv);
177 
178  if (pgraph_cat.is_spam()) {
179  pgraph_cat.spam()
180  << _node_path << " cull planes cull result = " << hex
181  << result << dec << "\n";
182  _cull_planes->write(pgraph_cat.spam(false));
183  }
184 
185  if (_node_reader.is_final()) {
186  // Even though the node may be partially within the clip planes,
187  // do no more culling against them below this node.
188  _cull_planes = CullPlanes::make_empty();
189 
190  if (pgraph_cat.is_spam()) {
191  pgraph_cat.spam()
192  << _node_path << " is_final, cull planes disabled, state:\n";
193  _state->write(pgraph_cat.spam(false), 2);
194  }
195  }
196 
197  if (result == BoundingVolume::IF_no_intersection) {
198  // No intersection at all. Cull.
199 #ifdef NDEBUG
200  return false;
201 #else
202  if (!fake_view_frustum_cull) {
203  return false;
204  }
205  _cull_planes = CullPlanes::make_empty();
206  CPT(RenderState) fake_state = get_fake_view_frustum_cull_state();
207  _state = _state->compose(fake_state);
208 #endif
209 
210  } else if ((result & BoundingVolume::IF_all) != 0) {
211  // The node and its descendents are completely in front of all
212  // of the clip planes and occluders. The do_cull() call should
213  // therefore have removed all of the clip planes and occluders.
214  nassertr(_cull_planes->is_empty(), true);
215  }
216  }
217 
218  return true;
219 }
220 
221 ////////////////////////////////////////////////////////////////////
222 // Function: CullTraverserData::get_fake_view_frustum_cull_state
223 // Access: Private, Static
224 // Description: Returns a RenderState for rendering stuff in red
225 // wireframe, strictly for the fake_view_frustum_cull
226 // effect.
227 ////////////////////////////////////////////////////////////////////
229 get_fake_view_frustum_cull_state() {
230 #ifdef NDEBUG
231  return NULL;
232 #else
233  // Once someone asks for this pointer, we hold its reference count
234  // and never free it.
235  static CPT(RenderState) state = (const RenderState *)NULL;
236  if (state == (const RenderState *)NULL) {
237  state = RenderState::make
238  (ColorAttrib::make_flat(LColor(1.0f, 0.0f, 0.0f, 1.0f)),
239  TextureAttrib::make_all_off(),
240  RenderModeAttrib::make(RenderModeAttrib::M_wireframe),
242  }
243  return state;
244 #endif
245 }
bool has_cull_callback() const
This function is provided as an optimization, to speed up the render-time checking for the existance ...
This is the base class for a number of render attributes (other than transform) that may be set on sc...
Definition: renderAttrib.h:60
void compose_draw_mask(DrawMask &running_draw_mask) const
Computes the result of applying this node&#39;s draw masks to a running draw mask, as during a traversal...
Definition: pandaNode.I:1526
static int get_max_priority()
Returns the maximum priority number (sometimes called override) that may be set on any node...
This collects together the pieces of data that are accumulated for each node while walking the scene ...
This functions similarly to a LightAttrib.
bool is_final() const
Returns the current state of the &quot;final&quot; flag.
Definition: pandaNode.I:1870
SceneSetup * get_scene() const
Returns the SceneSetup object.
Definition: cullTraverser.I:43
Camera * get_camera_node() const
Returns the camera used to render the scene.
Definition: sceneSetup.I:144
const TransformState * get_transform() const
Returns the transform that has been set on this particular node.
Definition: pandaNode.I:1755
bool has_tag(const string &key) const
Returns true if a value has been defined on this node for the particular key (even if that value is t...
Definition: pandaNode.I:1797
This is another abstract class, for a general class of bounding volumes that actually enclose points ...
const RenderEffect * get_effect(int n) const
Returns the nth effect in the state.
void cull_callback(CullTraverser *trav, CullTraverserData &data, CPT(TransformState)&node_transform, CPT(RenderState)&node_state) const
Calls cull_callback() on all effects.
This functions similarly to a LightAttrib or ClipPlaneAttrib.
bool has_tag_state_key() const
Returns true if a nonempty tag state key has been specified for the scene&#39;s camera, false otherwise.
Definition: cullTraverser.I:54
const string & get_tag_state_key() const
Returns the tag state key that has been specified for the scene&#39;s camera, if any. ...
Definition: cullTraverser.I:65
const RenderAttrib * get_attrib(TypeHandle type) const
Looks for a RenderAttrib of the indicated type in the state, and returns it if it is found...
Definition: renderState.I:134
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition: renderState.h:53
const RenderState * get_state() const
Returns the complete RenderState that will be applied to all nodes at this level and below...
Definition: pandaNode.I:1731
This is the base class for all three-component vectors and points.
Definition: lvecBase4.h:111
const RenderEffects * get_effects() const
Returns the complete RenderEffects that will be applied to this node.
Definition: pandaNode.I:1742
void apply_transform_and_state(CullTraverser *trav)
Applies the transform and state from the current node onto the current data.
string get_tag(const string &key) const
Retrieves the user-defined value that was previously set on this node for the particular key...
Definition: pandaNode.I:1780
A node that can be positioned around in the scene graph to represent a point of view for rendering a ...
Definition: camera.h:37
This represents a unique collection of RenderEffect objects that correspond to a particular renderabl...
Definition: renderEffects.h:46
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling...
Definition: cullTraverser.h:48