Panda3D
|
00001 // Filename: scissorEffect.cxx 00002 // Created by: drose (30Jul08) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 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 // Function: ScissorEffect::Constructor 00030 // Access: Private 00031 // Description: Use ScissorEffect::make() to construct a new 00032 // ScissorEffect object. 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 // Function: ScissorEffect::Copy Constructor 00047 // Access: Private 00048 // Description: Use ScissorEffect::make() to construct a new 00049 // ScissorEffect object. 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 // Function: ScissorEffect::make_screen 00062 // Access: Published, Static 00063 // Description: Constructs a new screen-relative ScissorEffect. The 00064 // frame defines a left, right, bottom, top region, 00065 // relative to the DisplayRegion. See ScissorAttrib. 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 // Function: ScissorEffect::make_node 00075 // Access: Published, Static 00076 // Description: Constructs a new node-relative ScissorEffect, with no 00077 // points. This empty ScissorEffect does nothing. You 00078 // must then call add_point a number of times to add the 00079 // points you require. 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 // Function: ScissorEffect::make_node 00089 // Access: Published, Static 00090 // Description: Constructs a new node-relative ScissorEffect. The 00091 // two points are understood to be relative to the 00092 // indicated node, or the current node if the NodePath 00093 // is empty, and determine the diagonally opposite 00094 // corners of the scissor region. 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 // Function: ScissorEffect::make_node 00109 // Access: Published, Static 00110 // Description: Constructs a new node-relative ScissorEffect. The 00111 // four points are understood to be relative to the 00112 // indicated node, or the current node if the indicated 00113 // NodePath is empty, and determine four points 00114 // surrounding the scissor region. 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 // Function: ScissorEffect::add_point 00133 // Access: Published 00134 // Description: Returns a new ScissorEffect with the indicated point 00135 // added. It is only valid to call this on a "node" 00136 // type ScissorEffect. The full set of points, 00137 // projected into screen space, defines the bounding 00138 // volume of the rectangular scissor region. 00139 // 00140 // Each point may be relative to a different node, if 00141 // desired. 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 // Function: ScissorEffect::xform 00156 // Access: Public, Virtual 00157 // Description: Returns a new RenderEffect transformed by the 00158 // indicated matrix. 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 // Function: ScissorEffect::output 00180 // Access: Public, Virtual 00181 // Description: 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 // Function: ScissorEffect::has_cull_callback 00207 // Access: Public, Virtual 00208 // Description: Should be overridden by derived classes to return 00209 // true if cull_callback() has been defined. Otherwise, 00210 // returns false to indicate cull_callback() does not 00211 // need to be called for this effect during the cull 00212 // traversal. 00213 //////////////////////////////////////////////////////////////////// 00214 bool ScissorEffect:: 00215 has_cull_callback() const { 00216 return true; 00217 } 00218 00219 //////////////////////////////////////////////////////////////////// 00220 // Function: ScissorEffect::cull_callback 00221 // Access: Public, Virtual 00222 // Description: If has_cull_callback() returns true, this function 00223 // will be called during the cull traversal to perform 00224 // any additional operations that should be performed at 00225 // cull time. This may include additional manipulation 00226 // of render state or additional visible/invisible 00227 // decisions, or any other arbitrary operation. 00228 // 00229 // At the time this function is called, the current 00230 // node's transform and state have not yet been applied 00231 // to the net_transform and net_state. This callback 00232 // may modify the node_transform and node_state to apply 00233 // an effective change to the render state at this 00234 // level. 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 // If we're under a singular transform, never mind. 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 // Relative to this node. 00263 pv = pv * net_mat; 00264 00265 } else { 00266 // Relative to some other node. 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 // Scale from -1..1 to 0..1. 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 // Impose bounding volumes. 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 // Set up the culling. We do this by extruding the four corners of 00309 // the frame into the eight corners of the bounding frustum. 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 // Function: ScissorEffect::compare_to_impl 00319 // Access: Protected, Virtual 00320 // Description: Intended to be overridden by derived ScissorEffect 00321 // types to return a unique number indicating whether 00322 // this ScissorEffect is equivalent to the other one. 00323 // 00324 // This should return 0 if the two ScissorEffect objects 00325 // are equivalent, a number less than zero if this one 00326 // should be sorted before the other one, and a number 00327 // greater than zero otherwise. 00328 // 00329 // This will only be called with two ScissorEffect 00330 // objects whose get_type() functions return the same. 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 // Function: ScissorEffect::register_with_read_factory 00369 // Access: Public, Static 00370 // Description: Tells the BamReader how to create objects of type 00371 // ScissorEffect. 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 // Function: ScissorEffect::write_datagram 00380 // Access: Public, Virtual 00381 // Description: Writes the contents of this object to the datagram 00382 // for shipping out to a Bam file. 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 // Function: ScissorEffect::make_from_bam 00403 // Access: Protected, Static 00404 // Description: This function is called by the BamReader's factory 00405 // when a new object of type ScissorEffect is encountered 00406 // in the Bam file. It should create the ScissorEffect 00407 // and extract its information from the file. 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 // Function: ScissorEffect::fillin 00423 // Access: Protected 00424 // Description: This internal function is called by make_from_bam to 00425 // read in all of the relevant data from the BamFile for 00426 // the new ScissorEffect. 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 // Function: ScissorEffect::make_frustum 00449 // Access: Private 00450 // Description: Constructs a new bounding frustum from the lens 00451 // properties, given the indicated scissor frame. 00452 //////////////////////////////////////////////////////////////////// 00453 PT(GeometricBoundingVolume) ScissorEffect:: 00454 make_frustum(const Lens *lens, const LVecBase4 &frame) const{ 00455 // Scale the frame from 0 .. 1 into -1 .. 1. 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 // Upper left. 00468 if (!lens->extrude(corner, nul, ful)) { 00469 return (GeometricBoundingVolume *)NULL; 00470 } 00471 00472 corner[0] = f2[1]; corner[1] = f2[3]; 00473 00474 // Upper right. 00475 if (!lens->extrude(corner, nur, fur)) { 00476 return (GeometricBoundingVolume *)NULL; 00477 } 00478 00479 corner[0] = f2[1]; corner[1] = f2[2]; 00480 00481 // Lower right. 00482 if (!lens->extrude(corner, nlr, flr)) { 00483 return (GeometricBoundingVolume *)NULL; 00484 } 00485 00486 corner[0] = f2[0]; corner[1] = f2[2]; 00487 00488 // Lower left. 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 }