00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "scissorEffect.h"
00016 #include "scissorAttrib.h"
00017 #include "cullTraverser.h"
00018 #include "cullTraverserData.h"
00019 #include "nodePath.h"
00020 #include "bamReader.h"
00021 #include "bamWriter.h"
00022 #include "datagram.h"
00023 #include "datagramIterator.h"
00024 #include "boundingHexahedron.h"
00025
00026 TypeHandle ScissorEffect::_type_handle;
00027
00028
00029
00030
00031
00032
00033
00034 ScissorEffect::
00035 ScissorEffect(bool screen, const LVecBase4 &frame,
00036 const PointDef *points, int num_points, bool clip) :
00037 _screen(screen), _frame(frame), _clip(clip)
00038 {
00039 _points.reserve(num_points);
00040 for (int i = 0; i < num_points; ++i) {
00041 _points.push_back(points[i]);
00042 }
00043 }
00044
00045
00046
00047
00048
00049
00050
00051 ScissorEffect::
00052 ScissorEffect(const ScissorEffect ©) :
00053 _screen(copy._screen),
00054 _frame(copy._frame),
00055 _points(copy._points),
00056 _clip(copy._clip)
00057 {
00058 }
00059
00060
00061
00062
00063
00064
00065
00066
00067 CPT(RenderEffect) ScissorEffect::
00068 make_screen(const LVecBase4 &frame, bool clip) {
00069 ScissorEffect *effect = new ScissorEffect(true, frame, NULL, 0, clip);
00070 return return_new(effect);
00071 }
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081 CPT(RenderEffect) ScissorEffect::
00082 make_node(bool clip) {
00083 ScissorEffect *effect = new ScissorEffect(false, LVecBase4::zero(), NULL, 0, clip);
00084 return return_new(effect);
00085 }
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096 CPT(RenderEffect) ScissorEffect::
00097 make_node(const LPoint3 &a, const LPoint3 &b, const NodePath &node) {
00098 PointDef points[2];
00099 points[0]._p = a;
00100 points[0]._node = node;
00101 points[1]._p = b;
00102 points[1]._node = node;
00103 ScissorEffect *effect = new ScissorEffect(false, LVecBase4::zero(), points, 2, true);
00104 return return_new(effect);
00105 }
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116 CPT(RenderEffect) ScissorEffect::
00117 make_node(const LPoint3 &a, const LPoint3 &b, const LPoint3 &c, const LPoint3 &d, const NodePath &node) {
00118 PointDef points[4];
00119 points[0]._p = a;
00120 points[0]._node = node;
00121 points[1]._p = b;
00122 points[1]._node = node;
00123 points[2]._p = c;
00124 points[2]._node = node;
00125 points[3]._p = d;
00126 points[3]._node = node;
00127 ScissorEffect *effect = new ScissorEffect(false, LVecBase4::zero(), points, 4, true);
00128 return return_new(effect);
00129 }
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143 CPT(RenderEffect) ScissorEffect::
00144 add_point(const LPoint3 &p, const NodePath &node) const {
00145 nassertr(!is_screen(), this);
00146 ScissorEffect *effect = new ScissorEffect(*this);
00147 PointDef point;
00148 point._p = p;
00149 point._node = node;
00150 effect->_points.push_back(point);
00151 return return_new(effect);
00152 }
00153
00154
00155
00156
00157
00158
00159
00160 CPT(RenderEffect) ScissorEffect::
00161 xform(const LMatrix4 &mat) const {
00162 if (is_screen()) {
00163 return this;
00164 }
00165 ScissorEffect *effect = new ScissorEffect(*this);
00166 Points::iterator pi;
00167 for (pi = effect->_points.begin();
00168 pi != effect->_points.end();
00169 ++pi) {
00170 PointDef &point = (*pi);
00171 if (point._node.is_empty()) {
00172 point._p = point._p * mat;
00173 }
00174 }
00175 return return_new(effect);
00176 }
00177
00178
00179
00180
00181
00182
00183 void ScissorEffect::
00184 output(ostream &out) const {
00185 out << get_type() << ":";
00186 if (is_screen()) {
00187 out << "screen [" << _frame << "]";
00188 } else {
00189 out << "node";
00190 Points::const_iterator pi;
00191 for (pi = _points.begin(); pi != _points.end(); ++pi) {
00192 const PointDef &point = (*pi);
00193 if (point._node.is_empty()) {
00194 out << " (" << point._p << ")";
00195 } else {
00196 out << " (" << point._node << ":" << point._p << ")";
00197 }
00198 }
00199 }
00200 if (!get_clip()) {
00201 out << " !clip";
00202 }
00203 }
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214 bool ScissorEffect::
00215 has_cull_callback() const {
00216 return true;
00217 }
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236 void ScissorEffect::
00237 cull_callback(CullTraverser *trav, CullTraverserData &data,
00238 CPT(TransformState) &node_transform,
00239 CPT(RenderState) &node_state) const {
00240 LVecBase4 frame;
00241 const Lens *lens = trav->get_scene()->get_lens();
00242 CPT(TransformState) modelview_transform = data.get_modelview_transform(trav);
00243 CPT(TransformState) net_transform = modelview_transform->compose(node_transform);
00244 if (net_transform->is_singular()) {
00245
00246 return;
00247 }
00248
00249 if (is_screen()) {
00250 frame = _frame;
00251 } else {
00252 const LMatrix4 &proj_mat = lens->get_projection_mat();
00253 LMatrix4 net_mat = net_transform->get_mat() * proj_mat;
00254
00255 bool any_points = false;
00256
00257 Points::const_iterator pi;
00258 for (pi = _points.begin(); pi != _points.end(); ++pi) {
00259 const PointDef &point = (*pi);
00260 LVecBase4 pv(point._p[0], point._p[1], point._p[2], 1.0f);
00261 if (point._node.is_empty()) {
00262
00263 pv = pv * net_mat;
00264
00265 } else {
00266
00267 LMatrix4 other_mat = point._node.get_net_transform()->get_mat() * proj_mat;
00268 pv = pv * other_mat;
00269 }
00270
00271 if (pv[3] == 0) {
00272 continue;
00273 }
00274 LPoint3 pr(pv[0] / pv[3], pv[1] / pv[3], pv[2] / pv[3]);
00275 if (!any_points) {
00276 frame[0] = pr[0];
00277 frame[1] = pr[0];
00278 frame[2] = pr[1];
00279 frame[3] = pr[1];
00280 any_points = true;
00281 } else {
00282 frame[0] = min(frame[0], pr[0]);
00283 frame[1] = max(frame[1], pr[0]);
00284 frame[2] = min(frame[2], pr[1]);
00285 frame[3] = max(frame[3], pr[1]);
00286 }
00287 }
00288
00289
00290 frame[0] = (frame[0] + 1.0f) * 0.5f;
00291 frame[1] = (frame[1] + 1.0f) * 0.5f;
00292 frame[2] = (frame[2] + 1.0f) * 0.5f;
00293 frame[3] = (frame[3] + 1.0f) * 0.5f;
00294 }
00295
00296
00297 frame[0] = max(min(frame[0], (PN_stdfloat)1.0), (PN_stdfloat)0.0);
00298 frame[1] = max(min(frame[1], (PN_stdfloat)1.0), frame[0]);
00299 frame[2] = max(min(frame[2], (PN_stdfloat)1.0), (PN_stdfloat)0.0);
00300 frame[3] = max(min(frame[3], (PN_stdfloat)1.0), frame[2]);
00301
00302 if (_clip) {
00303 CPT(RenderAttrib) scissor_attrib = ScissorAttrib::make(frame);
00304 CPT(RenderState) state = RenderState::make(scissor_attrib);
00305 node_state = node_state->compose(state);
00306 }
00307
00308
00309
00310 PT(GeometricBoundingVolume) frustum = make_frustum(lens, frame);
00311 if (frustum != (GeometricBoundingVolume *)NULL) {
00312 frustum->xform(modelview_transform->get_inverse()->get_mat());
00313 data._view_frustum = frustum;
00314 }
00315 }
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332 int ScissorEffect::
00333 compare_to_impl(const RenderEffect *other) const {
00334 const ScissorEffect *ta;
00335 DCAST_INTO_R(ta, other, 0);
00336
00337 if (_screen != ta->_screen) {
00338 return (int)_screen - (int)ta->_screen;
00339 }
00340 if (_clip != ta->_clip) {
00341 return (int)_clip - (int)ta->_clip;
00342 }
00343 if (_screen) {
00344 int compare = _frame.compare_to(ta->_frame);
00345 if (compare != 0) {
00346 return compare;
00347 }
00348 } else {
00349 int compare = (int)_points.size() - (int)ta->_points.size();
00350 if (compare != 0) {
00351 return compare;
00352 }
00353 for (size_t i = 0; i < _points.size(); ++i) {
00354 compare = _points[i]._p.compare_to(ta->_points[i]._p);
00355 if (compare != 0) {
00356 return compare;
00357 }
00358 compare = _points[i]._node.compare_to(ta->_points[i]._node);
00359 if (compare != 0) {
00360 return compare;
00361 }
00362 }
00363 }
00364 return 0;
00365 }
00366
00367
00368
00369
00370
00371
00372
00373 void ScissorEffect::
00374 register_with_read_factory() {
00375 BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
00376 }
00377
00378
00379
00380
00381
00382
00383
00384 void ScissorEffect::
00385 write_datagram(BamWriter *manager, Datagram &dg) {
00386 RenderEffect::write_datagram(manager, dg);
00387
00388 dg.add_bool(_screen);
00389 if (_screen) {
00390 _frame.write_datagram(dg);
00391 } else {
00392 dg.add_uint16(_points.size());
00393 Points::const_iterator pi;
00394 for (pi = _points.begin(); pi != _points.end(); ++pi) {
00395 (*pi)._p.write_datagram(dg);
00396 }
00397 }
00398 dg.add_bool(_clip);
00399 }
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409 TypedWritable *ScissorEffect::
00410 make_from_bam(const FactoryParams ¶ms) {
00411 ScissorEffect *effect = new ScissorEffect(true, LVecBase4::zero(), NULL, 0, false);
00412 DatagramIterator scan;
00413 BamReader *manager;
00414
00415 parse_params(params, scan, manager);
00416 effect->fillin(scan, manager);
00417
00418 return effect;
00419 }
00420
00421
00422
00423
00424
00425
00426
00427
00428 void ScissorEffect::
00429 fillin(DatagramIterator &scan, BamReader *manager) {
00430 RenderEffect::fillin(scan, manager);
00431
00432 _screen = scan.get_bool();
00433 if (_screen) {
00434 _frame.read_datagram(scan);
00435 } else {
00436 int num_points = scan.get_uint16();
00437 _points.reserve(num_points);
00438 for (int i = 0; i < num_points; ++i) {
00439 PointDef point;
00440 point._p.read_datagram(scan);
00441 _points.push_back(point);
00442 }
00443 }
00444 _clip = scan.get_bool();
00445 }
00446
00447
00448
00449
00450
00451
00452
00453 PT(GeometricBoundingVolume) ScissorEffect::
00454 make_frustum(const Lens *lens, const LVecBase4 &frame) const{
00455
00456 LVecBase4 f2(frame[0] * 2.0f - 1.0f,
00457 frame[1] * 2.0f - 1.0f,
00458 frame[2] * 2.0f - 1.0f,
00459 frame[3] * 2.0f - 1.0f);
00460
00461 LPoint3 fll, flr, ful, fur;
00462 LPoint3 nll, nlr, nul, nur;
00463 LPoint2 corner;
00464
00465 corner[0] = f2[0]; corner[1] = f2[3];
00466
00467
00468 if (!lens->extrude(corner, nul, ful)) {
00469 return (GeometricBoundingVolume *)NULL;
00470 }
00471
00472 corner[0] = f2[1]; corner[1] = f2[3];
00473
00474
00475 if (!lens->extrude(corner, nur, fur)) {
00476 return (GeometricBoundingVolume *)NULL;
00477 }
00478
00479 corner[0] = f2[1]; corner[1] = f2[2];
00480
00481
00482 if (!lens->extrude(corner, nlr, flr)) {
00483 return (GeometricBoundingVolume *)NULL;
00484 }
00485
00486 corner[0] = f2[0]; corner[1] = f2[2];
00487
00488
00489 if (!lens->extrude(corner, nll, fll)) {
00490 return (GeometricBoundingVolume *)NULL;
00491 }
00492
00493 return new BoundingHexahedron(fll, flr, fur, ful, nll, nlr, nur, nul);
00494 }