00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "cullTraverser.h"
00020 #include "cullTraverserData.h"
00021 #include "transformState.h"
00022 #include "renderState.h"
00023 #include "fogAttrib.h"
00024 #include "cullHandler.h"
00025 #include "dcast.h"
00026 #include "geomNode.h"
00027 #include "config_pgraph.h"
00028 #include "boundingSphere.h"
00029 #include "geomSphere.h"
00030 #include "colorAttrib.h"
00031 #include "renderModeAttrib.h"
00032 #include "cullFaceAttrib.h"
00033 #include "depthOffsetAttrib.h"
00034
00035
00036 TypeHandle CullTraverser::_type_handle;
00037
00038
00039
00040
00041
00042
00043 CullTraverser::
00044 CullTraverser() {
00045 _camera_mask = DrawMask::all_on();
00046 _initial_state = RenderState::make_empty();
00047 _depth_offset_decals = false;
00048 _cull_handler = (CullHandler *)NULL;
00049 }
00050
00051
00052
00053
00054
00055
00056 CullTraverser::
00057 CullTraverser(const CullTraverser ©) :
00058 _scene_setup(copy._scene_setup),
00059 _camera_mask(copy._camera_mask),
00060 _initial_state(copy._initial_state),
00061 _depth_offset_decals(copy._depth_offset_decals),
00062 _view_frustum(copy._view_frustum),
00063 _guard_band(copy._guard_band),
00064 _cull_handler(copy._cull_handler)
00065 {
00066 }
00067
00068
00069
00070
00071
00072
00073 void CullTraverser::
00074 traverse(const NodePath &root) {
00075 nassertv(_cull_handler != (CullHandler *)NULL);
00076 nassertv(_scene_setup != (SceneSetup *)NULL);
00077
00078 CullTraverserData data(root, get_render_transform(),
00079 TransformState::make_identity(),
00080 _initial_state, _view_frustum, _guard_band);
00081 traverse(data);
00082 }
00083
00084
00085
00086
00087
00088
00089
00090
00091 void CullTraverser::
00092 traverse(CullTraverserData &data) {
00093
00094
00095
00096
00097 if (data.is_in_view(_camera_mask)) {
00098 PandaNode *node = data.node();
00099
00100 const RenderEffects *node_effects = node->get_effects();
00101 if (node_effects->has_show_bounds()) {
00102
00103
00104 show_bounds(data);
00105 }
00106
00107 data.apply_transform_and_state(this);
00108
00109 const RenderState *node_state = node->get_state();
00110 const FogAttrib *fog = node_state->get_fog();
00111 if (fog != (const FogAttrib *)NULL && fog->get_fog() != (Fog *)NULL) {
00112
00113
00114
00115
00116 fog->get_fog()->adjust_to_camera(get_camera_transform());
00117 }
00118
00119 if (node->has_cull_callback()) {
00120 if (!node->cull_callback(this, data)) {
00121 return;
00122 }
00123 }
00124
00125 traverse_below(data);
00126 }
00127 }
00128
00129
00130
00131
00132
00133
00134
00135
00136 void CullTraverser::
00137 traverse_below(CullTraverserData &data) {
00138 PandaNode *node = data.node();
00139 const RenderEffects *node_effects = node->get_effects();
00140 bool has_decal = node_effects->has_decal();
00141 if (has_decal && !_depth_offset_decals) {
00142
00143
00144 start_decal(data);
00145
00146 } else {
00147 if (node->is_geom_node()) {
00148 GeomNode *geom_node = DCAST(GeomNode, node);
00149
00150
00151 int num_geoms = geom_node->get_num_geoms();
00152 for (int i = 0; i < num_geoms; i++) {
00153 CullableObject *object = new CullableObject(data, geom_node, i);
00154 _cull_handler->record_object(object);
00155 }
00156 }
00157
00158 if (has_decal) {
00159
00160
00161
00162 data._state = data._state->compose(get_depth_offset_state());
00163 #ifndef NDEBUG
00164
00165 if (!node->is_geom_node()) {
00166 pgraph_cat.error()
00167 << "DecalEffect applied to " << *node << ", not a GeomNode.\n";
00168 }
00169 #endif
00170 }
00171
00172
00173
00174
00175
00176 int num_children = node->get_num_children();
00177 if (node->has_selective_visibility()) {
00178 int i = node->get_first_visible_child();
00179 while (i < num_children) {
00180 CullTraverserData next_data(data, node->get_child(i));
00181 traverse(next_data);
00182 i = node->get_next_visible_child(i);
00183 }
00184
00185 } else {
00186 for (int i = 0; i < num_children; i++) {
00187 CullTraverserData next_data(data, node->get_child(i));
00188 traverse(next_data);
00189 }
00190 }
00191 }
00192 }
00193
00194
00195
00196
00197
00198
00199
00200 void CullTraverser::
00201 show_bounds(CullTraverserData &data) {
00202 PandaNode *node = data.node();
00203
00204 PT(Geom) bounds_viz = make_bounds_viz(node->get_bound());
00205 if (bounds_viz != (Geom *)NULL) {
00206 CullableObject *outer_viz =
00207 new CullableObject(bounds_viz, get_bounds_outer_viz_state(),
00208 data._render_transform);
00209 _cull_handler->record_object(outer_viz);
00210
00211 CullableObject *inner_viz =
00212 new CullableObject(bounds_viz, get_bounds_inner_viz_state(),
00213 data._render_transform);
00214 _cull_handler->record_object(inner_viz);
00215 }
00216 }
00217
00218
00219
00220
00221
00222
00223
00224 PT(Geom) CullTraverser::
00225 make_bounds_viz(const BoundingVolume &vol) {
00226 PT(Geom) geom;
00227 if (vol.is_infinite()) {
00228
00229
00230 } else if (vol.is_of_type(BoundingSphere::get_class_type())) {
00231 const BoundingSphere *sphere = DCAST(BoundingSphere, &vol);
00232
00233 geom = new GeomSphere;
00234 PTA_Vertexf verts;
00235 LPoint3f center = sphere->get_center();
00236 verts.push_back(center);
00237 center[0] += sphere->get_radius();
00238 verts.push_back(center);
00239 geom->set_coords(verts);
00240 geom->set_num_prims(1);
00241
00242 } else {
00243 pgraph_cat.warning()
00244 << "Don't know how to draw a representation of "
00245 << vol.get_class_type() << "\n";
00246 }
00247
00248 return geom;
00249 }
00250
00251
00252
00253
00254
00255
00256
00257 CPT(RenderState) CullTraverser::
00258 get_bounds_outer_viz_state() {
00259
00260
00261 static CPT(RenderState) state = (const RenderState *)NULL;
00262 if (state == (const RenderState *)NULL) {
00263 state = RenderState::make
00264 (ColorAttrib::make_flat(Colorf(0.3f, 1.0f, 0.5f, 1.0f)),
00265 RenderModeAttrib::make(RenderModeAttrib::M_wireframe),
00266 CullFaceAttrib::make(CullFaceAttrib::M_cull_clockwise));
00267 }
00268 return state;
00269 }
00270
00271
00272
00273
00274
00275
00276
00277 CPT(RenderState) CullTraverser::
00278 get_bounds_inner_viz_state() {
00279
00280
00281 static CPT(RenderState) state = (const RenderState *)NULL;
00282 if (state == (const RenderState *)NULL) {
00283 state = RenderState::make
00284 (ColorAttrib::make_flat(Colorf(0.15f, 0.5f, 0.25f, 1.0f)),
00285 RenderModeAttrib::make(RenderModeAttrib::M_wireframe),
00286 CullFaceAttrib::make(CullFaceAttrib::M_cull_counter_clockwise));
00287 }
00288 return state;
00289 }
00290
00291
00292
00293
00294
00295
00296
00297 CPT(RenderState) CullTraverser::
00298 get_depth_offset_state() {
00299
00300
00301 static CPT(RenderState) state = (const RenderState *)NULL;
00302 if (state == (const RenderState *)NULL) {
00303 state = RenderState::make
00304 (DepthOffsetAttrib::make(1));
00305 }
00306 return state;
00307 }
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317 void CullTraverser::
00318 start_decal(const CullTraverserData &data) {
00319 PandaNode *node = data.node();
00320 if (!node->is_geom_node()) {
00321 pgraph_cat.error()
00322 << "DecalEffect applied to " << *node << ", not a GeomNode.\n";
00323 return;
00324 }
00325
00326
00327
00328
00329
00330
00331
00332
00333 CullableObject *decals = (CullableObject *)NULL;
00334 PandaNode::Children cr = node->get_children();
00335 int num_children = cr.get_num_children();
00336 if (node->has_selective_visibility()) {
00337 int i = node->get_first_visible_child();
00338 while (i < num_children) {
00339 CullTraverserData next_data(data, cr.get_child(i));
00340 decals = r_get_decals(next_data, decals);
00341 i = node->get_next_visible_child(i);
00342 }
00343
00344 } else {
00345 for (int i = num_children - 1; i >= 0; i--) {
00346 CullTraverserData next_data(data, cr.get_child(i));
00347 decals = r_get_decals(next_data, decals);
00348 }
00349 }
00350
00351
00352
00353 CullableObject *separator = new CullableObject(decals);
00354
00355
00356 CullableObject *object = separator;
00357 GeomNode *geom_node = DCAST(GeomNode, node);
00358 int num_geoms = geom_node->get_num_geoms();
00359 for (int i = num_geoms - 1; i >= 0; i--) {
00360 object = new CullableObject(data, geom_node, i, object);
00361 }
00362
00363 if (object != separator) {
00364
00365
00366
00367 _cull_handler->record_object(object);
00368 }
00369 }
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380 CullableObject *CullTraverser::
00381 r_get_decals(CullTraverserData &data, CullableObject *decals) {
00382 if (data.is_in_view(_camera_mask)) {
00383 PandaNode *node = data.node();
00384
00385 const RenderEffects *node_effects = node->get_effects();
00386 if (node_effects->has_show_bounds()) {
00387
00388
00389 show_bounds(data);
00390 }
00391
00392 data.apply_transform_and_state(this);
00393
00394
00395 int num_children = node->get_num_children();
00396 if (node->has_selective_visibility()) {
00397 int i = node->get_first_visible_child();
00398 while (i < num_children) {
00399 CullTraverserData next_data(data, node->get_child(i));
00400 decals = r_get_decals(next_data, decals);
00401 i = node->get_next_visible_child(i);
00402 }
00403
00404 } else {
00405 for (int i = num_children - 1; i >= 0; i--) {
00406 CullTraverserData next_data(data, node->get_child(i));
00407 decals = r_get_decals(next_data, decals);
00408 }
00409 }
00410
00411
00412 if (node->is_geom_node()) {
00413 GeomNode *geom_node = DCAST(GeomNode, node);
00414
00415 int num_geoms = geom_node->get_num_geoms();
00416 for (int i = num_geoms - 1; i >= 0; i--) {
00417 decals = new CullableObject(data, geom_node, i, decals);
00418 }
00419 }
00420 }
00421
00422 return decals;
00423 }