00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "config_pgraph.h"
00016 #include "cullTraverser.h"
00017 #include "cullTraverserData.h"
00018 #include "transformState.h"
00019 #include "renderState.h"
00020 #include "fogAttrib.h"
00021 #include "colorAttrib.h"
00022 #include "renderModeAttrib.h"
00023 #include "cullFaceAttrib.h"
00024 #include "depthOffsetAttrib.h"
00025 #include "cullHandler.h"
00026 #include "dcast.h"
00027 #include "geomNode.h"
00028 #include "config_pgraph.h"
00029 #include "boundingSphere.h"
00030 #include "boundingBox.h"
00031 #include "boundingHexahedron.h"
00032 #include "portalClipper.h"
00033 #include "geom.h"
00034 #include "geomTristrips.h"
00035 #include "geomTriangles.h"
00036 #include "geomLinestrips.h"
00037 #include "geomLines.h"
00038 #include "geomVertexWriter.h"
00039
00040 PStatCollector CullTraverser::_nodes_pcollector("Nodes");
00041 PStatCollector CullTraverser::_geom_nodes_pcollector("Nodes:GeomNodes");
00042 PStatCollector CullTraverser::_geoms_pcollector("Geoms");
00043 PStatCollector CullTraverser::_geoms_occluded_pcollector("Geoms:Occluded");
00044
00045 TypeHandle CullTraverser::_type_handle;
00046
00047
00048
00049
00050
00051
00052 CullTraverser::
00053 CullTraverser() :
00054 _gsg(NULL),
00055 _current_thread(Thread::get_current_thread())
00056 {
00057 _camera_mask = DrawMask::all_on();
00058 _has_tag_state_key = false;
00059 _initial_state = RenderState::make_empty();
00060 _cull_handler = (CullHandler *)NULL;
00061 _portal_clipper = (PortalClipper *)NULL;
00062 _effective_incomplete_render = true;
00063 }
00064
00065
00066
00067
00068
00069
00070 CullTraverser::
00071 CullTraverser(const CullTraverser ©) :
00072 _gsg(copy._gsg),
00073 _current_thread(copy._current_thread),
00074 _scene_setup(copy._scene_setup),
00075 _camera_mask(copy._camera_mask),
00076 _has_tag_state_key(copy._has_tag_state_key),
00077 _tag_state_key(copy._tag_state_key),
00078 _initial_state(copy._initial_state),
00079 _depth_offset_decals(copy._depth_offset_decals),
00080 _view_frustum(copy._view_frustum),
00081 _cull_handler(copy._cull_handler),
00082 _portal_clipper(copy._portal_clipper),
00083 _effective_incomplete_render(copy._effective_incomplete_render)
00084 {
00085 }
00086
00087
00088
00089
00090
00091
00092
00093
00094 void CullTraverser::
00095 set_scene(SceneSetup *scene_setup, GraphicsStateGuardianBase *gsg,
00096 bool dr_incomplete_render) {
00097 _scene_setup = scene_setup;
00098 _gsg = gsg;
00099
00100 _initial_state = scene_setup->get_initial_state();
00101 _depth_offset_decals = _gsg->depth_offset_decals() && depth_offset_decals;
00102
00103 _current_thread = Thread::get_current_thread();
00104
00105 const Camera *camera = scene_setup->get_camera_node();
00106 _tag_state_key = camera->get_tag_state_key();
00107 _has_tag_state_key = !_tag_state_key.empty();
00108 _camera_mask = camera->get_camera_mask();
00109
00110 _effective_incomplete_render = _gsg->get_incomplete_render() && dr_incomplete_render;
00111 }
00112
00113
00114
00115
00116
00117
00118 void CullTraverser::
00119 traverse(const NodePath &root) {
00120 nassertv(_cull_handler != (CullHandler *)NULL);
00121 nassertv(_scene_setup != (SceneSetup *)NULL);
00122
00123 if (allow_portal_cull) {
00124
00125
00126
00127
00128 GeometricBoundingVolume *local_frustum = NULL;
00129 PT(BoundingVolume) bv = _scene_setup->get_lens()->make_bounds();
00130 if (bv != (BoundingVolume *)NULL &&
00131 bv->is_of_type(GeometricBoundingVolume::get_class_type())) {
00132
00133 local_frustum = DCAST(GeometricBoundingVolume, bv);
00134 }
00135
00136
00137 PortalClipper portal_viewer(local_frustum, _scene_setup);
00138 if (debug_portal_cull) {
00139 portal_viewer.draw_camera_frustum();
00140 }
00141
00142
00143 set_portal_clipper(&portal_viewer);
00144
00145 CullTraverserData data(root, TransformState::make_identity(),
00146 _initial_state, _view_frustum,
00147 _current_thread);
00148
00149 traverse(data);
00150
00151
00152 if (debug_portal_cull) {
00153 portal_viewer.draw_lines();
00154 }
00155
00156
00157 NodePath cull_center = _scene_setup->get_cull_center();
00158 CPT(TransformState) transform = cull_center.get_transform(root);
00159
00160 CullTraverserData my_data(data, portal_viewer._previous);
00161 my_data._net_transform = my_data._net_transform->compose(transform);
00162 traverse(my_data);
00163
00164 } else {
00165 CullTraverserData data(root, TransformState::make_identity(),
00166 _initial_state, _view_frustum,
00167 _current_thread);
00168
00169 traverse(data);
00170 }
00171 }
00172
00173
00174
00175
00176
00177
00178
00179
00180 void CullTraverser::
00181 traverse(CullTraverserData &data) {
00182 if (is_in_view(data)) {
00183 if (pgraph_cat.is_spam()) {
00184 pgraph_cat.spam()
00185 << "\n" << data._node_path
00186 << " " << data._draw_mask << "\n";
00187 }
00188
00189 PandaNodePipelineReader *node_reader = data.node_reader();
00190 int fancy_bits = node_reader->get_fancy_bits();
00191
00192 if ((fancy_bits & (PandaNode::FB_transform |
00193 PandaNode::FB_state |
00194 PandaNode::FB_effects |
00195 PandaNode::FB_tag |
00196 PandaNode::FB_draw_mask |
00197 PandaNode::FB_cull_callback)) == 0 &&
00198 data._cull_planes->is_empty()) {
00199
00200 traverse_below(data);
00201
00202 } else {
00203
00204 const RenderEffects *node_effects = node_reader->get_effects();
00205 if (node_effects->has_show_bounds()) {
00206
00207
00208 show_bounds(data, node_effects->has_show_tight_bounds());
00209 }
00210
00211 data.apply_transform_and_state(this);
00212
00213 const FogAttrib *fog = DCAST(FogAttrib, node_reader->get_state()->get_attrib(FogAttrib::get_class_slot()));
00214 if (fog != (const FogAttrib *)NULL && fog->get_fog() != (Fog *)NULL) {
00215
00216
00217
00218
00219 fog->get_fog()->adjust_to_camera(get_camera_transform());
00220 }
00221
00222 if (fancy_bits & PandaNode::FB_cull_callback) {
00223 PandaNode *node = data.node();
00224 if (!node->cull_callback(this, data)) {
00225 return;
00226 }
00227 }
00228 traverse_below(data);
00229 }
00230 }
00231 }
00232
00233
00234
00235
00236
00237
00238
00239
00240 void CullTraverser::
00241 traverse_below(CullTraverserData &data) {
00242 _nodes_pcollector.add_level(1);
00243 PandaNodePipelineReader *node_reader = data.node_reader();
00244 PandaNode *node = data.node();
00245
00246 bool this_node_hidden = data.is_this_node_hidden(this);
00247
00248 const RenderEffects *node_effects = node_reader->get_effects();
00249 bool has_decal = !this_node_hidden && node_effects->has_decal();
00250 if (has_decal && !_depth_offset_decals) {
00251
00252
00253 start_decal(data);
00254
00255 } else {
00256 if (!this_node_hidden) {
00257 node->add_for_draw(this, data);
00258 }
00259
00260 if (has_decal) {
00261
00262
00263
00264 data._state = data._state->compose(get_depth_offset_state());
00265 #ifndef NDEBUG
00266
00267 if (!node->is_geom_node()) {
00268 pgraph_cat.error()
00269 << "DecalEffect applied to " << *node << ", not a GeomNode.\n";
00270 }
00271 #endif
00272 }
00273
00274
00275 PandaNode::Children children = node_reader->get_children();
00276 node_reader->release();
00277 int num_children = children.get_num_children();
00278 if (node->has_selective_visibility()) {
00279 int i = node->get_first_visible_child();
00280 while (i < num_children) {
00281 CullTraverserData next_data(data, children.get_child(i));
00282 traverse(next_data);
00283 i = node->get_next_visible_child(i);
00284 }
00285
00286 } else {
00287 for (int i = 0; i < num_children; i++) {
00288 CullTraverserData next_data(data, children.get_child(i));
00289 traverse(next_data);
00290 }
00291 }
00292 }
00293 }
00294
00295
00296
00297
00298
00299
00300
00301
00302 void CullTraverser::
00303 end_traverse() {
00304 _cull_handler->end_traverse();
00305 }
00306
00307
00308
00309
00310
00311
00312
00313 void CullTraverser::
00314 draw_bounding_volume(const BoundingVolume *vol,
00315 const TransformState *net_transform,
00316 const TransformState *modelview_transform) const {
00317 PT(Geom) bounds_viz = make_bounds_viz(vol);
00318
00319 if (bounds_viz != (Geom *)NULL) {
00320 _geoms_pcollector.add_level(2);
00321 CullableObject *outer_viz =
00322 new CullableObject(bounds_viz, get_bounds_outer_viz_state(),
00323 net_transform, modelview_transform, get_gsg());
00324 _cull_handler->record_object(outer_viz, this);
00325
00326 CullableObject *inner_viz =
00327 new CullableObject(bounds_viz, get_bounds_inner_viz_state(),
00328 net_transform, modelview_transform, get_gsg());
00329 _cull_handler->record_object(inner_viz, this);
00330 }
00331 }
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341 bool CullTraverser::
00342 is_in_view(CullTraverserData &data) {
00343 return data.is_in_view(_camera_mask);
00344 }
00345
00346
00347
00348
00349
00350
00351
00352 void CullTraverser::
00353 show_bounds(CullTraverserData &data, bool tight) {
00354 PandaNode *node = data.node();
00355 CPT(TransformState) net_transform = data.get_net_transform(this);
00356 CPT(TransformState) modelview_transform = data.get_modelview_transform(this);
00357
00358 if (tight) {
00359 PT(Geom) bounds_viz = make_tight_bounds_viz(node);
00360
00361 if (bounds_viz != (Geom *)NULL) {
00362 _geoms_pcollector.add_level(1);
00363 CullableObject *outer_viz =
00364 new CullableObject(bounds_viz, get_bounds_outer_viz_state(),
00365 net_transform, modelview_transform,
00366 get_gsg());
00367 _cull_handler->record_object(outer_viz, this);
00368 }
00369
00370 } else {
00371 draw_bounding_volume(node->get_bounds(),
00372 net_transform, modelview_transform);
00373
00374 if (node->is_geom_node()) {
00375
00376 net_transform = net_transform->compose(node->get_transform());
00377 modelview_transform = modelview_transform->compose(node->get_transform());
00378 GeomNode *gnode = DCAST(GeomNode, node);
00379 int num_geoms = gnode->get_num_geoms();
00380 for (int i = 0; i < num_geoms; ++i) {
00381 draw_bounding_volume(gnode->get_geom(i)->get_bounds(),
00382 net_transform, modelview_transform);
00383 }
00384 }
00385 }
00386 }
00387
00388
00389
00390
00391
00392
00393
00394 PT(Geom) CullTraverser::
00395 make_bounds_viz(const BoundingVolume *vol) {
00396 PT(Geom) geom;
00397 if (vol->is_infinite() || vol->is_empty()) {
00398
00399
00400 } else if (vol->is_of_type(BoundingSphere::get_class_type())) {
00401 const BoundingSphere *sphere = DCAST(BoundingSphere, vol);
00402
00403 static const int num_slices = 16;
00404 static const int num_stacks = 8;
00405
00406 PT(GeomVertexData) vdata = new GeomVertexData
00407 ("bounds", GeomVertexFormat::get_v3(),
00408 Geom::UH_stream);
00409 GeomVertexWriter vertex(vdata, InternalName::get_vertex());
00410
00411 PT(GeomTristrips) strip = new GeomTristrips(Geom::UH_stream);
00412 for (int sl = 0; sl < num_slices; ++sl) {
00413 PN_stdfloat longitude0 = (PN_stdfloat)sl / (PN_stdfloat)num_slices;
00414 PN_stdfloat longitude1 = (PN_stdfloat)(sl + 1) / (PN_stdfloat)num_slices;
00415 vertex.add_data3(compute_point(sphere, 0.0, longitude0));
00416 for (int st = 1; st < num_stacks; ++st) {
00417 PN_stdfloat latitude = (PN_stdfloat)st / (PN_stdfloat)num_stacks;
00418 vertex.add_data3(compute_point(sphere, latitude, longitude0));
00419 vertex.add_data3(compute_point(sphere, latitude, longitude1));
00420 }
00421 vertex.add_data3(compute_point(sphere, 1.0, longitude0));
00422
00423 strip->add_next_vertices(num_stacks * 2);
00424 strip->close_primitive();
00425 }
00426
00427 geom = new Geom(vdata);
00428 geom->add_primitive(strip);
00429
00430 } else if (vol->is_of_type(BoundingHexahedron::get_class_type())) {
00431 const BoundingHexahedron *fvol = DCAST(BoundingHexahedron, vol);
00432
00433 PT(GeomVertexData) vdata = new GeomVertexData
00434 ("bounds", GeomVertexFormat::get_v3(),
00435 Geom::UH_stream);
00436 GeomVertexWriter vertex(vdata, InternalName::get_vertex());
00437
00438 for (int i = 0; i < 8; ++i ) {
00439 vertex.add_data3(fvol->get_point(i));
00440 }
00441
00442 PT(GeomLines) lines = new GeomLines(Geom::UH_stream);
00443 lines->add_vertices(0, 1); lines->close_primitive();
00444 lines->add_vertices(1, 2); lines->close_primitive();
00445 lines->add_vertices(2, 3); lines->close_primitive();
00446 lines->add_vertices(3, 0); lines->close_primitive();
00447
00448 lines->add_vertices(4, 5); lines->close_primitive();
00449 lines->add_vertices(5, 6); lines->close_primitive();
00450 lines->add_vertices(6, 7); lines->close_primitive();
00451 lines->add_vertices(7, 4); lines->close_primitive();
00452
00453 lines->add_vertices(0, 4); lines->close_primitive();
00454 lines->add_vertices(1, 5); lines->close_primitive();
00455 lines->add_vertices(2, 6); lines->close_primitive();
00456 lines->add_vertices(3, 7); lines->close_primitive();
00457
00458 geom = new Geom(vdata);
00459 geom->add_primitive(lines);
00460
00461 } else if (vol->is_of_type(FiniteBoundingVolume::get_class_type())) {
00462 const FiniteBoundingVolume *fvol = DCAST(FiniteBoundingVolume, vol);
00463
00464 BoundingBox box(fvol->get_min(), fvol->get_max());
00465 box.local_object();
00466
00467 PT(GeomVertexData) vdata = new GeomVertexData
00468 ("bounds", GeomVertexFormat::get_v3(),
00469 Geom::UH_stream);
00470 GeomVertexWriter vertex(vdata, InternalName::get_vertex());
00471
00472 for (int i = 0; i < 8; ++i ) {
00473 vertex.add_data3(box.get_point(i));
00474 }
00475
00476 PT(GeomTriangles) tris = new GeomTriangles(Geom::UH_stream);
00477 tris->add_vertices(0, 4, 5);
00478 tris->close_primitive();
00479 tris->add_vertices(0, 5, 1);
00480 tris->close_primitive();
00481 tris->add_vertices(4, 6, 7);
00482 tris->close_primitive();
00483 tris->add_vertices(4, 7, 5);
00484 tris->close_primitive();
00485 tris->add_vertices(6, 2, 3);
00486 tris->close_primitive();
00487 tris->add_vertices(6, 3, 7);
00488 tris->close_primitive();
00489 tris->add_vertices(2, 0, 1);
00490 tris->close_primitive();
00491 tris->add_vertices(2, 1, 3);
00492 tris->close_primitive();
00493 tris->add_vertices(1, 5, 7);
00494 tris->close_primitive();
00495 tris->add_vertices(1, 7, 3);
00496 tris->close_primitive();
00497 tris->add_vertices(2, 6, 4);
00498 tris->close_primitive();
00499 tris->add_vertices(2, 4, 0);
00500 tris->close_primitive();
00501
00502 geom = new Geom(vdata);
00503 geom->add_primitive(tris);
00504
00505 } else {
00506 pgraph_cat.warning()
00507 << "Don't know how to draw a representation of "
00508 << vol->get_class_type() << "\n";
00509 }
00510
00511 return geom;
00512 }
00513
00514
00515
00516
00517
00518
00519
00520 PT(Geom) CullTraverser::
00521 make_tight_bounds_viz(PandaNode *node) const {
00522 PT(Geom) geom;
00523
00524 NodePath np = NodePath::any_path(node);
00525
00526 LPoint3 n, x;
00527 bool found_any = false;
00528 node->calc_tight_bounds(n, x, found_any, TransformState::make_identity(),
00529 _current_thread);
00530 if (found_any) {
00531 PT(GeomVertexData) vdata = new GeomVertexData
00532 ("bounds", GeomVertexFormat::get_v3(),
00533 Geom::UH_stream);
00534 GeomVertexWriter vertex(vdata, InternalName::get_vertex(),
00535 _current_thread);
00536
00537 vertex.add_data3(n[0], n[1], n[2]);
00538 vertex.add_data3(n[0], n[1], x[2]);
00539 vertex.add_data3(n[0], x[1], n[2]);
00540 vertex.add_data3(n[0], x[1], x[2]);
00541 vertex.add_data3(x[0], n[1], n[2]);
00542 vertex.add_data3(x[0], n[1], x[2]);
00543 vertex.add_data3(x[0], x[1], n[2]);
00544 vertex.add_data3(x[0], x[1], x[2]);
00545
00546 PT(GeomLinestrips) strip = new GeomLinestrips(Geom::UH_stream);
00547
00548
00549
00550 strip->add_vertex(0);
00551 strip->add_vertex(1);
00552 strip->add_vertex(3);
00553 strip->add_vertex(2);
00554 strip->add_vertex(0);
00555 strip->add_vertex(4);
00556 strip->add_vertex(5);
00557 strip->add_vertex(7);
00558 strip->add_vertex(6);
00559 strip->add_vertex(4);
00560 strip->add_vertex(6);
00561 strip->add_vertex(2);
00562 strip->add_vertex(3);
00563 strip->add_vertex(7);
00564 strip->add_vertex(5);
00565 strip->add_vertex(1);
00566 strip->close_primitive();
00567
00568 geom = new Geom(vdata);
00569 geom->add_primitive(strip);
00570 }
00571
00572 return geom;
00573 }
00574
00575
00576
00577
00578
00579
00580
00581 LVertex CullTraverser::
00582 compute_point(const BoundingSphere *sphere,
00583 PN_stdfloat latitude, PN_stdfloat longitude) {
00584 PN_stdfloat s1, c1;
00585 csincos(latitude * MathNumbers::pi, &s1, &c1);
00586
00587 PN_stdfloat s2, c2;
00588 csincos(longitude * 2.0 * MathNumbers::pi, &s2, &c2);
00589
00590 LVertex p(s1 * c2, s1 * s2, c1);
00591 return p * sphere->get_radius() + sphere->get_center();
00592 }
00593
00594
00595
00596
00597
00598
00599
00600 CPT(RenderState) CullTraverser::
00601 get_bounds_outer_viz_state() {
00602
00603
00604 static CPT(RenderState) state = (const RenderState *)NULL;
00605 if (state == (const RenderState *)NULL) {
00606 state = RenderState::make
00607 (ColorAttrib::make_flat(LColor(0.3, 1.0f, 0.5f, 1.0f)),
00608 RenderModeAttrib::make(RenderModeAttrib::M_wireframe),
00609 CullFaceAttrib::make(CullFaceAttrib::M_cull_clockwise));
00610 }
00611 return state;
00612 }
00613
00614
00615
00616
00617
00618
00619
00620 CPT(RenderState) CullTraverser::
00621 get_bounds_inner_viz_state() {
00622
00623
00624 static CPT(RenderState) state = (const RenderState *)NULL;
00625 if (state == (const RenderState *)NULL) {
00626 state = RenderState::make
00627 (ColorAttrib::make_flat(LColor(0.15f, 0.5f, 0.25f, 1.0f)),
00628 RenderModeAttrib::make(RenderModeAttrib::M_wireframe),
00629 CullFaceAttrib::make(CullFaceAttrib::M_cull_counter_clockwise));
00630 }
00631 return state;
00632 }
00633
00634
00635
00636
00637
00638
00639
00640 CPT(RenderState) CullTraverser::
00641 get_depth_offset_state() {
00642
00643
00644 static CPT(RenderState) state = (const RenderState *)NULL;
00645 if (state == (const RenderState *)NULL) {
00646 state = RenderState::make
00647 (DepthOffsetAttrib::make(1));
00648 }
00649 return state;
00650 }
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660 void CullTraverser::
00661 start_decal(const CullTraverserData &data) {
00662 PandaNode *node = data.node();
00663 if (!node->is_geom_node()) {
00664 pgraph_cat.error()
00665 << "DecalEffect applied to " << *node << ", not a GeomNode.\n";
00666 return;
00667 }
00668
00669 const PandaNodePipelineReader *node_reader = data.node_reader();
00670
00671
00672
00673
00674
00675
00676
00677
00678 CullableObject *decals = (CullableObject *)NULL;
00679 PandaNode::Children cr = node_reader->get_children();
00680 int num_children = cr.get_num_children();
00681 if (node->has_selective_visibility()) {
00682 int i = node->get_first_visible_child();
00683 while (i < num_children) {
00684 CullTraverserData next_data(data, cr.get_child(i));
00685 decals = r_get_decals(next_data, decals);
00686 i = node->get_next_visible_child(i);
00687 }
00688
00689 } else {
00690 for (int i = num_children - 1; i >= 0; i--) {
00691 CullTraverserData next_data(data, cr.get_child(i));
00692 decals = r_get_decals(next_data, decals);
00693 }
00694 }
00695
00696
00697
00698 CullableObject *separator = new CullableObject;
00699 separator->set_next(decals);
00700
00701
00702 CullableObject *object = separator;
00703 GeomNode *geom_node = DCAST(GeomNode, node);
00704 GeomNode::Geoms geoms = geom_node->get_geoms();
00705 int num_geoms = geoms.get_num_geoms();
00706 _geoms_pcollector.add_level(num_geoms);
00707 CPT(TransformState) net_transform = data.get_net_transform(this);
00708 CPT(TransformState) modelview_transform = data.get_modelview_transform(this);
00709 CPT(TransformState) internal_transform = get_gsg()->get_cs_transform()->compose(modelview_transform);
00710
00711 for (int i = num_geoms - 1; i >= 0; i--) {
00712 const Geom *geom = geoms.get_geom(i);
00713 if (geom->is_empty()) {
00714 continue;
00715 }
00716
00717 CPT(RenderState) state = data._state->compose(geoms.get_geom_state(i));
00718 if (state->has_cull_callback() && !state->cull_callback(this, data)) {
00719
00720 continue;
00721 }
00722
00723
00724
00725
00726
00727
00728 if (num_geoms > 1) {
00729 if (data._view_frustum != (GeometricBoundingVolume *)NULL) {
00730
00731 CPT(BoundingVolume) geom_volume = geom->get_bounds();
00732 const GeometricBoundingVolume *geom_gbv =
00733 DCAST(GeometricBoundingVolume, geom_volume);
00734
00735 int result = data._view_frustum->contains(geom_gbv);
00736 if (result == BoundingVolume::IF_no_intersection) {
00737
00738 continue;
00739 }
00740 }
00741 if (!data._cull_planes->is_empty()) {
00742
00743 CPT(BoundingVolume) geom_volume = geom->get_bounds();
00744 const GeometricBoundingVolume *geom_gbv =
00745 DCAST(GeometricBoundingVolume, geom_volume);
00746 int result;
00747 data._cull_planes->do_cull(result, state, geom_gbv);
00748 if (result == BoundingVolume::IF_no_intersection) {
00749
00750 continue;
00751 }
00752 }
00753 }
00754
00755 CullableObject *next = object;
00756 object =
00757 new CullableObject(geom, state, net_transform,
00758 modelview_transform, internal_transform);
00759 object->set_next(next);
00760 }
00761
00762 if (object != separator) {
00763
00764
00765
00766 _cull_handler->record_object(object, this);
00767 } else {
00768
00769 delete object;
00770 }
00771 }
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782 CullableObject *CullTraverser::
00783 r_get_decals(CullTraverserData &data, CullableObject *decals) {
00784 if (is_in_view(data)) {
00785 PandaNodePipelineReader *node_reader = data.node_reader();
00786 PandaNode *node = data.node();
00787
00788 const RenderEffects *node_effects = node_reader->get_effects();
00789 if (node_effects->has_show_bounds()) {
00790
00791
00792 show_bounds(data, node_effects->has_show_tight_bounds());
00793 }
00794
00795 data.apply_transform_and_state(this);
00796
00797
00798 int num_children = node_reader->get_num_children();
00799 if (node->has_selective_visibility()) {
00800 int i = node->get_first_visible_child();
00801 while (i < num_children) {
00802 CullTraverserData next_data(data, node_reader->get_child(i));
00803 decals = r_get_decals(next_data, decals);
00804 i = node->get_next_visible_child(i);
00805 }
00806
00807 } else {
00808 for (int i = num_children - 1; i >= 0; i--) {
00809 CullTraverserData next_data(data, node_reader->get_child(i));
00810 decals = r_get_decals(next_data, decals);
00811 }
00812 }
00813
00814
00815 if (node->is_geom_node()) {
00816 GeomNode *geom_node = DCAST(GeomNode, node);
00817 GeomNode::Geoms geoms = geom_node->get_geoms();
00818 int num_geoms = geoms.get_num_geoms();
00819 _geoms_pcollector.add_level(num_geoms);
00820 CPT(TransformState) net_transform = data.get_net_transform(this);
00821 CPT(TransformState) modelview_transform = data.get_modelview_transform(this);
00822 CPT(TransformState) internal_transform = get_gsg()->get_cs_transform()->compose(modelview_transform);
00823
00824 for (int i = num_geoms - 1; i >= 0; i--) {
00825 const Geom *geom = geoms.get_geom(i);
00826 if (geom->is_empty()) {
00827 continue;
00828 }
00829
00830 CPT(RenderState) state = data._state->compose(geoms.get_geom_state(i));
00831 if (state->has_cull_callback() && !state->cull_callback(this, data)) {
00832
00833 continue;
00834 }
00835
00836
00837
00838
00839
00840
00841 if (num_geoms > 1) {
00842 if (data._view_frustum != (GeometricBoundingVolume *)NULL) {
00843
00844 CPT(BoundingVolume) geom_volume = geom->get_bounds();
00845 const GeometricBoundingVolume *geom_gbv =
00846 DCAST(GeometricBoundingVolume, geom_volume);
00847
00848 int result = data._view_frustum->contains(geom_gbv);
00849 if (result == BoundingVolume::IF_no_intersection) {
00850
00851 continue;
00852 }
00853 }
00854 if (!data._cull_planes->is_empty()) {
00855
00856 CPT(BoundingVolume) geom_volume = geom->get_bounds();
00857 const GeometricBoundingVolume *geom_gbv =
00858 DCAST(GeometricBoundingVolume, geom_volume);
00859 int result;
00860 data._cull_planes->do_cull(result, state, geom_gbv);
00861 if (result == BoundingVolume::IF_no_intersection) {
00862
00863 continue;
00864 }
00865 }
00866 }
00867
00868 CullableObject *next = decals;
00869 decals =
00870 new CullableObject(geom, state, net_transform,
00871 modelview_transform, internal_transform);
00872 decals->set_next(next);
00873 }
00874 }
00875 }
00876
00877 return decals;
00878 }