00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "cullTraverserData.h"
00016 #include "cullTraverser.h"
00017 #include "config_pgraph.h"
00018 #include "pandaNode.h"
00019 #include "colorAttrib.h"
00020 #include "textureAttrib.h"
00021 #include "renderModeAttrib.h"
00022 #include "clipPlaneAttrib.h"
00023 #include "boundingPlane.h"
00024 #include "billboardEffect.h"
00025 #include "compassEffect.h"
00026 #include "polylightEffect.h"
00027 #include "renderState.h"
00028
00029
00030
00031
00032
00033
00034
00035
00036 CPT(TransformState) CullTraverserData::
00037 get_modelview_transform(const CullTraverser *trav) const {
00038 return trav->get_world_transform()->compose(_net_transform);
00039 }
00040
00041
00042
00043
00044
00045
00046
00047
00048 void CullTraverserData::
00049 apply_transform_and_state(CullTraverser *trav) {
00050 CPT(RenderState) node_state = _node_reader.get_state();
00051
00052 if (trav->has_tag_state_key() &&
00053 _node_reader.has_tag(trav->get_tag_state_key())) {
00054
00055
00056
00057 const Camera *camera = trav->get_scene()->get_camera_node();
00058 string tag_state = _node_reader.get_tag(trav->get_tag_state_key());
00059 node_state = node_state->compose(camera->get_tag_state(tag_state));
00060 }
00061 _node_reader.compose_draw_mask(_draw_mask);
00062
00063 apply_transform_and_state(trav, _node_reader.get_transform(),
00064 node_state, _node_reader.get_effects(),
00065 _node_reader.get_off_clip_planes());
00066 }
00067
00068
00069
00070
00071
00072
00073
00074
00075 void CullTraverserData::
00076 apply_transform_and_state(CullTraverser *trav,
00077 CPT(TransformState) node_transform,
00078 CPT(RenderState) node_state,
00079 CPT(RenderEffects) node_effects,
00080 const RenderAttrib *off_clip_planes) {
00081 if (node_effects->has_cull_callback()) {
00082 node_effects->cull_callback(trav, *this, node_transform, node_state);
00083 }
00084
00085 if (!node_transform->is_identity()) {
00086 _net_transform = _net_transform->compose(node_transform);
00087
00088 if ((_view_frustum != (GeometricBoundingVolume *)NULL) ||
00089 (!_cull_planes->is_empty())) {
00090
00091
00092 if (node_transform->is_singular()) {
00093
00094
00095
00096 _view_frustum = (GeometricBoundingVolume *)NULL;
00097 _cull_planes = CullPlanes::make_empty();
00098
00099 } else {
00100 CPT(TransformState) inv_transform =
00101 node_transform->invert_compose(TransformState::make_identity());
00102
00103
00104
00105 if (_view_frustum != (GeometricBoundingVolume *)NULL) {
00106 _view_frustum = DCAST(GeometricBoundingVolume, _view_frustum->make_copy());
00107 _view_frustum->xform(inv_transform->get_mat());
00108 }
00109
00110 _cull_planes = _cull_planes->xform(inv_transform->get_mat());
00111 }
00112 }
00113 }
00114
00115 _state = _state->compose(node_state);
00116
00117 if (clip_plane_cull) {
00118 _cull_planes = _cull_planes->apply_state(trav, this,
00119 DCAST(ClipPlaneAttrib, node_state->get_attrib(ClipPlaneAttrib::get_class_slot())),
00120 DCAST(ClipPlaneAttrib, off_clip_planes),
00121 DCAST(OccluderEffect, node_effects->get_effect(OccluderEffect::get_class_type())));
00122 }
00123 }
00124
00125
00126
00127
00128
00129
00130 bool CullTraverserData::
00131 is_in_view_impl() {
00132 CPT(BoundingVolume) node_volume = _node_reader.get_bounds();
00133 nassertr(node_volume->is_of_type(GeometricBoundingVolume::get_class_type()), false);
00134 const GeometricBoundingVolume *node_gbv =
00135 DCAST(GeometricBoundingVolume, node_volume);
00136
00137 if (_view_frustum != (GeometricBoundingVolume *)NULL) {
00138 int result = _view_frustum->contains(node_gbv);
00139
00140 if (pgraph_cat.is_spam()) {
00141 pgraph_cat.spam()
00142 << _node_path << " cull result = " << hex << result << dec << "\n";
00143 }
00144
00145 if (result == BoundingVolume::IF_no_intersection) {
00146
00147 if (!fake_view_frustum_cull) {
00148 return false;
00149 }
00150
00151
00152
00153
00154 _view_frustum = (GeometricBoundingVolume *)NULL;
00155 CPT(RenderState) fake_state = get_fake_view_frustum_cull_state();
00156 _state = _state->compose(fake_state);
00157
00158 } else if ((result & BoundingVolume::IF_all) != 0) {
00159
00160
00161 _view_frustum = (GeometricBoundingVolume *)NULL;
00162
00163 } else {
00164
00165
00166 if (_node_reader.is_final()) {
00167
00168
00169
00170
00171 _view_frustum = (GeometricBoundingVolume *)NULL;
00172 }
00173 }
00174 }
00175
00176 if (!_cull_planes->is_empty()) {
00177
00178 int result;
00179 _cull_planes = _cull_planes->do_cull(result, _state, node_gbv);
00180
00181 if (pgraph_cat.is_spam()) {
00182 pgraph_cat.spam()
00183 << _node_path << " cull planes cull result = " << hex
00184 << result << dec << "\n";
00185 _cull_planes->write(pgraph_cat.spam(false));
00186 }
00187
00188 if (_node_reader.is_final()) {
00189
00190
00191 _cull_planes = CullPlanes::make_empty();
00192
00193 if (pgraph_cat.is_spam()) {
00194 pgraph_cat.spam()
00195 << _node_path << " is_final, cull planes disabled, state:\n";
00196 _state->write(pgraph_cat.spam(false), 2);
00197 }
00198 }
00199
00200 if (result == BoundingVolume::IF_no_intersection) {
00201
00202 if (!fake_view_frustum_cull) {
00203 return false;
00204 }
00205 _cull_planes = CullPlanes::make_empty();
00206 CPT(RenderState) fake_state = get_fake_view_frustum_cull_state();
00207 _state = _state->compose(fake_state);
00208
00209 } else if ((result & BoundingVolume::IF_all) != 0) {
00210
00211
00212
00213 nassertr(_cull_planes->is_empty(), true);
00214 }
00215 }
00216
00217 return true;
00218 }
00219
00220
00221
00222
00223
00224
00225
00226
00227 CPT(RenderState) CullTraverserData::
00228 get_fake_view_frustum_cull_state() {
00229
00230
00231 static CPT(RenderState) state = (const RenderState *)NULL;
00232 if (state == (const RenderState *)NULL) {
00233 state = RenderState::make
00234 (ColorAttrib::make_flat(LColor(1.0f, 0.0f, 0.0f, 1.0f)),
00235 TextureAttrib::make_all_off(),
00236 RenderModeAttrib::make(RenderModeAttrib::M_wireframe),
00237 RenderState::get_max_priority());
00238 }
00239 return state;
00240 }
00241