Panda3D
|
00001 // Filename: lens.cxx 00002 // Created by: drose (18Feb99) 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 "lens.h" 00016 #include "throw_event.h" 00017 #include "compose_matrix.h" 00018 #include "look_at.h" 00019 #include "geom.h" 00020 #include "geomLinestrips.h" 00021 #include "geomVertexWriter.h" 00022 #include "boundingHexahedron.h" 00023 #include "indent.h" 00024 #include "config_gobj.h" 00025 #include "plane.h" 00026 00027 TypeHandle Lens::_type_handle; 00028 TypeHandle Lens::CData::_type_handle; 00029 00030 //////////////////////////////////////////////////////////////////// 00031 // Function: Lens::Constructor 00032 // Access: Public 00033 // Description: 00034 //////////////////////////////////////////////////////////////////// 00035 Lens:: 00036 Lens() { 00037 clear(); 00038 } 00039 00040 //////////////////////////////////////////////////////////////////// 00041 // Function: Lens::Copy Constructor 00042 // Access: Public 00043 // Description: 00044 //////////////////////////////////////////////////////////////////// 00045 Lens:: 00046 Lens(const Lens ©) : _cycler(copy._cycler) { 00047 // We don't copy the _geom_data. That's unique to each Lens. 00048 CDWriter cdata(_cycler, true); 00049 cdata->_geom_data = NULL; 00050 } 00051 00052 //////////////////////////////////////////////////////////////////// 00053 // Function: Lens::Copy Assignment Operator 00054 // Access: Public 00055 // Description: 00056 //////////////////////////////////////////////////////////////////// 00057 void Lens:: 00058 operator = (const Lens ©) { 00059 _cycler = copy._cycler; 00060 00061 // We don't copy the _geom_data. That's unique to each Lens. 00062 CDWriter cdata(_cycler, true); 00063 cdata->_geom_data = NULL; 00064 } 00065 00066 //////////////////////////////////////////////////////////////////// 00067 // Function: Lens::set_coordinate_system 00068 // Access: Published 00069 // Description: Specifies the coordinate system that all 3-d 00070 // computations are performed within for this 00071 // Lens. Normally, this is CS_default. 00072 //////////////////////////////////////////////////////////////////// 00073 void Lens:: 00074 set_coordinate_system(CoordinateSystem cs) { 00075 CDWriter cdata(_cycler, true); 00076 cdata->_cs = cs; 00077 do_adjust_comp_flags(cdata, CF_mat | CF_view_hpr | CF_view_vector, 0); 00078 do_throw_change_event(cdata); 00079 } 00080 00081 //////////////////////////////////////////////////////////////////// 00082 // Function: Lens::clear 00083 // Access: Published 00084 // Description: Resets all lens parameters to their initial default 00085 // settings. 00086 //////////////////////////////////////////////////////////////////// 00087 void Lens:: 00088 clear() { 00089 CDWriter cdata(_cycler, true); 00090 cdata->clear(); 00091 00092 do_set_interocular_distance(cdata, default_iod); 00093 do_set_convergence_distance(cdata, default_converge); 00094 do_throw_change_event(cdata); 00095 } 00096 00097 //////////////////////////////////////////////////////////////////// 00098 // Function: Lens::set_min_fov 00099 // Access: Published 00100 // Description: Sets the field of view of the smallest dimension of 00101 // the window. If the window is wider than it is tall, 00102 // this specifies the vertical field of view; if it is 00103 // taller than it is wide, this specifies the horizontal 00104 // field of view. 00105 // 00106 // In many cases, this is preferable to setting either 00107 // the horizontal or vertical field of view explicitly. 00108 // Setting this parameter means that pulling the window 00109 // wider will widen the field of view, which is usually 00110 // what you expect to happen. 00111 //////////////////////////////////////////////////////////////////// 00112 void Lens:: 00113 set_min_fov(PN_stdfloat min_fov) { 00114 nassertv(!cnan(min_fov)); 00115 CDWriter cdata(_cycler, true); 00116 cdata->_min_fov = min_fov; 00117 00118 // We can't specify all three of focal length, fov, and film size. 00119 // Throw out the oldest one. 00120 do_resequence_fov_triad(cdata, cdata->_fov_seq, cdata->_focal_length_seq, cdata->_film_size_seq); 00121 00122 if (cdata->_focal_length_seq == 0) { 00123 // Throw out focal length if it's oldest. 00124 do_adjust_user_flags(cdata, UF_focal_length | UF_vfov | UF_hfov, 00125 UF_min_fov); 00126 } else { 00127 // Otherwise, throw out film size. 00128 nassertv(cdata->_film_size_seq == 0); 00129 00130 // Make sure we save the aspect ratio first. 00131 do_compute_aspect_ratio(cdata); 00132 do_adjust_user_flags(cdata, UF_film_width | UF_film_height | UF_vfov | UF_hfov, 00133 UF_min_fov); 00134 } 00135 do_adjust_comp_flags(cdata, CF_mat | CF_focal_length | CF_fov | CF_film_size, 00136 0); 00137 // We leave CF_fov off of comp_flags, because we will still need to 00138 // recompute the vertical fov. It's not exactly the same as hfov * 00139 // get_aspect_ratio(). 00140 do_throw_change_event(cdata); 00141 } 00142 00143 //////////////////////////////////////////////////////////////////// 00144 // Function: Lens::get_min_fov 00145 // Access: Published 00146 // Description: Returns the field of view of the narrowest dimension 00147 // of the window. See set_min_fov(). 00148 //////////////////////////////////////////////////////////////////// 00149 PN_stdfloat Lens:: 00150 get_min_fov() const { 00151 CDReader cdata(_cycler); 00152 00153 if ((cdata->_comp_flags & CF_fov) == 0) { 00154 ((Lens *)this)->do_compute_fov((CData *)cdata.p()); 00155 } 00156 return cdata->_min_fov; 00157 } 00158 00159 //////////////////////////////////////////////////////////////////// 00160 // Function: Lens::get_default_near 00161 // Access: Published, Static 00162 // Description: Returns the default near plane distance that will be 00163 // assigned to each newly-created lens. This is read 00164 // from the Configrc file. 00165 //////////////////////////////////////////////////////////////////// 00166 PN_stdfloat Lens:: 00167 get_default_near() { 00168 return default_near; 00169 } 00170 00171 //////////////////////////////////////////////////////////////////// 00172 // Function: Lens::get_default_far 00173 // Access: Published, Static 00174 // Description: Returns the default far plane distance that will be 00175 // assigned to each newly-created lens. This is read 00176 // from the Configrc file. 00177 //////////////////////////////////////////////////////////////////// 00178 PN_stdfloat Lens:: 00179 get_default_far() { 00180 return default_far; 00181 } 00182 00183 //////////////////////////////////////////////////////////////////// 00184 // Function: Lens::set_view_hpr 00185 // Access: Published 00186 // Description: Sets the direction in which the lens is facing. 00187 // Normally, this is down the forward axis (usually the 00188 // Y axis), but it may be rotated. This is only one way 00189 // of specifying the rotation; you may also specify an 00190 // explicit vector in which to look, or you may give a 00191 // complete transformation matrix. 00192 //////////////////////////////////////////////////////////////////// 00193 void Lens:: 00194 set_view_hpr(const LVecBase3 &view_hpr) { 00195 nassertv(!view_hpr.is_nan()); 00196 CDWriter cdata(_cycler, true); 00197 cdata->_view_hpr = view_hpr; 00198 do_adjust_user_flags(cdata, UF_view_vector | UF_view_mat, 00199 UF_view_hpr); 00200 do_adjust_comp_flags(cdata, CF_mat | CF_view_vector, 00201 CF_view_hpr); 00202 do_throw_change_event(cdata); 00203 } 00204 00205 //////////////////////////////////////////////////////////////////// 00206 // Function: Lens::get_view_hpr 00207 // Access: Published 00208 // Description: Returns the direction in which the lens is facing. 00209 //////////////////////////////////////////////////////////////////// 00210 const LVecBase3 &Lens:: 00211 get_view_hpr() const { 00212 CDReader cdata(_cycler); 00213 if ((cdata->_comp_flags & CF_view_hpr) == 0) { 00214 ((Lens *)this)->do_compute_view_hpr((CData *)cdata.p()); 00215 } 00216 return cdata->_view_hpr; 00217 } 00218 00219 //////////////////////////////////////////////////////////////////// 00220 // Function: Lens::set_view_vector 00221 // Access: Published 00222 // Description: Specifies the direction in which the lens is facing 00223 // by giving an axis to look along, and a perpendicular 00224 // (or at least non-parallel) up axis. 00225 // 00226 // See also set_view_hpr(). 00227 //////////////////////////////////////////////////////////////////// 00228 void Lens:: 00229 set_view_vector(const LVector3 &view_vector, const LVector3 &up_vector) { 00230 nassertv(!view_vector.is_nan()); 00231 CDWriter cdata(_cycler, true); 00232 cdata->_view_vector = view_vector; 00233 cdata->_up_vector = up_vector; 00234 do_adjust_user_flags(cdata, UF_view_hpr | UF_view_mat, 00235 UF_view_vector); 00236 do_adjust_comp_flags(cdata, CF_mat | CF_view_hpr, 00237 CF_view_vector); 00238 do_throw_change_event(cdata); 00239 } 00240 00241 //////////////////////////////////////////////////////////////////// 00242 // Function: Lens::get_view_vector 00243 // Access: Published 00244 // Description: Returns the axis along which the lens is facing. 00245 //////////////////////////////////////////////////////////////////// 00246 const LVector3 &Lens:: 00247 get_view_vector() const { 00248 CDReader cdata(_cycler); 00249 if ((cdata->_comp_flags & CF_view_vector) == 0) { 00250 ((Lens *)this)->do_compute_view_vector((CData *)cdata.p()); 00251 } 00252 return cdata->_view_vector; 00253 } 00254 00255 //////////////////////////////////////////////////////////////////// 00256 // Function: Lens::get_up_vector 00257 // Access: Published 00258 // Description: Returns the axis perpendicular to the camera's view 00259 // vector that indicates the "up" direction. 00260 //////////////////////////////////////////////////////////////////// 00261 const LVector3 &Lens:: 00262 get_up_vector() const { 00263 CDReader cdata(_cycler); 00264 if ((cdata->_comp_flags & CF_view_vector) == 0) { 00265 ((Lens *)this)->do_compute_view_vector((CData *)cdata.p()); 00266 } 00267 return cdata->_up_vector; 00268 } 00269 00270 //////////////////////////////////////////////////////////////////// 00271 // Function: Lens::get_nodal_point 00272 // Access: Published 00273 // Description: Returns the center point of the lens: the point from 00274 // which the lens is viewing. 00275 //////////////////////////////////////////////////////////////////// 00276 LPoint3 Lens:: 00277 get_nodal_point() const { 00278 return get_view_mat().get_row3(3); 00279 } 00280 00281 //////////////////////////////////////////////////////////////////// 00282 // Function: Lens::clear_view_mat 00283 // Access: Published 00284 // Description: Resets the lens transform to identity. 00285 //////////////////////////////////////////////////////////////////// 00286 void Lens:: 00287 clear_view_mat() { 00288 CDWriter cdata(_cycler, true); 00289 cdata->_lens_mat = LMatrix4::ident_mat(); 00290 do_adjust_user_flags(cdata, 0, UF_view_vector | UF_view_hpr | UF_view_mat); 00291 do_adjust_comp_flags(cdata, CF_projection_mat | CF_projection_mat_inv | 00292 CF_projection_mat_left_inv | CF_projection_mat_right_inv | 00293 CF_lens_mat_inv | CF_view_hpr | CF_view_vector, 00294 CF_lens_mat); 00295 do_throw_change_event(cdata); 00296 } 00297 00298 //////////////////////////////////////////////////////////////////// 00299 // Function: Lens::set_keystone 00300 // Access: Published 00301 // Description: Indicates the ratio of keystone correction to perform 00302 // on the lens, in each of three axes. This will build 00303 // a special non-affine scale factor into the projection 00304 // matrix that will compensate for keystoning of a 00305 // projected image; this can be used to compensate for a 00306 // projector that for physical reasons cannot be aimed 00307 // directly at its screen. 00308 // 00309 // The default value is taken from the default-keystone 00310 // Config variable. 0, 0 indicates no keystone 00311 // correction; specify a small value (usually in the 00312 // range -1 .. 1) in either the x or y position to 00313 // generate a keystone correction in that axis. 00314 //////////////////////////////////////////////////////////////////// 00315 void Lens:: 00316 set_keystone(const LVecBase2 &keystone) { 00317 nassertv(!keystone.is_nan()); 00318 CDWriter cdata(_cycler, true); 00319 cdata->_keystone = keystone; 00320 do_adjust_user_flags(cdata, 0, UF_keystone); 00321 do_adjust_comp_flags(cdata, CF_projection_mat | CF_projection_mat_inv | 00322 CF_projection_mat_left_inv | CF_projection_mat_right_inv | 00323 CF_film_mat | CF_film_mat_inv, 0); 00324 do_throw_change_event(cdata); 00325 } 00326 00327 //////////////////////////////////////////////////////////////////// 00328 // Function: Lens::clear_keystone 00329 // Access: Published 00330 // Description: Disables the lens keystone correction. 00331 //////////////////////////////////////////////////////////////////// 00332 void Lens:: 00333 clear_keystone() { 00334 CDWriter cdata(_cycler, true); 00335 cdata->_keystone.set(0.0f, 0.0f); 00336 do_adjust_user_flags(cdata, UF_keystone, 0); 00337 do_adjust_comp_flags(cdata, CF_projection_mat | CF_projection_mat_inv | 00338 CF_projection_mat_left_inv | CF_projection_mat_right_inv | 00339 CF_film_mat | CF_film_mat_inv, 0); 00340 do_throw_change_event(cdata); 00341 } 00342 00343 //////////////////////////////////////////////////////////////////// 00344 // Function: Lens::set_frustum_from_corners 00345 // Access: Published 00346 // Description: Sets up the lens to use the frustum defined by the 00347 // four indicated points. This is most useful for a 00348 // PerspectiveLens, but it may be called for other kinds 00349 // of lenses as well. 00350 // 00351 // The frustum will be rooted at the origin (or by 00352 // whatever translation might have been specified in a 00353 // previous call to set_view_mat). 00354 // 00355 // It is legal for the four points not to be arranged in 00356 // a rectangle; if this is the case, the frustum will be 00357 // fitted as tightly as possible to cover all four 00358 // points. 00359 // 00360 // The flags parameter contains the union of one or more 00361 // of the following bits to control the behavior of this 00362 // function: 00363 // 00364 // FC_roll - If this is included, the camera may be 00365 // rotated so that its up vector is perpendicular to the 00366 // top line. Otherwise, the standard up vector is used. 00367 // 00368 // FC_camera_plane - This allows the camera plane to be 00369 // adjusted to be as nearly perpendicular to the center 00370 // of the frustum as possible. Without this bit, the 00371 // orientation camera plane is defined by position of 00372 // the four points (which should all be coplanar). With 00373 // this bit, the camera plane is arbitarary, and may be 00374 // chosen so that the four points do not themselves lie 00375 // in the camera plane (but the points will still be 00376 // within the frustum). 00377 // 00378 // FC_off_axis - This allows the resulting frustum to be 00379 // off-axis to get the tightest possible fit. Without 00380 // this bit, the viewing axis will be centered within 00381 // the frustum, but there may be more wasted space along 00382 // the edges. 00383 // 00384 // FC_aspect_ratio - This allows the frustum to be 00385 // scaled non-proportionately in the vertical and 00386 // horizontal dimensions, if necessary, to get a tighter 00387 // fit. Without this bit, the current aspect ratio will 00388 // be preserved. 00389 // 00390 // FC_shear - This allows the frustum to be sheared, if 00391 // necessary, to get the tightest possible fit. This 00392 // may result in a parallelogram-based frustum, which 00393 // will give a slanted appearance to the rendered image. 00394 // Without this bit, the frustum will be 00395 // rectangle-based. 00396 // 00397 // In general, if 0 is passed in as the value for flags, 00398 // the generated frustum will be a loose fit but sane; 00399 // if -1 is passed in, it will be a tighter fit and 00400 // possibly screwy. 00401 //////////////////////////////////////////////////////////////////// 00402 void Lens:: 00403 set_frustum_from_corners(const LVecBase3 &ul, const LVecBase3 &ur, 00404 const LVecBase3 &ll, const LVecBase3 &lr, 00405 int flags) { 00406 nassertv(!ul.is_nan() && !ur.is_nan() && !ll.is_nan() && !lr.is_nan()); 00407 00408 CDWriter cdata(_cycler, true); 00409 // We'll need to know the pre-existing eyepoint translation from the 00410 // center, so we can preserve it in the new frustum. This is 00411 // usually (0, 0, 0), but it could be an arbitrary vector. 00412 const LMatrix4 &lens_mat_inv = do_get_lens_mat_inv(cdata); 00413 LVector3 eye_offset; 00414 lens_mat_inv.get_row3(eye_offset, 3); 00415 00416 // Now choose the viewing axis. If FC_camera_plane is specified, 00417 // we'll pass it through the centroid for the best camera plane; 00418 // otherwise, it's perpendicular to the plane in which the points 00419 // lie. 00420 LVector3 view_vector; 00421 if ((flags & FC_camera_plane) != 0) { 00422 view_vector = (ul + ur + ll + lr) * 0.25; 00423 } else { 00424 LPlane plane(ll, ul, ur); 00425 view_vector = plane.get_normal(); 00426 nassertv(!view_vector.is_nan() && view_vector.length_squared() != 0.0f); 00427 } 00428 00429 // Now determine the up axis. If FC_roll is specified, or if our 00430 // view vector is straight up, it is the vector perpendicular to 00431 // both the viewing axis and the top line. Otherwise, it is the 00432 // standard up axis. 00433 LVector3 up_vector = LVector3::up(cdata->_cs); 00434 if (view_vector == up_vector || ((flags & FC_roll) != 0)) { 00435 LVector3 top = ul - ur; 00436 up_vector = view_vector.cross(top); 00437 nassertv(!up_vector.is_nan() && up_vector.length_squared() != 0.0f); 00438 } 00439 00440 // Now compute the matrix that applies this rotation. 00441 LMatrix4 rot_mat; 00442 look_at(rot_mat, view_vector, up_vector, CS_zup_right); 00443 00444 // And invert it. 00445 LMatrix4 inv_rot_mat; 00446 inv_rot_mat.invert_affine_from(rot_mat); 00447 00448 // Use that inverse matrix to convert the four corners to a local 00449 // coordinate system, looking down the Y axis. 00450 LPoint3 cul = inv_rot_mat.xform_point(ul); 00451 LPoint3 cur = inv_rot_mat.xform_point(ur); 00452 LPoint3 cll = inv_rot_mat.xform_point(ll); 00453 LPoint3 clr = inv_rot_mat.xform_point(lr); 00454 00455 // Project all points into the Y == 1 plane, so we can do 2-d 00456 // manipulation on them. 00457 nassertv(cul[1] != 0.0f && cur[1] != 0.0f && cll[1] != 0.0f && clr[1] != 0.0f); 00458 cul /= cul[1]; 00459 cur /= cur[1]; 00460 cll /= cll[1]; 00461 clr /= clr[1]; 00462 00463 LMatrix4 shear_mat = LMatrix4::ident_mat(); 00464 LMatrix4 inv_shear_mat = LMatrix4::ident_mat(); 00465 00466 // Now, if we're allowed to shear the frustum, do so. 00467 if ((flags & FC_shear) != 0) { 00468 build_shear_mat(shear_mat, cul, cur, cll, clr); 00469 inv_shear_mat.invert_from(shear_mat); 00470 } 00471 00472 // Now build the complete view matrix. 00473 LMatrix4 inv_view_mat = 00474 inv_rot_mat * 00475 inv_shear_mat; 00476 00477 // And reapply the eye offset to this matrix. 00478 inv_view_mat.set_row(3, eye_offset); 00479 00480 LMatrix4 view_mat; 00481 view_mat.invert_from(inv_view_mat); 00482 do_set_view_mat(cdata, view_mat); 00483 00484 LPoint3 ful = inv_view_mat.xform_point(ul); 00485 LPoint3 fur = inv_view_mat.xform_point(ur); 00486 LPoint3 fll = inv_view_mat.xform_point(ll); 00487 LPoint3 flr = inv_view_mat.xform_point(lr); 00488 00489 // Normalize *these* points into the y == 1 plane. 00490 nassertv(ful[1] != 0.0f && fur[1] != 0.0f && fll[1] != 0.0f && flr[1] != 0.0f); 00491 ful /= ful[1]; 00492 fur /= fur[1]; 00493 fll /= fll[1]; 00494 flr /= flr[1]; 00495 00496 // Determine the minimum field of view necesary to cover all four 00497 // transformed points. 00498 PN_stdfloat min_x = min(min(ful[0], fur[0]), min(fll[0], flr[0])); 00499 PN_stdfloat max_x = max(max(ful[0], fur[0]), max(fll[0], flr[0])); 00500 PN_stdfloat min_z = min(min(ful[2], fur[2]), min(fll[2], flr[2])); 00501 PN_stdfloat max_z = max(max(ful[2], fur[2]), max(fll[2], flr[2])); 00502 00503 PN_stdfloat x_spread, x_center, z_spread, z_center; 00504 00505 if ((flags & FC_off_axis) != 0) { 00506 // If we're allowed to make an off-axis projection, then pick the 00507 // best center. 00508 x_center = (max_x + min_x) * 0.5f; 00509 z_center = (max_z + min_z) * 0.5f; 00510 x_spread = x_center - min_x; 00511 z_spread = z_center - min_z; 00512 } else { 00513 // Otherwise, the center must be (0, 0). 00514 x_center = 0.0f; 00515 z_center = 0.0f; 00516 x_spread = max(cabs(max_x), cabs(min_x)); 00517 z_spread = max(cabs(max_z), cabs(min_z)); 00518 } 00519 00520 PN_stdfloat aspect_ratio = do_get_aspect_ratio(cdata); 00521 nassertv(aspect_ratio != 0.0f); 00522 if ((flags & FC_aspect_ratio) == 0) { 00523 // If we must preserve the aspect ratio, then the x and z spreads 00524 // must be adjusted to match. 00525 if (x_spread < z_spread * aspect_ratio) { 00526 // x_spread is too small. 00527 x_spread = z_spread * aspect_ratio; 00528 } else if (z_spread < x_spread / aspect_ratio) { 00529 // z_spread is too small. 00530 z_spread = x_spread / aspect_ratio; 00531 } 00532 } 00533 00534 PN_stdfloat hfov = rad_2_deg(catan(x_spread)) * 2.0f; 00535 PN_stdfloat vfov = rad_2_deg(catan(z_spread)) * 2.0f; 00536 00537 do_set_fov(cdata, LVecBase2(hfov, vfov)); 00538 00539 if ((flags & FC_aspect_ratio) == 0) { 00540 // If we must preserve the aspect ratio, store it one more time. 00541 // This is mainly in case we have a non-perspective lens with a 00542 // funny relationship between fov and aspect ratio. 00543 do_set_aspect_ratio(cdata, aspect_ratio); 00544 } 00545 00546 const LVecBase2 &film_size = do_get_film_size(cdata); 00547 nassertv(x_spread != 0.0f && z_spread != 0.0f); 00548 do_set_film_offset(cdata, LVecBase2(film_size[0] * x_center / (x_spread * 2.0f), 00549 film_size[1] * z_center / (z_spread * 2.0f))); 00550 } 00551 00552 00553 //////////////////////////////////////////////////////////////////// 00554 // Function: Lens::recompute_all 00555 // Access: Published 00556 // Description: Forces all internal parameters of the Lens to be 00557 // recomputed. Normally, this should never need to be 00558 // called; it is provided only to assist in debugging. 00559 //////////////////////////////////////////////////////////////////// 00560 void Lens:: 00561 recompute_all() { 00562 CDWriter cdata(_cycler); 00563 cdata->_comp_flags = 0; 00564 } 00565 00566 //////////////////////////////////////////////////////////////////// 00567 // Function: Lens::is_linear 00568 // Access: Published, Virtual 00569 // Description: Returns true if the lens represents a linear 00570 // projection (e.g. PerspectiveLens, OrthographicLens), 00571 // and therefore there is a valid matrix returned by 00572 // get_projection_mat(), or false otherwise. 00573 //////////////////////////////////////////////////////////////////// 00574 bool Lens:: 00575 is_linear() const { 00576 return false; 00577 } 00578 00579 //////////////////////////////////////////////////////////////////// 00580 // Function: Lens::is_perspective 00581 // Access: Published, Virtual 00582 // Description: Returns true if the lens represents a perspective 00583 // projection (i.e. it is a PerspectiveLens), false 00584 // otherwise. 00585 //////////////////////////////////////////////////////////////////// 00586 bool Lens:: 00587 is_perspective() const { 00588 return false; 00589 } 00590 00591 //////////////////////////////////////////////////////////////////// 00592 // Function: Lens::is_orthographic 00593 // Access: Published, Virtual 00594 // Description: Returns true if the lens represents a orthographic 00595 // projection (i.e. it is a OrthographicLens), false 00596 // otherwise. 00597 //////////////////////////////////////////////////////////////////// 00598 bool Lens:: 00599 is_orthographic() const { 00600 return false; 00601 } 00602 00603 //////////////////////////////////////////////////////////////////// 00604 // Function: Lens::make_geometry 00605 // Access: Published, Virtual 00606 // Description: Allocates and returns a new Geom that can be rendered 00607 // to show a visible representation of the frustum used 00608 // for this kind of lens, if it makes sense to do 00609 // so. If a visible representation cannot be created, 00610 // returns NULL. 00611 //////////////////////////////////////////////////////////////////// 00612 PT(Geom) Lens:: 00613 make_geometry() { 00614 CDWriter cdata(_cycler, true); 00615 00616 // The default behavior for make_geometry() will be to draw a 00617 // hexahedron around the eight vertices of the frustum. If the lens 00618 // is non-linear, the hexahedron will be curved; in that case, we'll 00619 // subdivide the lines into several segments to get an approximation 00620 // of the curve. 00621 00622 // First, define all the points we'll use in this Geom. That's one 00623 // point at each corner of the near and far planes (and possibly 00624 // more points along the edges). 00625 int num_segments = do_define_geom_data(cdata); 00626 if (num_segments == 0) { 00627 // Can't do a frustum. 00628 cdata->_geom_data.clear(); 00629 return (Geom *)NULL; 00630 } 00631 00632 // Now string together the line segments. 00633 PT(GeomLinestrips) line = new GeomLinestrips(Geom::UH_static); 00634 00635 // Draw a frame around the near plane. 00636 int i, si; 00637 for (i = 0; i < 4; ++i) { 00638 for (si = 0; si < num_segments; ++si) { 00639 line->add_vertex(i * 2 + si * (4 * 2) + 0); 00640 } 00641 } 00642 line->add_vertex(0); 00643 line->close_primitive(); 00644 00645 // Draw a frame around the far plane. 00646 for (i = 0; i < 4; ++i) { 00647 for (si = 0; si < num_segments; ++si) { 00648 line->add_vertex(i * 2 + si * (4 * 2) + 1); 00649 } 00650 } 00651 line->add_vertex(1); 00652 line->close_primitive(); 00653 00654 // Draw connecting lines at the corners. 00655 line->add_vertex(0 * 2 + 0); 00656 line->add_vertex(0 * 2 + 1); 00657 line->close_primitive(); 00658 00659 line->add_vertex(1 * 2 + 0); 00660 line->add_vertex(1 * 2 + 1); 00661 line->close_primitive(); 00662 00663 line->add_vertex(2 * 2 + 0); 00664 line->add_vertex(2 * 2 + 1); 00665 line->close_primitive(); 00666 00667 line->add_vertex(3 * 2 + 0); 00668 line->add_vertex(3 * 2 + 1); 00669 line->close_primitive(); 00670 00671 // And one more line for the viewing axis. 00672 line->add_vertex(num_segments * (4 * 2) + 0); 00673 line->add_vertex(num_segments * (4 * 2) + 1); 00674 line->close_primitive(); 00675 00676 PT(Geom) geom = new Geom(cdata->_geom_data); 00677 geom->add_primitive(line); 00678 00679 return geom.p(); 00680 } 00681 00682 //////////////////////////////////////////////////////////////////// 00683 // Function: Lens::make_bounds 00684 // Access: Published, Virtual 00685 // Description: Allocates and returns a new BoundingVolume that 00686 // encloses the frustum used for this kind of 00687 // lens, if possible. If a suitable bounding 00688 // volume cannot be created, returns NULL. 00689 //////////////////////////////////////////////////////////////////// 00690 PT(BoundingVolume) Lens:: 00691 make_bounds() const { 00692 CDReader cdata(_cycler); 00693 00694 // The default bounding volume is a hexahedron based on the eight 00695 // corners of the frustum. 00696 LPoint3 fll, flr, ful, fur; 00697 LPoint3 nll, nlr, nul, nur; 00698 LPoint3 corner; 00699 00700 // Upper left. 00701 corner.set(-1.0f, 1.0f, 0.0f); 00702 if (!do_extrude(cdata, corner, nul, ful)) { 00703 return (BoundingVolume *)NULL; 00704 } 00705 00706 // Upper right. 00707 corner.set(1.0f, 1.0f, 0.0f); 00708 if (!do_extrude(cdata, corner, nur, fur)) { 00709 return (BoundingVolume *)NULL; 00710 } 00711 00712 // Lower right. 00713 corner.set(1.0f, -1.0f, 0.0f); 00714 if (!do_extrude(cdata, corner, nlr, flr)) { 00715 return (BoundingVolume *)NULL; 00716 } 00717 00718 // Lower left. 00719 corner.set(-1.0f, -1.0f, 0.0f); 00720 if (!do_extrude(cdata, corner, nll, fll)) { 00721 return (BoundingVolume *)NULL; 00722 } 00723 00724 return new BoundingHexahedron(fll, flr, fur, ful, nll, nlr, nur, nul); 00725 } 00726 00727 //////////////////////////////////////////////////////////////////// 00728 // Function: Lens::output 00729 // Access: Published, Virtual 00730 // Description: 00731 //////////////////////////////////////////////////////////////////// 00732 void Lens:: 00733 output(ostream &out) const { 00734 out << get_type(); 00735 } 00736 00737 //////////////////////////////////////////////////////////////////// 00738 // Function: Lens::write 00739 // Access: Published, Virtual 00740 // Description: 00741 //////////////////////////////////////////////////////////////////// 00742 void Lens:: 00743 write(ostream &out, int indent_level) const { 00744 indent(out, indent_level) << get_type() << " fov = " << get_fov() << "\n"; 00745 } 00746 00747 //////////////////////////////////////////////////////////////////// 00748 // Function: Lens::do_set_film_size 00749 // Access: Protected 00750 // Description: 00751 //////////////////////////////////////////////////////////////////// 00752 void Lens:: 00753 do_set_film_size(CData *cdata, PN_stdfloat width) { 00754 nassertv(!cnan(width)); 00755 cdata->_film_size.set(width, width / do_get_aspect_ratio(cdata)); 00756 00757 // We can't specify all three of focal length, fov, and film size. 00758 // Throw out the oldest one. 00759 do_resequence_fov_triad(cdata, cdata->_film_size_seq, cdata->_focal_length_seq, cdata->_fov_seq); 00760 00761 if (cdata->_fov_seq == 0) { 00762 // Throw out fov if it's oldest. 00763 do_adjust_user_flags(cdata, UF_hfov | UF_vfov | UF_min_fov | UF_film_height, 00764 UF_film_width); 00765 } else { 00766 // Otherwise, throw out focal length. 00767 nassertv(cdata->_focal_length_seq == 0); 00768 do_adjust_user_flags(cdata, UF_focal_length | UF_film_height, 00769 UF_film_width); 00770 } 00771 do_adjust_comp_flags(cdata, CF_mat | CF_focal_length | CF_fov, 00772 CF_film_size); 00773 do_throw_change_event(cdata); 00774 } 00775 00776 //////////////////////////////////////////////////////////////////// 00777 // Function: Lens::do_set_film_size 00778 // Access: Protected 00779 // Description: 00780 //////////////////////////////////////////////////////////////////// 00781 void Lens:: 00782 do_set_film_size(CData *cdata, const LVecBase2 &film_size) { 00783 nassertv(!film_size.is_nan()); 00784 cdata->_film_size = film_size; 00785 00786 // We can't specify all three of focal length, fov, and film size. 00787 // Throw out the oldest one. 00788 do_resequence_fov_triad(cdata, cdata->_film_size_seq, cdata->_focal_length_seq, cdata->_fov_seq); 00789 00790 if (cdata->_fov_seq == 0) { 00791 // Throw out fov if it's oldest. 00792 do_adjust_user_flags(cdata, UF_hfov | UF_vfov | UF_min_fov | UF_aspect_ratio, 00793 UF_film_width | UF_film_height); 00794 } else { 00795 // Otherwise, throw out focal length. 00796 nassertv(cdata->_focal_length_seq == 0); 00797 do_adjust_user_flags(cdata, UF_focal_length | UF_vfov | UF_aspect_ratio, 00798 UF_film_width | UF_film_height); 00799 } 00800 do_adjust_comp_flags(cdata, CF_mat | CF_focal_length | CF_fov | CF_aspect_ratio, 00801 CF_film_size); 00802 00803 // Also, the user has implicitly specified an aspect ratio. Make it 00804 // stick until the user tells us something different. 00805 do_compute_aspect_ratio(cdata); 00806 do_adjust_user_flags(cdata, 0, UF_aspect_ratio); 00807 00808 do_throw_change_event(cdata); 00809 } 00810 00811 //////////////////////////////////////////////////////////////////// 00812 // Function: Lens::do_get_film_size 00813 // Access: Protected 00814 // Description: 00815 //////////////////////////////////////////////////////////////////// 00816 const LVecBase2 &Lens:: 00817 do_get_film_size(const CData *cdata) const { 00818 if ((cdata->_comp_flags & CF_film_size) == 0) { 00819 // We pretend this is a const method, even though it may call a 00820 // non-const method to recompute the internal values. We can do 00821 // this because this is just compute-on-demand. 00822 ((Lens *)this)->do_compute_film_size((CData *)cdata); 00823 } 00824 return cdata->_film_size; 00825 } 00826 00827 //////////////////////////////////////////////////////////////////// 00828 // Function: Lens::do_set_focal_length 00829 // Access: Protected 00830 // Description: 00831 //////////////////////////////////////////////////////////////////// 00832 void Lens:: 00833 do_set_focal_length(CData *cdata, PN_stdfloat focal_length) { 00834 nassertv(!cnan(focal_length)); 00835 cdata->_focal_length = focal_length; 00836 00837 // We can't specify all three of focal length, fov, and film size. 00838 // Throw out the oldest one. 00839 do_resequence_fov_triad(cdata, cdata->_focal_length_seq, cdata->_film_size_seq, cdata->_fov_seq); 00840 00841 if (cdata->_film_size_seq == 0) { 00842 // Throw out film size if it's oldest. 00843 do_adjust_user_flags(cdata, UF_film_width | UF_film_height, 00844 UF_focal_length); 00845 } else { 00846 // Otherwise, throw out the fov. 00847 nassertv(cdata->_fov_seq == 0); 00848 do_adjust_user_flags(cdata, UF_hfov | UF_vfov | UF_min_fov, 00849 UF_focal_length); 00850 } 00851 00852 do_adjust_comp_flags(cdata, CF_mat | CF_fov | CF_film_size, 00853 CF_focal_length); 00854 do_throw_change_event(cdata); 00855 } 00856 00857 //////////////////////////////////////////////////////////////////// 00858 // Function: Lens::do_get_focal_length 00859 // Access: Protected 00860 // Description: 00861 //////////////////////////////////////////////////////////////////// 00862 PN_stdfloat Lens:: 00863 do_get_focal_length(const CData *cdata) const { 00864 if ((cdata->_comp_flags & CF_focal_length) == 0) { 00865 ((Lens *)this)->do_compute_focal_length((CData *)cdata); 00866 } 00867 return cdata->_focal_length; 00868 } 00869 00870 //////////////////////////////////////////////////////////////////// 00871 // Function: Lens::do_set_fov 00872 // Access: Protected 00873 // Description: 00874 //////////////////////////////////////////////////////////////////// 00875 void Lens:: 00876 do_set_fov(CData *cdata, PN_stdfloat hfov) { 00877 nassertv(!cnan(hfov)); 00878 cdata->_fov[0] = hfov; 00879 00880 // We can't specify all three of focal length, fov, and film size. 00881 // Throw out the oldest one. 00882 do_resequence_fov_triad(cdata, cdata->_fov_seq, cdata->_focal_length_seq, cdata->_film_size_seq); 00883 00884 if (cdata->_focal_length_seq == 0) { 00885 // Throw out focal length if it's oldest. 00886 do_adjust_user_flags(cdata, UF_focal_length | UF_vfov | UF_min_fov, 00887 UF_hfov); 00888 } else { 00889 // Otherwise, throw out film size. 00890 nassertv(cdata->_film_size_seq == 0); 00891 00892 // Make sure we save the aspect ratio first. 00893 do_compute_aspect_ratio(cdata); 00894 do_adjust_user_flags(cdata, UF_film_width | UF_film_height | UF_vfov | UF_min_fov, 00895 UF_hfov); 00896 } 00897 do_adjust_comp_flags(cdata, CF_mat | CF_focal_length | CF_fov | CF_film_size, 00898 0); 00899 // We leave CF_fov off of comp_flags, because we will still need to 00900 // recompute the vertical fov. It's not exactly the same as hfov * 00901 // get_aspect_ratio(). 00902 do_throw_change_event(cdata); 00903 } 00904 00905 //////////////////////////////////////////////////////////////////// 00906 // Function: Lens::do_set_fov 00907 // Access: Protected 00908 // Description: 00909 //////////////////////////////////////////////////////////////////// 00910 void Lens:: 00911 do_set_fov(CData *cdata, const LVecBase2 &fov) { 00912 nassertv(!fov.is_nan()); 00913 cdata->_fov = fov; 00914 00915 // We can't specify all three of focal length, fov, and film size. 00916 // Throw out the oldest one. 00917 do_resequence_fov_triad(cdata, cdata->_fov_seq, cdata->_focal_length_seq, cdata->_film_size_seq); 00918 00919 if (cdata->_focal_length_seq == 0) { 00920 // Throw out focal length if it's oldest. 00921 do_adjust_user_flags(cdata, UF_focal_length | UF_film_height | UF_min_fov | UF_aspect_ratio, 00922 UF_hfov | UF_vfov); 00923 } else { 00924 // Otherwise, throw out film size. 00925 nassertv(cdata->_film_size_seq == 0); 00926 do_adjust_user_flags(cdata, UF_film_width | UF_film_height | UF_min_fov | UF_aspect_ratio, 00927 UF_hfov | UF_vfov); 00928 } 00929 do_adjust_comp_flags(cdata, CF_mat | CF_focal_length | CF_film_size | CF_aspect_ratio, 00930 CF_fov); 00931 00932 // Also, the user has implicitly specified an aspect ratio. Make it 00933 // stick until the user tells us something different. 00934 do_compute_aspect_ratio(cdata); 00935 do_adjust_user_flags(cdata, 0, UF_aspect_ratio); 00936 00937 do_throw_change_event(cdata); 00938 } 00939 00940 //////////////////////////////////////////////////////////////////// 00941 // Function: Lens::do_get_fov 00942 // Access: Protected 00943 // Description: 00944 //////////////////////////////////////////////////////////////////// 00945 const LVecBase2 &Lens:: 00946 do_get_fov(const CData *cdata) const { 00947 if ((cdata->_comp_flags & CF_fov) == 0) { 00948 ((Lens *)this)->do_compute_fov((CData *)cdata); 00949 } 00950 return cdata->_fov; 00951 } 00952 00953 //////////////////////////////////////////////////////////////////// 00954 // Function: Lens::do_set_aspect_ratio 00955 // Access: Protected 00956 // Description: 00957 //////////////////////////////////////////////////////////////////// 00958 void Lens:: 00959 do_set_aspect_ratio(CData *cdata, PN_stdfloat aspect_ratio) { 00960 nassertv(!cnan(aspect_ratio)); 00961 cdata->_aspect_ratio = aspect_ratio; 00962 do_adjust_user_flags(cdata, UF_film_height | UF_vfov, 00963 UF_aspect_ratio); 00964 do_adjust_comp_flags(cdata, CF_mat | CF_film_size | CF_fov | CF_focal_length, 00965 CF_aspect_ratio); 00966 do_throw_change_event(cdata); 00967 } 00968 00969 //////////////////////////////////////////////////////////////////// 00970 // Function: Lens::do_get_aspect_ratio 00971 // Access: Protected 00972 // Description: 00973 //////////////////////////////////////////////////////////////////// 00974 PN_stdfloat Lens:: 00975 do_get_aspect_ratio(const CData *cdata) const { 00976 if ((cdata->_comp_flags & CF_aspect_ratio) == 0) { 00977 ((Lens *)this)->do_compute_aspect_ratio((CData *)cdata); 00978 } 00979 return cdata->_aspect_ratio; 00980 } 00981 00982 //////////////////////////////////////////////////////////////////// 00983 // Function: Lens::do_get_projection_mat 00984 // Access: Protected 00985 // Description: 00986 //////////////////////////////////////////////////////////////////// 00987 const LMatrix4 &Lens:: 00988 do_get_projection_mat(const CData *cdata, StereoChannel channel) const { 00989 if ((cdata->_comp_flags & CF_projection_mat) == 0) { 00990 ((Lens *)this)->do_compute_projection_mat((CData *)cdata); 00991 } 00992 00993 switch (channel) { 00994 case SC_left: 00995 return cdata->_projection_mat_left; 00996 case SC_right: 00997 return cdata->_projection_mat_right; 00998 case SC_mono: 00999 case SC_stereo: 01000 return cdata->_projection_mat; 01001 } 01002 01003 return cdata->_projection_mat; 01004 } 01005 01006 //////////////////////////////////////////////////////////////////// 01007 // Function: Lens::do_get_projection_mat_inv 01008 // Access: Protected 01009 // Description: 01010 //////////////////////////////////////////////////////////////////// 01011 const LMatrix4 &Lens:: 01012 do_get_projection_mat_inv(const CData *cdata, StereoChannel stereo_channel) const { 01013 switch (stereo_channel) { 01014 case SC_left: 01015 { 01016 if ((cdata->_comp_flags & CF_projection_mat_left_inv) == 0) { 01017 const LMatrix4 &projection_mat_left = do_get_projection_mat(cdata, SC_left); 01018 ((CData *)cdata)->_projection_mat_left_inv.invert_from(projection_mat_left); 01019 ((Lens *)this)->do_adjust_comp_flags((CData *)cdata, 0, CF_projection_mat_left_inv); 01020 } 01021 } 01022 return cdata->_projection_mat_left_inv; 01023 01024 case SC_right: 01025 { 01026 if ((cdata->_comp_flags & CF_projection_mat_right_inv) == 0) { 01027 const LMatrix4 &projection_mat_right = do_get_projection_mat(cdata, SC_right); 01028 ((CData *)cdata)->_projection_mat_right_inv.invert_from(projection_mat_right); 01029 ((Lens *)this)->do_adjust_comp_flags((CData *)cdata, 0, CF_projection_mat_right_inv); 01030 } 01031 } 01032 return cdata->_projection_mat_right_inv; 01033 01034 case SC_mono: 01035 case SC_stereo: 01036 break; 01037 } 01038 01039 if ((cdata->_comp_flags & CF_projection_mat_inv) == 0) { 01040 const LMatrix4 &projection_mat = do_get_projection_mat(cdata); 01041 ((CData *)cdata)->_projection_mat_inv.invert_from(projection_mat); 01042 ((Lens *)this)->do_adjust_comp_flags((CData *)cdata, 0, CF_projection_mat_inv); 01043 } 01044 return cdata->_projection_mat_inv; 01045 } 01046 01047 //////////////////////////////////////////////////////////////////// 01048 // Function: Lens::do_get_film_mat 01049 // Access: Protected 01050 // Description: 01051 //////////////////////////////////////////////////////////////////// 01052 const LMatrix4 &Lens:: 01053 do_get_film_mat(const CData *cdata) const { 01054 if ((cdata->_comp_flags & CF_film_mat) == 0) { 01055 ((Lens *)this)->do_compute_film_mat((CData *)cdata); 01056 } 01057 return cdata->_film_mat; 01058 } 01059 01060 //////////////////////////////////////////////////////////////////// 01061 // Function: Lens::do_get_film_mat_inv 01062 // Access: Protected 01063 // Description: 01064 //////////////////////////////////////////////////////////////////// 01065 const LMatrix4 &Lens:: 01066 do_get_film_mat_inv(const CData *cdata) const { 01067 if ((cdata->_comp_flags & CF_film_mat_inv) == 0) { 01068 const LMatrix4 &film_mat = do_get_film_mat(cdata); 01069 ((CData *)cdata)->_film_mat_inv.invert_from(film_mat); 01070 ((Lens *)this)->do_adjust_comp_flags((CData *)cdata, 0, CF_film_mat_inv); 01071 } 01072 return cdata->_film_mat_inv; 01073 } 01074 01075 //////////////////////////////////////////////////////////////////// 01076 // Function: Lens::do_get_lens_mat 01077 // Access: Protected 01078 // Description: 01079 //////////////////////////////////////////////////////////////////// 01080 const LMatrix4 &Lens:: 01081 do_get_lens_mat(const CData *cdata) const { 01082 if ((cdata->_comp_flags & CF_lens_mat) == 0) { 01083 ((Lens *)this)->do_compute_lens_mat((CData *)cdata); 01084 } 01085 return cdata->_lens_mat; 01086 } 01087 01088 //////////////////////////////////////////////////////////////////// 01089 // Function: Lens::do_get_lens_mat_inv 01090 // Access: Protected 01091 // Description: 01092 //////////////////////////////////////////////////////////////////// 01093 const LMatrix4 &Lens:: 01094 do_get_lens_mat_inv(const CData *cdata) const { 01095 if ((cdata->_comp_flags & CF_lens_mat_inv) == 0) { 01096 const LMatrix4 &lens_mat = do_get_lens_mat(cdata); 01097 ((CData *)cdata)->_lens_mat_inv.invert_from(lens_mat); 01098 ((Lens *)this)->do_adjust_comp_flags((CData *)cdata, 0, CF_lens_mat_inv); 01099 } 01100 return cdata->_lens_mat_inv; 01101 } 01102 01103 //////////////////////////////////////////////////////////////////// 01104 // Function: Lens::do_set_interocular_distance 01105 // Access: Protected 01106 // Description: 01107 //////////////////////////////////////////////////////////////////// 01108 void Lens:: 01109 do_set_interocular_distance(CData *cdata, PN_stdfloat interocular_distance) { 01110 nassertv(!cnan(interocular_distance)); 01111 cdata->_interocular_distance = interocular_distance; 01112 if (cdata->_interocular_distance == 0.0f) { 01113 do_adjust_user_flags(cdata, UF_interocular_distance, 0); 01114 } else { 01115 do_adjust_user_flags(cdata, 0, UF_interocular_distance); 01116 } 01117 01118 do_adjust_comp_flags(cdata, CF_mat, 0); 01119 } 01120 01121 //////////////////////////////////////////////////////////////////// 01122 // Function: Lens::do_set_convergence_distance 01123 // Access: Protected 01124 // Description: 01125 //////////////////////////////////////////////////////////////////// 01126 void Lens:: 01127 do_set_convergence_distance(CData *cdata, PN_stdfloat convergence_distance) { 01128 nassertv(!cnan(convergence_distance)); 01129 cdata->_convergence_distance = convergence_distance; 01130 if (cdata->_convergence_distance == 0.0f) { 01131 do_adjust_user_flags(cdata, UF_convergence_distance, 0); 01132 } else { 01133 do_adjust_user_flags(cdata, 0, UF_convergence_distance); 01134 } 01135 01136 do_adjust_comp_flags(cdata, CF_mat, 0); 01137 } 01138 01139 //////////////////////////////////////////////////////////////////// 01140 // Function: Lens::do_set_view_mat 01141 // Access: Protected 01142 // Description: 01143 //////////////////////////////////////////////////////////////////// 01144 void Lens:: 01145 do_set_view_mat(CData *cdata, const LMatrix4 &view_mat) { 01146 nassertv(!view_mat.is_nan()); 01147 cdata->_lens_mat = view_mat; 01148 do_adjust_user_flags(cdata, UF_view_vector | UF_view_hpr, 01149 UF_view_mat); 01150 do_adjust_comp_flags(cdata, CF_projection_mat | CF_projection_mat_inv | 01151 CF_projection_mat_left_inv | CF_projection_mat_right_inv | 01152 CF_lens_mat_inv | CF_view_hpr | CF_view_vector, 01153 CF_lens_mat); 01154 do_throw_change_event(cdata); 01155 } 01156 01157 //////////////////////////////////////////////////////////////////// 01158 // Function: Lens::do_get_view_mat 01159 // Access: Protected 01160 // Description: 01161 //////////////////////////////////////////////////////////////////// 01162 const LMatrix4 &Lens:: 01163 do_get_view_mat(const CData *cdata) const { 01164 if ((cdata->_comp_flags & CF_lens_mat) == 0) { 01165 ((Lens *)this)->do_compute_lens_mat((CData *)cdata); 01166 } 01167 return cdata->_lens_mat; 01168 } 01169 01170 //////////////////////////////////////////////////////////////////// 01171 // Function: Lens::do_throw_change_event 01172 // Access: Protected 01173 // Description: Throws the event associated with changing properties 01174 // on this Lens, if any. 01175 //////////////////////////////////////////////////////////////////// 01176 void Lens:: 01177 do_throw_change_event(CData *cdata) { 01178 ++(cdata->_last_change); 01179 01180 if (!cdata->_change_event.empty()) { 01181 throw_event(cdata->_change_event, this); 01182 } 01183 01184 if (!cdata->_geom_data.is_null()) { 01185 if (cdata->_geom_data->get_ref_count() == 1) { 01186 // No one's using the data any more (there are no references to 01187 // it other than this one), so don't bother to recompute it; 01188 // just release it. 01189 cdata->_geom_data.clear(); 01190 } else { 01191 // Someone still has a handle to the data, so recompute it for 01192 // them. 01193 do_define_geom_data(cdata); 01194 } 01195 } 01196 } 01197 01198 //////////////////////////////////////////////////////////////////// 01199 // Function: Lens::do_extrude 01200 // Access: Protected, Virtual 01201 // Description: Given a 2-d point in the range (-1,1) in both 01202 // dimensions, where (0,0) is the center of the 01203 // lens and (-1,-1) is the lower-left corner, 01204 // compute the corresponding vector in space that maps 01205 // to this point, if such a vector can be determined. 01206 // The vector is returned by indicating the points on 01207 // the near plane and far plane that both map to the 01208 // indicated 2-d point. 01209 // 01210 // The z coordinate of the 2-d point is ignored. 01211 // 01212 // Returns true if the vector is defined, or false 01213 // otherwise. 01214 //////////////////////////////////////////////////////////////////// 01215 bool Lens:: 01216 do_extrude(const CData *cdata, 01217 const LPoint3 &point2d, LPoint3 &near_point, LPoint3 &far_point) const { 01218 const LMatrix4 &projection_mat_inv = do_get_projection_mat_inv(cdata); 01219 { 01220 LVecBase4 full(point2d[0], point2d[1], -1.0f, 1.0f); 01221 full = projection_mat_inv.xform(full); 01222 01223 PN_stdfloat recip_full3 = 1.0 / max((double)full[3], (double)lens_far_limit); 01224 near_point.set(full[0] * recip_full3, 01225 full[1] * recip_full3, 01226 full[2] * recip_full3); 01227 } 01228 { 01229 LVecBase4 full(point2d[0], point2d[1], 1.0f, 1.0f); 01230 full = projection_mat_inv.xform(full); 01231 01232 // We can truncate the weight factor at near 0. If it goes too 01233 // close to zero, or becomes negative, the far plane moves out 01234 // past infinity and comes back in behind the lens, which is just 01235 // crazy. Truncating it to zero keeps the far plane from moving 01236 // too far out. 01237 PN_stdfloat recip_full3 = 1.0 / max((double)full[3], (double)lens_far_limit); 01238 far_point.set(full[0] * recip_full3, 01239 full[1] * recip_full3, 01240 full[2] * recip_full3); 01241 } 01242 return true; 01243 } 01244 01245 //////////////////////////////////////////////////////////////////// 01246 // Function: Lens::do_extrude_vec 01247 // Access: Protected, Virtual 01248 // Description: Given a 2-d point in the range (-1,1) in both 01249 // dimensions, where (0,0) is the center of the 01250 // lens and (-1,-1) is the lower-left corner, 01251 // compute the vector that corresponds to the view 01252 // direction. This will be parallel to the normal on 01253 // the surface (the far plane) corresponding to the lens 01254 // shape at this point. 01255 // 01256 // Generally, for all rational lenses, the center of the 01257 // film at (0,0) computes a vector that is in the same 01258 // direction as the vector specified by 01259 // set_view_vector(). 01260 // 01261 // For all linear lenses, including perspective and 01262 // orthographic lenses, all points on the film compute 01263 // this same vector (the far plane is a flat plane, so 01264 // the normal is the same everywhere). For curved 01265 // lenses like fisheye and cylindrical lenses, different 01266 // points may compute different vectors (the far "plane" 01267 // on these lenses is a curved surface). 01268 // 01269 // The z coordinate of the 2-d point is ignored. 01270 // 01271 // Returns true if the vector is defined, or false 01272 // otherwise. 01273 //////////////////////////////////////////////////////////////////// 01274 bool Lens:: 01275 do_extrude_vec(const CData *cdata, const LPoint3 &point2d, LVector3 &vec) const { 01276 vec = LVector3::forward(cdata->_cs) * do_get_lens_mat(cdata); 01277 return true; 01278 } 01279 01280 //////////////////////////////////////////////////////////////////// 01281 // Function: Lens::do_project 01282 // Access: Protected, Virtual 01283 // Description: Given a 3-d point in space, determine the 2-d point 01284 // this maps to, in the range (-1,1) in both dimensions, 01285 // where (0,0) is the center of the lens and 01286 // (-1,-1) is the lower-left corner. 01287 // 01288 // The z coordinate will also be set to a value in the 01289 // range (-1, 1), where 1 represents a point on the near 01290 // plane, and -1 represents a point on the far plane. 01291 // 01292 // Returns true if the 3-d point is in front of the lens 01293 // and within the viewing frustum (in which case point2d 01294 // is filled in), or false otherwise (in which case 01295 // point2d will be filled in with something, which may 01296 // or may not be meaningful). 01297 //////////////////////////////////////////////////////////////////// 01298 bool Lens:: 01299 do_project(const CData *cdata, const LPoint3 &point3d, LPoint3 &point2d) const { 01300 const LMatrix4 &projection_mat = do_get_projection_mat(cdata); 01301 LVecBase4 full(point3d[0], point3d[1], point3d[2], 1.0f); 01302 full = projection_mat.xform(full); 01303 if (full[3] == 0.0f) { 01304 point2d.set(0.0f, 0.0f, 0.0f); 01305 return false; 01306 } 01307 PN_stdfloat recip_full3 = 1.0f/full[3]; 01308 point2d.set(full[0] * recip_full3, full[1] * recip_full3, full[2] * recip_full3); 01309 return 01310 (full[3] > 0.0f) && 01311 (point2d[0] >= -1.0f) && (point2d[0] <= 1.0f) && 01312 (point2d[1] >= -1.0f) && (point2d[1] <= 1.0f); 01313 } 01314 01315 //////////////////////////////////////////////////////////////////// 01316 // Function: Lens::do_compute_film_size 01317 // Access: Protected, Virtual 01318 // Description: Computes the size and shape of the film behind the 01319 // camera, based on the aspect ratio and fov. 01320 //////////////////////////////////////////////////////////////////// 01321 void Lens:: 01322 do_compute_film_size(CData *cdata) { 01323 if ((cdata->_user_flags & (UF_min_fov | UF_focal_length)) == (UF_min_fov | UF_focal_length)) { 01324 // If we just have a min FOV and a focal length, that determines 01325 // the smaller of the two film_sizes, and the larger is simply 01326 // chosen according to the aspect ratio. 01327 PN_stdfloat fs = fov_to_film(cdata->_min_fov, cdata->_focal_length, true); 01328 nassertv((cdata->_user_flags & UF_aspect_ratio) != 0 || 01329 (cdata->_comp_flags & CF_aspect_ratio) != 0); 01330 01331 if (cdata->_aspect_ratio < 1.0f) { 01332 cdata->_film_size[1] = fs / cdata->_aspect_ratio; 01333 cdata->_film_size[0] = fs; 01334 01335 } else { 01336 cdata->_film_size[0] = fs * cdata->_aspect_ratio; 01337 cdata->_film_size[1] = fs; 01338 } 01339 01340 } else { 01341 if ((cdata->_user_flags & UF_film_width) == 0) { 01342 if ((cdata->_user_flags & (UF_hfov | UF_focal_length)) == (UF_hfov | UF_focal_length)) { 01343 cdata->_film_size[0] = fov_to_film(cdata->_fov[0], cdata->_focal_length, true); 01344 } else { 01345 cdata->_film_size[0] = 1.0f; 01346 } 01347 } 01348 01349 if ((cdata->_user_flags & UF_film_height) == 0) { 01350 if ((cdata->_user_flags & (UF_vfov | UF_focal_length)) == (UF_vfov | UF_focal_length)) { 01351 cdata->_film_size[1] = fov_to_film(cdata->_fov[1], cdata->_focal_length, false); 01352 01353 } else if ((cdata->_user_flags & (UF_hfov | UF_vfov)) == (UF_hfov | UF_vfov)) { 01354 // If we don't have a focal length, but we have an explicit vfov 01355 // and hfov, we can infer the focal length is whatever makes the 01356 // film width, above, be what it is. 01357 if ((cdata->_comp_flags & CF_focal_length) == 0) { 01358 cdata->_focal_length = fov_to_focal_length(cdata->_fov[0], cdata->_film_size[0], true); 01359 do_adjust_comp_flags(cdata, 0, CF_focal_length); 01360 } 01361 cdata->_film_size[1] = fov_to_film(cdata->_fov[1], cdata->_focal_length, false); 01362 01363 } else if ((cdata->_user_flags & UF_aspect_ratio) != 0 || 01364 (cdata->_comp_flags & CF_aspect_ratio) != 0) { 01365 cdata->_film_size[1] = cdata->_film_size[0] / cdata->_aspect_ratio; 01366 01367 } else { 01368 // Default is an aspect ratio of 1. 01369 cdata->_film_size[1] = cdata->_film_size[0]; 01370 } 01371 } 01372 } 01373 01374 do_adjust_comp_flags(cdata, 0, CF_film_size); 01375 } 01376 01377 //////////////////////////////////////////////////////////////////// 01378 // Function: Lens::do_compute_focal_length 01379 // Access: Protected, Virtual 01380 // Description: Computes the focal length of the lens, based on the 01381 // fov and film size. This is based on the horizontal 01382 // dimension. 01383 //////////////////////////////////////////////////////////////////// 01384 void Lens:: 01385 do_compute_focal_length(CData *cdata) { 01386 if ((cdata->_user_flags & UF_focal_length) == 0) { 01387 const LVecBase2 &film_size = do_get_film_size(cdata); 01388 const LVecBase2 &fov = do_get_fov(cdata); 01389 cdata->_focal_length = fov_to_focal_length(fov[0], film_size[0], true); 01390 } 01391 01392 do_adjust_comp_flags(cdata, 0, CF_focal_length); 01393 } 01394 01395 //////////////////////////////////////////////////////////////////// 01396 // Function: Lens::do_compute_fov 01397 // Access: Protected, Virtual 01398 // Description: Computes the field of view of the lens, based on the 01399 // film size and focal length. 01400 //////////////////////////////////////////////////////////////////// 01401 void Lens:: 01402 do_compute_fov(CData *cdata) { 01403 const LVecBase2 &film_size = do_get_film_size(cdata); 01404 01405 bool got_hfov = ((cdata->_user_flags & UF_hfov) != 0); 01406 bool got_vfov = ((cdata->_user_flags & UF_vfov) != 0); 01407 bool got_min_fov = ((cdata->_user_flags & UF_min_fov) != 0); 01408 01409 if (!got_hfov && !got_vfov && !got_min_fov) { 01410 // If the user hasn't specified any FOV, we have to compute it. 01411 if ((cdata->_user_flags & UF_focal_length) != 0) { 01412 // The FOV is determined from the film size and focal length. 01413 cdata->_fov[0] = film_to_fov(film_size[0], cdata->_focal_length, true); 01414 cdata->_fov[1] = film_to_fov(film_size[1], cdata->_focal_length, true); 01415 got_hfov = true; 01416 got_vfov = true; 01417 01418 } else { 01419 // We can't compute the FOV; take the default. 01420 cdata->_min_fov = default_fov; 01421 got_min_fov = true; 01422 } 01423 } 01424 01425 if (got_min_fov) { 01426 // If we have just a min_fov, use it to derive whichever fov is 01427 // smaller. 01428 if (film_size[0] < film_size[1]) { 01429 cdata->_fov[0] = cdata->_min_fov; 01430 got_hfov = true; 01431 } else { 01432 cdata->_fov[1] = cdata->_min_fov; 01433 got_vfov = true; 01434 } 01435 } 01436 01437 // Now compute whichever fov is remaining. 01438 if (!got_hfov) { 01439 if ((cdata->_user_flags & UF_focal_length) == 0 && 01440 (cdata->_comp_flags & CF_focal_length) == 0) { 01441 // If we don't have an explicit focal length, we can infer it 01442 // from the above. 01443 nassertv(got_vfov); 01444 cdata->_focal_length = fov_to_focal_length(cdata->_fov[1], film_size[1], true); 01445 do_adjust_comp_flags(cdata, 0, CF_focal_length); 01446 } 01447 cdata->_fov[0] = film_to_fov(film_size[0], cdata->_focal_length, false); 01448 got_hfov = true; 01449 } 01450 01451 if (!got_vfov) { 01452 if ((cdata->_user_flags & UF_focal_length) == 0 && 01453 (cdata->_comp_flags & CF_focal_length) == 0) { 01454 // If we don't have an explicit focal length, we can infer it 01455 // from the above. 01456 nassertv(got_hfov); 01457 cdata->_focal_length = fov_to_focal_length(cdata->_fov[0], film_size[0], true); 01458 do_adjust_comp_flags(cdata, 0, CF_focal_length); 01459 } 01460 cdata->_fov[1] = film_to_fov(film_size[1], cdata->_focal_length, false); 01461 got_vfov = true; 01462 } 01463 01464 if (!got_min_fov) { 01465 cdata->_min_fov = film_size[0] < film_size[1] ? cdata->_fov[0] : cdata->_fov[1]; 01466 got_min_fov = true; 01467 } 01468 01469 nassertv(got_hfov && got_vfov && got_min_fov); 01470 do_adjust_comp_flags(cdata, 0, CF_fov); 01471 } 01472 01473 //////////////////////////////////////////////////////////////////// 01474 // Function: Lens::do_compute_aspect_ratio 01475 // Access: Protected, Virtual 01476 // Description: Computes the aspect ratio of the film rectangle, as a 01477 // ratio of width to height. 01478 //////////////////////////////////////////////////////////////////// 01479 void Lens:: 01480 do_compute_aspect_ratio(CData *cdata) { 01481 if ((cdata->_user_flags & UF_aspect_ratio) == 0) { 01482 const LVecBase2 &film_size = do_get_film_size(cdata); 01483 if (film_size[1] == 0.0f) { 01484 cdata->_aspect_ratio = 1.0f; 01485 } else { 01486 cdata->_aspect_ratio = film_size[0] / film_size[1]; 01487 } 01488 } 01489 do_adjust_comp_flags(cdata, 0, CF_aspect_ratio); 01490 } 01491 01492 //////////////////////////////////////////////////////////////////// 01493 // Function: Lens::do_compute_view_hpr 01494 // Access: Protected, Virtual 01495 // Description: Computes the Euler angles representing the lens' 01496 // rotation. 01497 //////////////////////////////////////////////////////////////////// 01498 void Lens:: 01499 do_compute_view_hpr(CData *cdata) { 01500 if ((cdata->_user_flags & UF_view_hpr) == 0) { 01501 const LMatrix4 &view_mat = do_get_view_mat(cdata); 01502 LVecBase3 scale, shear, translate; 01503 decompose_matrix(view_mat, scale, shear, cdata->_view_hpr, translate, cdata->_cs); 01504 } 01505 do_adjust_comp_flags(cdata, 0, CF_view_hpr); 01506 } 01507 01508 //////////////////////////////////////////////////////////////////// 01509 // Function: Lens::do_compute_view_vector 01510 // Access: Protected, Virtual 01511 // Description: Computes the view vector and up vector for the lens. 01512 //////////////////////////////////////////////////////////////////// 01513 void Lens:: 01514 do_compute_view_vector(CData *cdata) { 01515 if ((cdata->_user_flags & UF_view_vector) == 0) { 01516 const LMatrix4 &view_mat = do_get_view_mat(cdata); 01517 cdata->_view_vector = LVector3::forward(cdata->_cs) * view_mat; 01518 cdata->_up_vector = LVector3::up(cdata->_cs) * view_mat; 01519 } 01520 do_adjust_comp_flags(cdata, 0, CF_view_vector); 01521 } 01522 01523 //////////////////////////////////////////////////////////////////// 01524 // Function: Lens::do_compute_projection_mat 01525 // Access: Protected, Virtual 01526 // Description: Computes the complete transformation matrix from 3-d 01527 // point to 2-d point, if the lens is linear. 01528 //////////////////////////////////////////////////////////////////// 01529 void Lens:: 01530 do_compute_projection_mat(CData *cdata) { 01531 cdata->_projection_mat = 01532 cdata->_projection_mat_left = 01533 cdata->_projection_mat_right = 01534 cdata->_projection_mat_inv = 01535 cdata->_projection_mat_left_inv = 01536 cdata->_projection_mat_right_inv = 01537 LMatrix4::ident_mat(); 01538 do_adjust_comp_flags(cdata, 0, CF_projection_mat | CF_projection_mat_inv | 01539 CF_projection_mat_left_inv |CF_projection_mat_right_inv); 01540 } 01541 01542 //////////////////////////////////////////////////////////////////// 01543 // Function: Lens::do_compute_film_mat 01544 // Access: Protected, Virtual 01545 // Description: Computes the matrix that transforms from a point 01546 // behind the lens to a point on the film. 01547 //////////////////////////////////////////////////////////////////// 01548 void Lens:: 01549 do_compute_film_mat(CData *cdata) { 01550 // The lens will return a point in the range [-film_size/2, 01551 // film_size/2] in each dimension. Convert this to [-1, 1], and 01552 // also apply the offset. 01553 01554 // We declare these two as local variables, instead of references, 01555 // to work around a VC7 compiler bug. 01556 LVecBase2 film_size = do_get_film_size(cdata); 01557 LVector2 film_offset = do_get_film_offset(cdata); 01558 01559 PN_stdfloat scale_x = 2.0f / film_size[0]; 01560 PN_stdfloat scale_y = 2.0f / film_size[1]; 01561 cdata->_film_mat.set(scale_x, 0.0f, 0.0f, 0.0f, 01562 0.0f, scale_y, 0.0f, 0.0f, 01563 0.0f, 0.0f, 1.0f, 0.0f, 01564 -film_offset[0] * scale_x, -film_offset[1] * scale_y, 0.0f, 1.0f); 01565 01566 if ((cdata->_user_flags & UF_keystone) != 0) { 01567 cdata->_film_mat = LMatrix4(1.0f, 0.0f, cdata->_keystone[0], cdata->_keystone[0], 01568 0.0f, 1.0f, cdata->_keystone[1], cdata->_keystone[1], 01569 0.0f, 0.0f, 1.0f, 0.0f, 01570 0.0f, 0.0f, 0.0f, 1.0f) * cdata->_film_mat; 01571 } 01572 01573 do_adjust_comp_flags(cdata, CF_film_mat_inv, CF_film_mat); 01574 } 01575 01576 //////////////////////////////////////////////////////////////////// 01577 // Function: Lens::do_compute_lens_mat 01578 // Access: Protected, Virtual 01579 // Description: Computes the matrix that transforms from a point 01580 // in front of the lens to a point in space. 01581 //////////////////////////////////////////////////////////////////// 01582 void Lens:: 01583 do_compute_lens_mat(CData *cdata) { 01584 if ((cdata->_user_flags & UF_view_mat) == 0) { 01585 if ((cdata->_user_flags & UF_view_hpr) != 0) { 01586 compose_matrix(cdata->_lens_mat, 01587 LVecBase3(1.0f, 1.0f, 1.0f), 01588 LVecBase3(0.0f, 0.0f, 0.0f), 01589 cdata->_view_hpr, 01590 LVecBase3(0.0f, 0.0f, 0.0f), cdata->_cs); 01591 01592 } else if ((cdata->_user_flags & UF_view_vector) != 0) { 01593 look_at(cdata->_lens_mat, cdata->_view_vector, cdata->_up_vector, cdata->_cs); 01594 01595 } else { 01596 cdata->_lens_mat = LMatrix4::ident_mat(); 01597 } 01598 } 01599 do_adjust_comp_flags(cdata, CF_lens_mat_inv, CF_lens_mat); 01600 } 01601 01602 //////////////////////////////////////////////////////////////////// 01603 // Function: Lens::fov_to_film 01604 // Access: Protected, Virtual 01605 // Description: Given a field of view in degrees and a focal length, 01606 // compute the corresponding width (or height) on the 01607 // film. If horiz is true, this is in the horizontal 01608 // direction; otherwise, it is in the vertical direction 01609 // (some lenses behave differently in each direction). 01610 //////////////////////////////////////////////////////////////////// 01611 PN_stdfloat Lens:: 01612 fov_to_film(PN_stdfloat, PN_stdfloat, bool) const { 01613 return 1.0f; 01614 } 01615 01616 //////////////////////////////////////////////////////////////////// 01617 // Function: Lens::fov_to_focal_length 01618 // Access: Protected, Virtual 01619 // Description: Given a field of view in degrees and a width (or 01620 // height) on the film, compute the focal length of the 01621 // lens. If horiz is true, this is in the horizontal 01622 // direction; otherwise, it is in the vertical direction 01623 // (some lenses behave differently in each direction). 01624 //////////////////////////////////////////////////////////////////// 01625 PN_stdfloat Lens:: 01626 fov_to_focal_length(PN_stdfloat, PN_stdfloat, bool) const { 01627 return 1.0f; 01628 } 01629 01630 //////////////////////////////////////////////////////////////////// 01631 // Function: Lens::film_to_fov 01632 // Access: Protected, Virtual 01633 // Description: Given a width (or height) on the film and a focal 01634 // length, compute the field of view in degrees. If 01635 // horiz is true, this is in the horizontal direction; 01636 // otherwise, it is in the vertical direction (some 01637 // lenses behave differently in each direction). 01638 //////////////////////////////////////////////////////////////////// 01639 PN_stdfloat Lens:: 01640 film_to_fov(PN_stdfloat, PN_stdfloat, bool) const { 01641 return default_fov; 01642 } 01643 01644 //////////////////////////////////////////////////////////////////// 01645 // Function: Lens::do_resequence_fov_triad 01646 // Access: Private 01647 // Description: Called whenever the user changes one of the three FOV 01648 // parameters: fov, focal length, or film size. This 01649 // rearranges the three sequence numbers so the newest 01650 // parameter has value 2, and the older parameters are 01651 // kept in sequence order. 01652 // 01653 // This is used to determine which two parameters of the 01654 // three are the most recently changed, and conversely, 01655 // which one the user has *not* changed recently. It is 01656 // this third value which should be discarded. 01657 //////////////////////////////////////////////////////////////////// 01658 void Lens:: 01659 do_resequence_fov_triad(const CData *cdata, char &newest, char &older_a, char &older_b) const { 01660 nassertv(newest + older_a + older_b == 3); 01661 switch (newest) { 01662 case 0: 01663 newest = 2; 01664 older_a--; 01665 older_b--; 01666 nassertv(older_a + older_b == 1); 01667 break; 01668 01669 case 1: 01670 newest = 2; 01671 if (older_a == 2) { 01672 nassertv(older_b == 0); 01673 older_a = 1; 01674 } else { 01675 nassertv(older_a == 0 && older_b == 2); 01676 older_b = 1; 01677 } 01678 break; 01679 01680 case 2: 01681 nassertv(older_a + older_b == 1); 01682 break; 01683 01684 default: 01685 gobj_cat.error() 01686 << "Invalid fov sequence numbers in lens: " 01687 << (int)newest << ", " << (int)older_a << ", " << (int)older_b << "\n"; 01688 nassertv(false); 01689 return; 01690 } 01691 01692 if (gobj_cat.is_debug()) { 01693 gobj_cat.debug() 01694 << "Lens.do_resequence_fov_triad():"; 01695 for (int i = 2; i >= 0; --i) { 01696 if (cdata->_fov_seq == i) { 01697 gobj_cat.debug(false) 01698 << " fov"; 01699 } else if (cdata->_focal_length_seq == i) { 01700 gobj_cat.debug(false) 01701 << " focal_length"; 01702 } else if (cdata->_film_size_seq == i) { 01703 gobj_cat.debug(false) 01704 << " film_size"; 01705 } 01706 } 01707 gobj_cat.debug(false) 01708 << "\n"; 01709 } 01710 } 01711 01712 //////////////////////////////////////////////////////////////////// 01713 // Function: Lens::do_define_geom_data 01714 // Access: Private 01715 // Description: Adjusts (or defines for the first time) all the 01716 // vertices in the _geom_data to match the properties of 01717 // the lens. This will update the visual representation 01718 // of the lens's frustum to match the changing 01719 // parameters. Returns the number of line segments per 01720 // edge. 01721 //////////////////////////////////////////////////////////////////// 01722 int Lens:: 01723 do_define_geom_data(CData *cdata) { 01724 int num_segments = 1; 01725 if (!is_linear()) { 01726 num_segments = lens_geom_segments; 01727 } 01728 01729 if (cdata->_geom_data == (GeomVertexData *)NULL) { 01730 cdata->_geom_data = new GeomVertexData 01731 ("lens", GeomVertexFormat::get_v3(), 01732 Geom::UH_dynamic); 01733 } 01734 01735 GeomVertexWriter vertex(cdata->_geom_data, InternalName::get_vertex()); 01736 LPoint3 near_point, far_point; 01737 for (int si = 0; si < num_segments; si++) { 01738 PN_stdfloat t = 2.0f * (PN_stdfloat)si / (PN_stdfloat)num_segments; 01739 01740 // Upper left, top edge. 01741 LPoint2 p1(-1.0f + t, 1.0f); 01742 if (!extrude(p1, near_point, far_point)) { 01743 // Hey, this point is off the lens! Can't do a frustum. 01744 return 0; 01745 } 01746 vertex.add_data3(near_point); 01747 vertex.add_data3(far_point); 01748 01749 // Upper right, right edge. 01750 LPoint2 p2(1.0f, 1.0f - t); 01751 if (!extrude(p2, near_point, far_point)) { 01752 // Hey, this point is off the lens! Can't do a frustum. 01753 return 0; 01754 } 01755 vertex.add_data3(near_point); 01756 vertex.add_data3(far_point); 01757 01758 // Lower right, bottom edge. 01759 LPoint2 p3(1.0f - t, -1.0f); 01760 if (!extrude(p3, near_point, far_point)) { 01761 // Hey, this point is off the lens! Can't do a frustum. 01762 return 0; 01763 } 01764 vertex.add_data3(near_point); 01765 vertex.add_data3(far_point); 01766 01767 // Lower left, left edge. 01768 LPoint2 p4(-1.0f, -1.0f + t); 01769 if (!extrude(p4, near_point, far_point)) { 01770 // Hey, this point is off the lens! Can't do a frustum. 01771 return 0; 01772 } 01773 vertex.add_data3(near_point); 01774 vertex.add_data3(far_point); 01775 } 01776 01777 // Finally, add one more pair for the viewing axis. 01778 LPoint3 near_axis = LPoint3::origin(cdata->_cs) + LVector3::forward(cdata->_cs) * cdata->_near_distance; 01779 LPoint3 far_axis = LPoint3::origin(cdata->_cs) + LVector3::forward(cdata->_cs) * cdata->_far_distance; 01780 const LMatrix4 &lens_mat = do_get_lens_mat(cdata); 01781 near_axis = near_axis * lens_mat; 01782 far_axis = far_axis * lens_mat; 01783 vertex.add_data3(near_axis); 01784 vertex.add_data3(far_axis); 01785 01786 return num_segments; 01787 } 01788 01789 //////////////////////////////////////////////////////////////////// 01790 // Function: Lens::build_shear_mat 01791 // Access: Private, Static 01792 // Description: A support function for set_frustum_from_corners(), 01793 // this computes a matrix that will shear the four 01794 // indicated points to the most nearly rectangular. 01795 //////////////////////////////////////////////////////////////////// 01796 void Lens:: 01797 build_shear_mat(LMatrix4 &shear_mat, 01798 const LPoint3 &cul, const LPoint3 &cur, 01799 const LPoint3 &cll, const LPoint3 &clr) { 01800 // Fit a parallelogram around these four points. 01801 01802 // Put the points in an array so we can rotate it around to find 01803 // the longest edge. 01804 LPoint3 points[4] = { 01805 cul, cur, clr, cll 01806 }; 01807 01808 PN_stdfloat max_edge_length = -1.0f; 01809 int base_edge = -1; 01810 for (int i = 0; i < 4; i++) { 01811 LVector3 edge = points[(i + 1) % 4] - points[i]; 01812 PN_stdfloat length = edge.length_squared(); 01813 if (length > max_edge_length) { 01814 base_edge = i; 01815 max_edge_length = length; 01816 } 01817 } 01818 01819 const LPoint3 &base_origin = points[base_edge]; 01820 LVector3 base_vec = points[(base_edge + 1) % 4] - base_origin; 01821 01822 PN_stdfloat base_edge_length = csqrt(max_edge_length); 01823 01824 // The longest edge is the base of our parallelogram. The parallel 01825 // edge must pass through the point furthest from this edge. 01826 01827 int a = (base_edge + 2) % 4; 01828 int b = (base_edge + 3) % 4; 01829 01830 PN_stdfloat a_dist = sqr_dist_to_line(points[a], base_origin, base_vec); 01831 PN_stdfloat b_dist = sqr_dist_to_line(points[b], base_origin, base_vec); 01832 01833 int far_point; 01834 PN_stdfloat dist; 01835 if (a_dist > b_dist) { 01836 far_point = a; 01837 dist = csqrt(a_dist); 01838 } else { 01839 far_point = b; 01840 dist = csqrt(b_dist); 01841 } 01842 01843 // Try to make the parallelogram as nearly rectangular as possible. 01844 // How suitable is a true rectangle? 01845 LVector3 perpendic = base_vec.cross(LVector3(0.0f, -1.0f, 0.0f)); 01846 perpendic.normalize(); 01847 perpendic *= dist; 01848 LPoint3 parallel_origin = points[base_edge] + perpendic; 01849 01850 // It follows that far_point is on the line passing through the 01851 // parallel edge. Is it within the endpoints? 01852 LVector3 base_norm_vec = base_vec / base_edge_length; 01853 01854 LVector3 far_point_delta = points[far_point] - parallel_origin; 01855 PN_stdfloat far_point_pos = far_point_delta.dot(base_norm_vec); 01856 01857 if (far_point_pos < 0.0f) { 01858 // We have to slide the parallel_origin back to include far_point. 01859 parallel_origin += base_norm_vec * far_point_pos; 01860 01861 } else if (far_point_pos > base_edge_length) { 01862 // We have to slide the parallel_origin forward to include 01863 // far_point. 01864 parallel_origin += base_norm_vec * (far_point_pos - base_edge_length); 01865 } 01866 01867 // Finally, is the other point within the parallelogram? 01868 PN_stdfloat t; 01869 PN_stdfloat Ox = parallel_origin[0]; 01870 PN_stdfloat Oy = parallel_origin[2]; 01871 PN_stdfloat Vx = base_vec[0]; 01872 PN_stdfloat Vy = base_vec[2]; 01873 PN_stdfloat Ax, Ay, Bx, By; 01874 01875 if (far_point == a) { 01876 // near point is b 01877 LVector3 v = points[b] - base_origin; 01878 Ax = points[b][0]; 01879 Ay = points[b][2]; 01880 Bx = v[0]; 01881 By = v[2]; 01882 } else { 01883 // near point is a 01884 LVector3 v = points[a] - (base_origin + base_vec); 01885 Ax = points[a][0]; 01886 Ay = points[a][2]; 01887 Bx = v[0]; 01888 By = v[2]; 01889 } 01890 t = ((Ox - Ax) * By + (Ay - Oy) * Bx) / (Bx * Vy - By * Vx); 01891 01892 if (t < 0.0f) { 01893 // We need to slide the parallel_origin back to include 01894 // the near point. 01895 parallel_origin += base_vec * t; 01896 } else if (t > 1.0f) { 01897 // We need to slide the parallel_origin forward to include the far 01898 // point. 01899 parallel_origin += base_vec * (1.0f - t); 01900 } 01901 01902 LVector3 adjacent_norm_vec = parallel_origin - base_origin; 01903 adjacent_norm_vec.normalize(); 01904 01905 // Now we've defined a parallelogram that includes all four points, 01906 // and we're ready to build a shear transform. 01907 shear_mat = LMatrix4::ident_mat(); 01908 01909 // The edges of the parallelogram become the axes. 01910 switch (base_edge) { 01911 case 0: 01912 // The base_origin is the upper-left corner. X axis is base_norm_vec, 01913 // Z axis is -adjacent_norm_vec. 01914 shear_mat.set_row(0, base_norm_vec); 01915 shear_mat.set_row(2, -adjacent_norm_vec); 01916 break; 01917 01918 case 1: 01919 // The base_origin is the upper-right corner. X axis is 01920 // -adjacent_norm_vec, Z axis is -base_norm_vec. 01921 shear_mat.set_row(0, -adjacent_norm_vec); 01922 shear_mat.set_row(2, -base_norm_vec); 01923 break; 01924 01925 case 2: 01926 // The base_origin is the lower-right corner. X axis is 01927 // -base_norm_vec, Z axis is adjacent_norm_vec. 01928 shear_mat.set_row(0, -base_norm_vec); 01929 shear_mat.set_row(2, adjacent_norm_vec); 01930 break; 01931 01932 case 3: 01933 // The base_origin is the lower-left corner. X axis is 01934 // adjacent_norm_vec, Z axis is base_norm_vec. 01935 shear_mat.set_row(0, adjacent_norm_vec); 01936 shear_mat.set_row(2, base_norm_vec); 01937 break; 01938 01939 default: 01940 nassertv(false); 01941 } 01942 } 01943 01944 //////////////////////////////////////////////////////////////////// 01945 // Function: Lens::sqr_dist_to_line 01946 // Access: Private, Static 01947 // Description: A support function for build_shear_mat(), this 01948 // computes the minimum distance from a point to a line, 01949 // and returns the distance squared. 01950 //////////////////////////////////////////////////////////////////// 01951 PN_stdfloat Lens:: 01952 sqr_dist_to_line(const LPoint3 &point, const LPoint3 &origin, 01953 const LVector3 &vec) { 01954 LVector3 norm = vec; 01955 norm.normalize(); 01956 LVector3 d = point - origin; 01957 PN_stdfloat hyp_2 = d.length_squared(); 01958 PN_stdfloat leg = d.dot(norm); 01959 return hyp_2 - leg * leg; 01960 } 01961 01962 //////////////////////////////////////////////////////////////////// 01963 // Function: Lens::write_datagram 01964 // Access: Public, Virtual 01965 // Description: Writes the contents of this object to the datagram 01966 // for shipping out to a Bam file. 01967 //////////////////////////////////////////////////////////////////// 01968 void Lens:: 01969 write_datagram(BamWriter *manager, Datagram &dg) { 01970 TypedWritable::write_datagram(manager, dg); 01971 manager->write_cdata(dg, _cycler); 01972 } 01973 01974 //////////////////////////////////////////////////////////////////// 01975 // Function: Lens::fillin 01976 // Access: Protected 01977 // Description: This internal function is called by make_from_bam to 01978 // read in all of the relevant data from the BamFile for 01979 // the new Lens. 01980 //////////////////////////////////////////////////////////////////// 01981 void Lens:: 01982 fillin(DatagramIterator &scan, BamReader *manager) { 01983 TypedWritable::fillin(scan, manager); 01984 manager->read_cdata(scan, _cycler); 01985 } 01986 01987 //////////////////////////////////////////////////////////////////// 01988 // Function: Lens::CData::Constructor 01989 // Access: Public 01990 // Description: 01991 //////////////////////////////////////////////////////////////////// 01992 Lens::CData:: 01993 CData() { 01994 clear(); 01995 } 01996 01997 //////////////////////////////////////////////////////////////////// 01998 // Function: Lens::CData::Copy Constructor 01999 // Access: Public 02000 // Description: 02001 //////////////////////////////////////////////////////////////////// 02002 Lens::CData:: 02003 CData(const Lens::CData ©) { 02004 _change_event = copy._change_event; 02005 _cs = copy._cs; 02006 _film_size = copy._film_size; 02007 _film_offset = copy._film_offset; 02008 _focal_length = copy._focal_length; 02009 _fov = copy._fov; 02010 _aspect_ratio = copy._aspect_ratio; 02011 _near_distance = copy._near_distance; 02012 _far_distance = copy._far_distance; 02013 02014 _view_hpr = copy._view_hpr; 02015 _view_vector = copy._view_vector; 02016 _interocular_distance = copy._interocular_distance; 02017 _convergence_distance = copy._convergence_distance; 02018 _keystone = copy._keystone; 02019 02020 _user_flags = copy._user_flags; 02021 _comp_flags = 0; 02022 02023 _focal_length_seq = copy._focal_length_seq; 02024 _fov_seq = copy._fov_seq; 02025 _film_size_seq = copy._film_size_seq; 02026 02027 _geom_data = copy._geom_data; 02028 } 02029 02030 //////////////////////////////////////////////////////////////////// 02031 // Function: Lens::CData::make_copy 02032 // Access: Public, Virtual 02033 // Description: 02034 //////////////////////////////////////////////////////////////////// 02035 CycleData *Lens::CData:: 02036 make_copy() const { 02037 return new CData(*this); 02038 } 02039 02040 //////////////////////////////////////////////////////////////////// 02041 // Function: Lens::CData::write_datagram 02042 // Access: Public, Virtual 02043 // Description: Writes the contents of this object to the datagram 02044 // for shipping out to a Bam file. 02045 //////////////////////////////////////////////////////////////////// 02046 void Lens::CData:: 02047 write_datagram(BamWriter *manager, Datagram &dg) const { 02048 dg.add_string(_change_event); 02049 dg.add_uint8((int)_cs); 02050 _film_size.write_datagram(dg); 02051 _film_offset.write_datagram(dg); 02052 dg.add_stdfloat(_focal_length); 02053 _fov.write_datagram(dg); 02054 dg.add_stdfloat(_aspect_ratio); 02055 dg.add_stdfloat(_near_distance); 02056 dg.add_stdfloat(_far_distance); 02057 dg.add_uint16(_user_flags); 02058 } 02059 02060 //////////////////////////////////////////////////////////////////// 02061 // Function: Lens::CData::fillin 02062 // Access: Public, Virtual 02063 // Description: This internal function is called by make_from_bam to 02064 // read in all of the relevant data from the BamFile for 02065 // the new Geom. 02066 //////////////////////////////////////////////////////////////////// 02067 void Lens::CData:: 02068 fillin(DatagramIterator &scan, BamReader *manager) { 02069 _change_event = scan.get_string(); 02070 _cs = (CoordinateSystem)scan.get_uint8(); 02071 _film_size.read_datagram(scan); 02072 _film_offset.read_datagram(scan); 02073 _focal_length = scan.get_stdfloat(); 02074 _fov.read_datagram(scan); 02075 _aspect_ratio = scan.get_stdfloat(); 02076 _near_distance = scan.get_stdfloat(); 02077 _far_distance = scan.get_stdfloat(); 02078 _user_flags = scan.get_uint16(); 02079 02080 _comp_flags = 0; 02081 } 02082 02083 //////////////////////////////////////////////////////////////////// 02084 // Function: Lens::CData::clear 02085 // Access: Public 02086 // Description: 02087 //////////////////////////////////////////////////////////////////// 02088 void Lens::CData:: 02089 clear() { 02090 _change_event = ""; 02091 _cs = CS_default; 02092 _film_size.set(1.0f, 1.0f); 02093 _film_offset.set(0.0f, 0.0f); 02094 _focal_length = 1.0f; 02095 _fov.set(default_fov, default_fov); 02096 _aspect_ratio = 1.0f; 02097 _near_distance = default_near; 02098 _far_distance = default_far; 02099 _view_hpr.set(0.0f, 0.0f, 0.0f); 02100 _view_vector.set(0.0f, 1.0f, 0.0f); 02101 _up_vector.set(0.0f, 0.0f, 1.0f); 02102 _keystone.set(0.0f, 0.0f); 02103 02104 _user_flags = 0; 02105 _comp_flags = CF_fov; 02106 02107 _interocular_distance = 0.0; 02108 _convergence_distance = 0.0; 02109 02110 if (default_keystone.has_value()) { 02111 _keystone.set(default_keystone[0], default_keystone[1]); 02112 _user_flags |= UF_keystone; 02113 } 02114 02115 // Assign an initial arbitrary sequence to these three. 02116 _film_size_seq = 0; 02117 _focal_length_seq = 1; 02118 _fov_seq = 2; 02119 }