Panda3D
 All Classes Functions Variables Enumerations
cullResult.cxx
1 // Filename: cullResult.cxx
2 // Created by: drose (28Feb02)
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 "cullResult.h"
16 #include "cullBinManager.h"
17 #include "cullBinAttrib.h"
18 #include "textureAttrib.h"
19 #include "lightAttrib.h"
20 #include "colorAttrib.h"
21 #include "alphaTestAttrib.h"
22 #include "depthWriteAttrib.h"
23 #include "colorScaleAttrib.h"
24 #include "fogAttrib.h"
25 #include "transparencyAttrib.h"
26 #include "renderState.h"
27 #include "clockObject.h"
28 #include "config_pgraph.h"
29 #include "depthOffsetAttrib.h"
30 #include "colorBlendAttrib.h"
31 
32 TypeHandle CullResult::_type_handle;
33 
34 // This value is used instead of 1.0 to represent the alpha level of a
35 // pixel that is to be considered "opaque" for the purposes of M_dual.
36 //
37 // Ideally, 1.0 is the only correct value for this. Realistically, we
38 // have to fudge it lower for two reasons:
39 //
40 // (1) The modelers tend to paint textures with very slight
41 // transparency levels in places that are not intended to be
42 // transparent, without realizing it. These very faint transparency
43 // regions are normally (almost) invisible, but when rendered with
44 // M_dual they may be revealed as regions of poor alpha sorting.
45 //
46 // (2) There seems to be some problem in DX where, in certain
47 // circumstances apparently related to automatic texture management,
48 // it spontaneously drops out the bottom two bits of an eight-bit
49 // alpha channel, causing a value of 255 to become a value of 252
50 // instead.
51 //
52 // We use 256 as the denominator here (instead of, say, 255) because a
53 // fractional power of two will have a terminating representation in
54 // base 2, and thus will be more likely to have a precise value in
55 // whatever internal representation the graphics API will use.
56 static const PN_stdfloat dual_opaque_level = 252.0 / 256.0;
57 static const double bin_color_flash_rate = 1.0; // 1 state change per second
58 
59 ////////////////////////////////////////////////////////////////////
60 // Function: CullResult::Constructor
61 // Access: Public
62 // Description:
63 ////////////////////////////////////////////////////////////////////
64 CullResult::
65 CullResult(GraphicsStateGuardianBase *gsg,
66  const PStatCollector &draw_region_pcollector) :
67  _gsg(gsg),
68  _draw_region_pcollector(draw_region_pcollector)
69 {
70 #ifdef DO_MEMORY_USAGE
71  MemoryUsage::update_type(this, get_class_type());
72 #endif
73 
74 #ifndef NDEBUG
75  _show_transparency = show_transparency.get_value();
76 #endif
77 }
78 
79 ////////////////////////////////////////////////////////////////////
80 // Function: CullResult::make_next
81 // Access: Published
82 // Description: Returns a newly-allocated CullResult object that
83 // contains a copy of just the subset of the data from
84 // this CullResult object that is worth keeping around
85 // for next frame.
86 ////////////////////////////////////////////////////////////////////
88 make_next() const {
89  PT(CullResult) new_result = new CullResult(_gsg, _draw_region_pcollector);
90  new_result->_bins.reserve(_bins.size());
91 
92  CullBinManager *bin_manager = CullBinManager::get_global_ptr();
93 
94  for (size_t i = 0; i < _bins.size(); ++i) {
95  CullBin *old_bin = _bins[i];
96  if (old_bin == (CullBin *)NULL ||
97  old_bin->get_bin_type() != bin_manager->get_bin_type(i)) {
98  new_result->_bins.push_back((CullBin *)NULL);
99  } else {
100  new_result->_bins.push_back(old_bin->make_next());
101  }
102  }
103 
104  return new_result;
105 }
106 
107 ////////////////////////////////////////////////////////////////////
108 // Function: CullResult::add_object
109 // Access: Published
110 // Description: Adds the indicated CullableObject to the appropriate
111 // bin. The bin becomes the owner of the object
112 // pointer, and will eventually delete it.
113 ////////////////////////////////////////////////////////////////////
114 void CullResult::
115 add_object(CullableObject *object, const CullTraverser *traverser) {
116  static const LColor flash_alpha_color(0.92, 0.96, 0.10, 1.0f);
117  static const LColor flash_binary_color(0.21f, 0.67f, 0.24, 1.0f);
118  static const LColor flash_multisample_color(0.78f, 0.05f, 0.81f, 1.0f);
119  static const LColor flash_dual_color(0.92, 0.01f, 0.01f, 1.0f);
120 
121  bool force = !traverser->get_effective_incomplete_render();
122  Thread *current_thread = traverser->get_current_thread();
124 
125  // Check to see if there's a special transparency setting.
126  const RenderState *state = object->_state;
127  nassertv(state != (const RenderState *)NULL);
128 
129  const TransparencyAttrib *trans = (const TransparencyAttrib *)
130  state->get_attrib(TransparencyAttrib::get_class_slot());
131 
132  if (trans != (const TransparencyAttrib *)NULL) {
133  switch (trans->get_mode()) {
134  case TransparencyAttrib::M_alpha:
135  // M_alpha implies an alpha-write test, so we don't waste time
136  // writing 0-valued pixels.
137  object->_state = state->compose(get_alpha_state());
138  check_flash_transparency(object->_state, flash_alpha_color);
139  break;
140 
141  case TransparencyAttrib::M_binary:
142  // M_binary is implemented by explicitly setting the alpha test.
143  object->_state = state->compose(get_binary_state());
144  check_flash_transparency(object->_state, flash_binary_color);
145  break;
146 
147  case TransparencyAttrib::M_multisample:
148  case TransparencyAttrib::M_multisample_mask:
149  // The multisample modes are implemented using M_binary if the
150  // GSG in use doesn't support multisample.
151  if (!_gsg->get_supports_multisample()) {
152  object->_state = state->compose(get_binary_state());
153  }
154  check_flash_transparency(object->_state, flash_multisample_color);
155  break;
156 
157  case TransparencyAttrib::M_dual:
158 #ifndef NDEBUG
159  check_flash_transparency(object->_state, flash_dual_color);
160  state = object->_state;
161 #endif
162  if (!m_dual) {
163  // If m_dual is configured off, it becomes M_alpha.
164  break;
165  }
166 
167  // M_dual is implemented by drawing the opaque parts first,
168  // without transparency, then drawing the transparent parts
169  // later. This means we must copy the object and add it to
170  // both bins. We can only do this if we do not have an
171  // explicit bin already applied; otherwise, M_dual falls back
172  // to M_alpha.
173  {
174  const CullBinAttrib *bin_attrib = (const CullBinAttrib *)
175  state->get_attrib(CullBinAttrib::get_class_slot());
176 
177  if (bin_attrib == (CullBinAttrib *)NULL ||
178  bin_attrib->get_bin_name().empty()) {
179  // We make a copy of the object to draw the transparent part;
180  // this gets placed in the transparent bin.
181 #ifndef NDEBUG
182  if (m_dual_transparent)
183 #endif
184  {
185  CullableObject *transparent_part = new CullableObject(*object);
186  CPT(RenderState) transparent_state = get_dual_transparent_state();
187  transparent_part->_state = state->compose(transparent_state);
188  if (transparent_part->munge_geom
189  (_gsg, _gsg->get_geom_munger(transparent_part->_state, current_thread),
190  traverser, force)) {
191  int transparent_bin_index = transparent_part->_state->get_bin_index();
192  CullBin *bin = get_bin(transparent_bin_index);
193  nassertv(bin != (CullBin *)NULL);
194  check_flash_bin(transparent_part->_state, bin_manager, transparent_bin_index);
195  bin->add_object(transparent_part, current_thread);
196  } else {
197  delete transparent_part;
198  }
199  }
200 
201  // Now we can draw the opaque part. This will end up in
202  // the opaque bin.
203  object->_state = state->compose(get_dual_opaque_state());
204 #ifndef NDEBUG
205  if (!m_dual_opaque) {
206  delete object;
207  return;
208  }
209 #endif
210  }
211  // The object is assigned to a specific bin; M_dual becomes
212  // M_alpha.
213  }
214  break;
215 
216  default:
217  // Other kinds of transparency need no special handling.
218  break;
219  }
220  }
221 
222  // Check for a special wireframe setting.
223  const RenderModeAttrib *rmode = (const RenderModeAttrib *)
224  object->_state->get_attrib(RenderModeAttrib::get_class_slot());
225  if (rmode != (const RenderModeAttrib *)NULL) {
226  if (rmode->get_mode() == RenderModeAttrib::M_filled_wireframe) {
227  CullableObject *wireframe_part = new CullableObject(*object);
228  wireframe_part->_state = get_wireframe_overlay_state(rmode);
229 
230  if (wireframe_part->munge_geom
231  (_gsg, _gsg->get_geom_munger(wireframe_part->_state, current_thread),
232  traverser, force)) {
233  int wireframe_bin_index = bin_manager->find_bin("fixed");
234  CullBin *bin = get_bin(wireframe_bin_index);
235  nassertv(bin != (CullBin *)NULL);
236  check_flash_bin(wireframe_part->_state, bin_manager, wireframe_bin_index);
237  bin->add_object(wireframe_part, current_thread);
238  } else {
239  delete wireframe_part;
240  }
241 
242  object->_state = object->_state->set_attrib(RenderModeAttrib::make(RenderModeAttrib::M_filled));
243  }
244  }
245 
246  int bin_index = object->_state->get_bin_index();
247  CullBin *bin = get_bin(bin_index);
248  nassertv(bin != (CullBin *)NULL);
249  check_flash_bin(object->_state, bin_manager, bin_index);
250 
251  // Munge vertices as needed for the GSG's requirements, and the
252  // object's current state.
253  if (object->munge_geom(_gsg, _gsg->get_geom_munger(object->_state, current_thread), traverser, force)) {
254  // The object may or may not now be fully resident, but this may
255  // not matter, since the GSG may have the necessary buffers
256  // already loaded. We'll let the GSG ultimately decide whether to
257  // render it.
258  bin->add_object(object, current_thread);
259  } else {
260  delete object;
261  }
262 }
263 
264 ////////////////////////////////////////////////////////////////////
265 // Function: CullResult::finish_cull
266 // Access: Published
267 // Description: Called after all the geoms have been added, this
268 // indicates that the cull process is finished for this
269 // frame and gives the bins a chance to do any
270 // post-processing (like sorting) before moving on to
271 // draw.
272 ////////////////////////////////////////////////////////////////////
273 void CullResult::
274 finish_cull(SceneSetup *scene_setup, Thread *current_thread) {
276 
277  for (size_t i = 0; i < _bins.size(); ++i) {
278  if (!bin_manager->get_bin_active(i)) {
279  // If the bin isn't active, don't sort it, and don't draw it.
280  // In fact, clear it.
281  _bins[i] = NULL;
282 
283  } else {
284  CullBin *bin = _bins[i];
285  if (bin != (CullBin *)NULL) {
286  bin->finish_cull(scene_setup, current_thread);
287  }
288  }
289  }
290 }
291 
292 ////////////////////////////////////////////////////////////////////
293 // Function: CullResult::draw
294 // Access: Published
295 // Description: Asks all the bins to draw themselves in the correct
296 // order.
297 ////////////////////////////////////////////////////////////////////
298 void CullResult::
299 draw(Thread *current_thread) {
300  bool force = !_gsg->get_effective_incomplete_render();
301 
302  // Ask the bin manager for the correct order to draw all the bins.
304  int num_bins = bin_manager->get_num_bins();
305  for (int i = 0; i < num_bins; i++) {
306  int bin_index = bin_manager->get_bin(i);
307  nassertv(bin_index >= 0);
308 
309  if (bin_index < (int)_bins.size() && _bins[bin_index] != (CullBin *)NULL) {
310  _bins[bin_index]->draw(force, current_thread);
311  }
312  }
313 }
314 
315 ////////////////////////////////////////////////////////////////////
316 // Function: CullResult::make_result_graph
317 // Access: Published
318 // Description: Returns a special scene graph constructed to
319 // represent the results of the cull. This will be a
320 // hierarchy of nodes, one node for each bin, each of
321 // which will in term be a parent of a number of
322 // GeomNodes, representing the geometry drawn in each
323 // bin.
324 //
325 // This is useful mainly for high-level debugging and
326 // abstraction tools; it should not be mistaken for the
327 // low-level cull result itself. For the low-level cull
328 // result, use draw() to efficiently draw the culled
329 // scene.
330 ////////////////////////////////////////////////////////////////////
331 PT(PandaNode) CullResult::
332 make_result_graph() {
333  PT(PandaNode) root_node = new PandaNode("cull_result");
334 
335  // Ask the bin manager for the correct order to draw all the bins.
336  CullBinManager *bin_manager = CullBinManager::get_global_ptr();
337  int num_bins = bin_manager->get_num_bins();
338  for (int i = 0; i < num_bins; i++) {
339  int bin_index = bin_manager->get_bin(i);
340  nassertr(bin_index >= 0, NULL);
341 
342  if (bin_index < (int)_bins.size() && _bins[bin_index] != (CullBin *)NULL) {
343  root_node->add_child(_bins[bin_index]->make_result_graph());
344  }
345  }
346 
347  return root_node;
348 }
349 
350 ////////////////////////////////////////////////////////////////////
351 // Function: CullResult::bin_removed
352 // Access: Public, Static
353 // Description: Intended to be called by
354 // CullBinManager::remove_bin(), this informs all the
355 // CullResults in the world to remove the indicated
356 // bin_index from their cache if it has been cached.
357 ////////////////////////////////////////////////////////////////////
358 void CullResult::
359 bin_removed(int bin_index) {
360  // Do something here.
361  nassertv(false);
362 }
363 
364 ////////////////////////////////////////////////////////////////////
365 // Function: CullResult::make_new_bin
366 // Access: Private
367 // Description: Allocates a new CullBin for the given bin_index and
368 // stores it for next time.
369 ////////////////////////////////////////////////////////////////////
370 CullBin *CullResult::
371 make_new_bin(int bin_index) {
373  PT(CullBin) bin = bin_manager->make_new_bin(bin_index, _gsg,
374  _draw_region_pcollector);
375  CullBin *bin_ptr = bin.p();
376 
377  if (bin_ptr != (CullBin *)NULL) {
378  // Now store it in the vector.
379  while (bin_index >= (int)_bins.size()) {
380  _bins.push_back((CullBin *)NULL);
381  }
382  nassertr(bin_index >= 0 && bin_index < (int)_bins.size(), NULL);
383 
384  // Prevent unnecessary ref/unref by swapping the PointerTos.
385  swap(_bins[bin_index], bin);
386  }
387 
388  return bin_ptr;
389 }
390 
391 ////////////////////////////////////////////////////////////////////
392 // Function: CullResult::get_alpha_state
393 // Access: Private
394 // Description: Returns a RenderState that changes the alpha test to
395 // > 0, for implementing M_alpha.
396 ////////////////////////////////////////////////////////////////////
397 CPT(RenderState) CullResult::
398 get_alpha_state() {
399  static CPT(RenderState) state = NULL;
400  if (state == (const RenderState *)NULL) {
401  // We don't monkey with the priority, since we want to allow the
402  // user to override this if he desires.
403  state = RenderState::make(AlphaTestAttrib::make(AlphaTestAttrib::M_greater, 0.0f));
404  }
405  return state;
406 }
407 
408 ////////////////////////////////////////////////////////////////////
409 // Function: CullResult::get_binary_state
410 // Access: Private
411 // Description: Returns a RenderState that applies the effects of
412 // M_binary.
413 ////////////////////////////////////////////////////////////////////
414 CPT(RenderState) CullResult::
415 get_binary_state() {
416  static CPT(RenderState) state = NULL;
417  if (state == (const RenderState *)NULL) {
418  state = RenderState::make(AlphaTestAttrib::make(AlphaTestAttrib::M_greater_equal, 0.5f),
419  TransparencyAttrib::make(TransparencyAttrib::M_none),
421  }
422  return state;
423 }
424 
425 #ifndef NDEBUG
426 ////////////////////////////////////////////////////////////////////
427 // Function: CullResult::apply_flash_color
428 // Access: Private
429 // Description: Update the object's state to flash the geometry
430 // with a solid color.
431 ////////////////////////////////////////////////////////////////////
432 void CullResult::
433 apply_flash_color(CPT(RenderState) &state, const LColor &flash_color) {
434  int cycle = (int)(ClockObject::get_global_clock()->get_frame_time() * bin_color_flash_rate);
435  if ((cycle & 1) == 0) {
436  state = state->remove_attrib(TextureAttrib::get_class_slot());
437  state = state->remove_attrib(LightAttrib::get_class_slot());
438  state = state->remove_attrib(ColorScaleAttrib::get_class_slot());
439  state = state->remove_attrib(FogAttrib::get_class_slot());
440  state = state->add_attrib(ColorAttrib::make_flat(flash_color),
442  }
443 }
444 #endif // NDEBUG
445 
446 ////////////////////////////////////////////////////////////////////
447 // Function: CullResult::get_dual_transparent_state
448 // Access: Private
449 // Description: Returns a RenderState that renders only the
450 // transparent parts of an object, in support of M_dual.
451 ////////////////////////////////////////////////////////////////////
452 CPT(RenderState) CullResult::
453 get_dual_transparent_state() {
454  static CPT(RenderState) state = NULL;
455  if (state == (const RenderState *)NULL) {
456  // The alpha test for > 0 prevents us from drawing empty pixels,
457  // and hence filling up the depth buffer with large empty spaces
458  // that may obscure other things. However, this does mean we draw
459  // pixels twice where the alpha == 1.0 (since they were already
460  // drawn in the opaque pass). This is not normally a problem.
461  state = RenderState::make(AlphaTestAttrib::make(AlphaTestAttrib::M_greater, 0.0f),
462  TransparencyAttrib::make(TransparencyAttrib::M_alpha),
463  DepthWriteAttrib::make(DepthWriteAttrib::M_off),
465  }
466 
467 #ifndef NDEBUG
468  if (m_dual_flash) {
469  int cycle = (int)(ClockObject::get_global_clock()->get_frame_time() * bin_color_flash_rate);
470  if ((cycle & 1) == 0) {
471  static CPT(RenderState) flash_state = NULL;
472  if (flash_state == (const RenderState *)NULL) {
473  flash_state = state->add_attrib(ColorAttrib::make_flat(LColor(0.8f, 0.2, 0.2, 1.0f)),
475 
476  flash_state = flash_state->add_attrib(ColorScaleAttrib::make(LVecBase4(1.0f, 1.0f, 1.0f, 1.0f)),
478 
479  flash_state = flash_state->add_attrib(AlphaTestAttrib::make(AlphaTestAttrib::M_less, 1.0f),
481  }
482  return flash_state;
483  }
484  }
485 #endif // NDEBUG
486 
487  return state;
488 }
489 
490 ////////////////////////////////////////////////////////////////////
491 // Function: CullResult::get_dual_opaque_state
492 // Access: Private
493 // Description: Returns a RenderState that renders only the
494 // opaque parts of an object, in support of M_dual.
495 ////////////////////////////////////////////////////////////////////
496 CPT(RenderState) CullResult::
497 get_dual_opaque_state() {
498  static CPT(RenderState) state = NULL;
499  if (state == (const RenderState *)NULL) {
500  state = RenderState::make(AlphaTestAttrib::make(AlphaTestAttrib::M_greater_equal, dual_opaque_level),
501  TransparencyAttrib::make(TransparencyAttrib::M_none),
503  }
504 
505 #ifndef NDEBUG
506  if (m_dual_flash) {
507  int cycle = (int)(ClockObject::get_global_clock()->get_frame_time() * bin_color_flash_rate);
508  if ((cycle & 1) == 0) {
509  static CPT(RenderState) flash_state = NULL;
510  if (flash_state == (const RenderState *)NULL) {
511  flash_state = state->add_attrib(ColorAttrib::make_flat(LColor(0.2, 0.2, 0.8f, 1.0f)),
513  flash_state = flash_state->add_attrib(ColorScaleAttrib::make(LVecBase4(1.0f, 1.0f, 1.0f, 1.0f)),
515 
516  }
517  return flash_state;
518  }
519  }
520 #endif // NDEBUG
521 
522  return state;
523 }
524 
525 ////////////////////////////////////////////////////////////////////
526 // Function: CullResult::get_wireframe_overlay_state
527 // Access: Private
528 // Description: Returns a RenderState that renders only the
529 // wireframe part of an M_filled_wireframe model.
530 ////////////////////////////////////////////////////////////////////
531 CPT(RenderState) CullResult::
532 get_wireframe_overlay_state(const RenderModeAttrib *rmode) {
533  return RenderState::make(
534  DepthOffsetAttrib::make(1, 0, 0.99999f),
535  ColorAttrib::make_flat(rmode->get_wireframe_color()),
536  ColorBlendAttrib::make(ColorBlendAttrib::M_add,
537  ColorBlendAttrib::O_incoming_alpha,
538  ColorBlendAttrib::O_one_minus_incoming_alpha),
539  RenderModeAttrib::make(RenderModeAttrib::M_wireframe,
540  rmode->get_thickness(),
541  rmode->get_perspective()));
542 }
543 
int get_num_bins() const
Returns the number of bins in the world.
static ClockObject * get_global_clock()
Returns a pointer to the global ClockObject.
Definition: clockObject.I:271
bool get_value() const
Returns the variable&#39;s value.
bool get_bin_active(int bin_index) const
Returns the active flag of the bin with the indicated bin_index (where bin_index was retrieved by get...
A basic node of the scene graph or data graph.
Definition: pandaNode.h:72
void add_object(CullableObject *object, const CullTraverser *traverser)
Adds the indicated CullableObject to the appropriate bin.
Definition: cullResult.cxx:115
A collection of Geoms and their associated state, for a particular scene.
Definition: cullBin.h:44
static int get_max_priority()
Returns the maximum priority number (sometimes called override) that may be set on any node...
This controls the enabling of transparency.
const string & get_bin_name() const
Returns the name of the bin this attribute specifies.
Definition: cullBinAttrib.I:35
BinType get_bin_type(int bin_index) const
Returns the type of the bin with the indicated bin_index (where bin_index was retrieved by get_bin() ...
void finish_cull(SceneSetup *scene_setup, Thread *current_thread)
Called after all the geoms have been added, this indicates that the cull process is finished for this...
Definition: cullResult.cxx:274
int find_bin(const string &name) const
Returns the bin_index associated with the bin of the given name, or -1 if no bin has that name...
static CullBinManager * get_global_ptr()
Returns the pointer to the global CullBinManager object.
A lightweight class that represents a single element that may be timed and/or counted via stats...
The smallest atom of cull.
CullBin * get_bin(int bin_index)
Returns the CullBin associated with the indicated bin_index, or NULL if the bin_index is invalid...
Definition: cullResult.I:35
double get_frame_time(Thread *current_thread=Thread::get_current_thread()) const
Returns the time in seconds as of the last time tick() was called (typically, this will be as of the ...
Definition: clockObject.I:48
bool munge_geom(GraphicsStateGuardianBase *gsg, GeomMunger *munger, const CullTraverser *traverser, bool force)
Uses the indicated GeomMunger to transform the geom and/or its vertices.
static void bin_removed(int bin_index)
Intended to be called by CullBinManager::remove_bin(), this informs all the CullResults in the world ...
Definition: cullResult.cxx:359
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
Mode get_mode() const
Returns the render mode.
Thread * get_current_thread() const
Returns the currently-executing thread object, as passed to the CullTraverser constructor.
Definition: cullTraverser.I:33
Assigns geometry to a particular bin by name.
Definition: cullBinAttrib.h:30
This is the base class for all three-component vectors and points.
Definition: lvecBase4.h:111
This stores the result of a BinCullHandler traversal: an ordered collection of CullBins, each of which holds a number of Geoms and RenderStates to be rendered in some defined order.
Definition: cullResult.h:47
This is a base class for the GraphicsStateGuardian class, which is itself a base class for the variou...
Mode get_mode() const
Returns the transparency mode.
bool get_effective_incomplete_render() const
Returns true if the cull traversal is effectively in incomplete_render state, considering both the GS...
A thread; that is, a lightweight process.
Definition: thread.h:51
int get_bin(int n) const
Returns the bin_index of the nth bin in the set, where n is a number between 0 and get_num_bins()...
Specifies how polygons are to be drawn.
void draw(Thread *current_thread)
Asks all the bins to draw themselves in the correct order.
Definition: cullResult.cxx:299
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
This object holds the camera position, etc., and other general setup information for rendering a part...
Definition: sceneSetup.h:35
This is a global object that maintains the collection of named CullBins in the world.
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling...
Definition: cullTraverser.h:48