00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
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
00032
00033
00034
00035 Lens::
00036 Lens() {
00037 clear();
00038 }
00039
00040
00041
00042
00043
00044
00045 Lens::
00046 Lens(const Lens ©) : _cycler(copy._cycler) {
00047
00048 CDWriter cdata(_cycler, true);
00049 cdata->_geom_data = NULL;
00050 }
00051
00052
00053
00054
00055
00056
00057 void Lens::
00058 operator = (const Lens ©) {
00059 _cycler = copy._cycler;
00060
00061
00062 CDWriter cdata(_cycler, true);
00063 cdata->_geom_data = NULL;
00064 }
00065
00066
00067
00068
00069
00070
00071
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
00083
00084
00085
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
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
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
00119
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
00124 do_adjust_user_flags(cdata, UF_focal_length | UF_vfov | UF_hfov,
00125 UF_min_fov);
00126 } else {
00127
00128 nassertv(cdata->_film_size_seq == 0);
00129
00130
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
00138
00139
00140 do_throw_change_event(cdata);
00141 }
00142
00143
00144
00145
00146
00147
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
00161
00162
00163
00164
00165
00166 PN_stdfloat Lens::
00167 get_default_near() {
00168 return default_near;
00169 }
00170
00171
00172
00173
00174
00175
00176
00177
00178 PN_stdfloat Lens::
00179 get_default_far() {
00180 return default_far;
00181 }
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
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
00207
00208
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
00221
00222
00223
00224
00225
00226
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
00243
00244
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
00257
00258
00259
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
00272
00273
00274
00275
00276 LPoint3 Lens::
00277 get_nodal_point() const {
00278 return get_view_mat().get_row3(3);
00279 }
00280
00281
00282
00283
00284
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
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
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
00329
00330
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
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
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
00410
00411
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
00417
00418
00419
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
00430
00431
00432
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
00441 LMatrix4 rot_mat;
00442 look_at(rot_mat, view_vector, up_vector, CS_zup_right);
00443
00444
00445 LMatrix4 inv_rot_mat;
00446 inv_rot_mat.invert_affine_from(rot_mat);
00447
00448
00449
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
00456
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
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
00473 LMatrix4 inv_view_mat =
00474 inv_rot_mat *
00475 inv_shear_mat;
00476
00477
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
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
00497
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
00507
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
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
00524
00525 if (x_spread < z_spread * aspect_ratio) {
00526
00527 x_spread = z_spread * aspect_ratio;
00528 } else if (z_spread < x_spread / aspect_ratio) {
00529
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
00541
00542
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
00555
00556
00557
00558
00559
00560 void Lens::
00561 recompute_all() {
00562 CDWriter cdata(_cycler);
00563 cdata->_comp_flags = 0;
00564 }
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574 bool Lens::
00575 is_linear() const {
00576 return false;
00577 }
00578
00579
00580
00581
00582
00583
00584
00585
00586 bool Lens::
00587 is_perspective() const {
00588 return false;
00589 }
00590
00591
00592
00593
00594
00595
00596
00597
00598 bool Lens::
00599 is_orthographic() const {
00600 return false;
00601 }
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612 PT(Geom) Lens::
00613 make_geometry() {
00614 CDWriter cdata(_cycler, true);
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625 int num_segments = do_define_geom_data(cdata);
00626 if (num_segments == 0) {
00627
00628 cdata->_geom_data.clear();
00629 return (Geom *)NULL;
00630 }
00631
00632
00633 PT(GeomLinestrips) line = new GeomLinestrips(Geom::UH_static);
00634
00635
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
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
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
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
00684
00685
00686
00687
00688
00689
00690 PT(BoundingVolume) Lens::
00691 make_bounds() const {
00692 CDReader cdata(_cycler);
00693
00694
00695
00696 LPoint3 fll, flr, ful, fur;
00697 LPoint3 nll, nlr, nul, nur;
00698 LPoint3 corner;
00699
00700
00701 corner.set(-1.0f, 1.0f, 0.0f);
00702 if (!do_extrude(cdata, corner, nul, ful)) {
00703 return (BoundingVolume *)NULL;
00704 }
00705
00706
00707 corner.set(1.0f, 1.0f, 0.0f);
00708 if (!do_extrude(cdata, corner, nur, fur)) {
00709 return (BoundingVolume *)NULL;
00710 }
00711
00712
00713 corner.set(1.0f, -1.0f, 0.0f);
00714 if (!do_extrude(cdata, corner, nlr, flr)) {
00715 return (BoundingVolume *)NULL;
00716 }
00717
00718
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
00729
00730
00731
00732 void Lens::
00733 output(ostream &out) const {
00734 out << get_type();
00735 }
00736
00737
00738
00739
00740
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
00749
00750
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
00758
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
00763 do_adjust_user_flags(cdata, UF_hfov | UF_vfov | UF_min_fov | UF_film_height,
00764 UF_film_width);
00765 } else {
00766
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
00778
00779
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
00787
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
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
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
00804
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
00813
00814
00815
00816 const LVecBase2 &Lens::
00817 do_get_film_size(const CData *cdata) const {
00818 if ((cdata->_comp_flags & CF_film_size) == 0) {
00819
00820
00821
00822 ((Lens *)this)->do_compute_film_size((CData *)cdata);
00823 }
00824 return cdata->_film_size;
00825 }
00826
00827
00828
00829
00830
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
00838
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
00843 do_adjust_user_flags(cdata, UF_film_width | UF_film_height,
00844 UF_focal_length);
00845 } else {
00846
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
00859
00860
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
00872
00873
00874
00875 void Lens::
00876 do_set_fov(CData *cdata, PN_stdfloat hfov) {
00877 nassertv(!cnan(hfov));
00878 cdata->_fov[0] = hfov;
00879
00880
00881
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
00886 do_adjust_user_flags(cdata, UF_focal_length | UF_vfov | UF_min_fov,
00887 UF_hfov);
00888 } else {
00889
00890 nassertv(cdata->_film_size_seq == 0);
00891
00892
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
00900
00901
00902 do_throw_change_event(cdata);
00903 }
00904
00905
00906
00907
00908
00909
00910 void Lens::
00911 do_set_fov(CData *cdata, const LVecBase2 &fov) {
00912 nassertv(!fov.is_nan());
00913 cdata->_fov = fov;
00914
00915
00916
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
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
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
00933
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
00942
00943
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
00955
00956
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
00971
00972
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
00984
00985
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
01008
01009
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
01049
01050
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
01062
01063
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
01077
01078
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
01090
01091
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
01105
01106
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
01123
01124
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
01141
01142
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
01159
01160
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
01172
01173
01174
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
01187
01188
01189 cdata->_geom_data.clear();
01190 } else {
01191
01192
01193 do_define_geom_data(cdata);
01194 }
01195 }
01196 }
01197
01198
01199
01200
01201
01202
01203
01204
01205
01206
01207
01208
01209
01210
01211
01212
01213
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
01233
01234
01235
01236
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
01247
01248
01249
01250
01251
01252
01253
01254
01255
01256
01257
01258
01259
01260
01261
01262
01263
01264
01265
01266
01267
01268
01269
01270
01271
01272
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
01282
01283
01284
01285
01286
01287
01288
01289
01290
01291
01292
01293
01294
01295
01296
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
01317
01318
01319
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
01325
01326
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
01355
01356
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
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
01379
01380
01381
01382
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
01397
01398
01399
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
01411 if ((cdata->_user_flags & UF_focal_length) != 0) {
01412
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
01420 cdata->_min_fov = default_fov;
01421 got_min_fov = true;
01422 }
01423 }
01424
01425 if (got_min_fov) {
01426
01427
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
01438 if (!got_hfov) {
01439 if ((cdata->_user_flags & UF_focal_length) == 0 &&
01440 (cdata->_comp_flags & CF_focal_length) == 0) {
01441
01442
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
01455
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
01475
01476
01477
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
01494
01495
01496
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
01510
01511
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
01525
01526
01527
01528
01529 void Lens::
01530 do_compute_projection_mat(CData *lens_cdata) {
01531
01532
01533
01534
01535
01536
01537
01538
01539 CoordinateSystem cs = lens_cdata->_cs;
01540 if (cs == CS_default) {
01541 cs = get_default_coordinate_system();
01542 }
01543 lens_cdata->_projection_mat = LMatrix4::convert_mat(cs, CS_zup_right);
01544 lens_cdata->_projection_mat_inv = LMatrix4::convert_mat(CS_zup_right, cs);
01545
01546
01547
01548 lens_cdata->_projection_mat_left = lens_cdata->_projection_mat_right = lens_cdata->_projection_mat;
01549 lens_cdata->_projection_mat_left_inv = lens_cdata->_projection_mat_right_inv = lens_cdata->_projection_mat_inv;
01550
01551 do_adjust_comp_flags(lens_cdata, 0, CF_projection_mat | CF_projection_mat_inv |
01552 CF_projection_mat_left_inv | CF_projection_mat_right_inv);
01553 }
01554
01555
01556
01557
01558
01559
01560
01561 void Lens::
01562 do_compute_film_mat(CData *cdata) {
01563
01564
01565
01566
01567
01568
01569 LVecBase2 film_size = do_get_film_size(cdata);
01570 LVector2 film_offset = do_get_film_offset(cdata);
01571
01572 PN_stdfloat scale_x = 2.0f / film_size[0];
01573 PN_stdfloat scale_y = 2.0f / film_size[1];
01574 cdata->_film_mat.set(scale_x, 0.0f, 0.0f, 0.0f,
01575 0.0f, scale_y, 0.0f, 0.0f,
01576 0.0f, 0.0f, 1.0f, 0.0f,
01577 -film_offset[0] * scale_x, -film_offset[1] * scale_y, 0.0f, 1.0f);
01578
01579 if ((cdata->_user_flags & UF_keystone) != 0) {
01580 cdata->_film_mat = LMatrix4(1.0f, 0.0f, cdata->_keystone[0], cdata->_keystone[0],
01581 0.0f, 1.0f, cdata->_keystone[1], cdata->_keystone[1],
01582 0.0f, 0.0f, 1.0f, 0.0f,
01583 0.0f, 0.0f, 0.0f, 1.0f) * cdata->_film_mat;
01584 }
01585
01586 do_adjust_comp_flags(cdata, CF_film_mat_inv, CF_film_mat);
01587 }
01588
01589
01590
01591
01592
01593
01594
01595 void Lens::
01596 do_compute_lens_mat(CData *cdata) {
01597 if ((cdata->_user_flags & UF_view_mat) == 0) {
01598 if ((cdata->_user_flags & UF_view_hpr) != 0) {
01599 compose_matrix(cdata->_lens_mat,
01600 LVecBase3(1.0f, 1.0f, 1.0f),
01601 LVecBase3(0.0f, 0.0f, 0.0f),
01602 cdata->_view_hpr,
01603 LVecBase3(0.0f, 0.0f, 0.0f), cdata->_cs);
01604
01605 } else if ((cdata->_user_flags & UF_view_vector) != 0) {
01606 look_at(cdata->_lens_mat, cdata->_view_vector, cdata->_up_vector, cdata->_cs);
01607
01608 } else {
01609 cdata->_lens_mat = LMatrix4::ident_mat();
01610 }
01611 }
01612 do_adjust_comp_flags(cdata, CF_lens_mat_inv, CF_lens_mat);
01613 }
01614
01615
01616
01617
01618
01619
01620
01621
01622
01623
01624 PN_stdfloat Lens::
01625 fov_to_film(PN_stdfloat, PN_stdfloat, bool) const {
01626 return 1.0f;
01627 }
01628
01629
01630
01631
01632
01633
01634
01635
01636
01637
01638 PN_stdfloat Lens::
01639 fov_to_focal_length(PN_stdfloat, PN_stdfloat, bool) const {
01640 return 1.0f;
01641 }
01642
01643
01644
01645
01646
01647
01648
01649
01650
01651
01652 PN_stdfloat Lens::
01653 film_to_fov(PN_stdfloat, PN_stdfloat, bool) const {
01654 return default_fov;
01655 }
01656
01657
01658
01659
01660
01661
01662
01663
01664
01665
01666
01667
01668
01669
01670
01671 void Lens::
01672 do_resequence_fov_triad(const CData *cdata, char &newest, char &older_a, char &older_b) const {
01673 nassertv(newest + older_a + older_b == 3);
01674 switch (newest) {
01675 case 0:
01676 newest = 2;
01677 older_a--;
01678 older_b--;
01679 nassertv(older_a + older_b == 1);
01680 break;
01681
01682 case 1:
01683 newest = 2;
01684 if (older_a == 2) {
01685 nassertv(older_b == 0);
01686 older_a = 1;
01687 } else {
01688 nassertv(older_a == 0 && older_b == 2);
01689 older_b = 1;
01690 }
01691 break;
01692
01693 case 2:
01694 nassertv(older_a + older_b == 1);
01695 break;
01696
01697 default:
01698 gobj_cat.error()
01699 << "Invalid fov sequence numbers in lens: "
01700 << (int)newest << ", " << (int)older_a << ", " << (int)older_b << "\n";
01701 nassertv(false);
01702 return;
01703 }
01704
01705 if (gobj_cat.is_debug()) {
01706 gobj_cat.debug()
01707 << "Lens.do_resequence_fov_triad():";
01708 for (int i = 2; i >= 0; --i) {
01709 if (cdata->_fov_seq == i) {
01710 gobj_cat.debug(false)
01711 << " fov";
01712 } else if (cdata->_focal_length_seq == i) {
01713 gobj_cat.debug(false)
01714 << " focal_length";
01715 } else if (cdata->_film_size_seq == i) {
01716 gobj_cat.debug(false)
01717 << " film_size";
01718 }
01719 }
01720 gobj_cat.debug(false)
01721 << "\n";
01722 }
01723 }
01724
01725
01726
01727
01728
01729
01730
01731
01732
01733
01734
01735 int Lens::
01736 do_define_geom_data(CData *cdata) {
01737 int num_segments = 1;
01738 if (!is_linear()) {
01739 num_segments = lens_geom_segments;
01740 }
01741
01742 if (cdata->_geom_data == (GeomVertexData *)NULL) {
01743 cdata->_geom_data = new GeomVertexData
01744 ("lens", GeomVertexFormat::get_v3(),
01745 Geom::UH_dynamic);
01746 }
01747
01748 GeomVertexWriter vertex(cdata->_geom_data, InternalName::get_vertex());
01749 LPoint3 near_point, far_point;
01750 for (int si = 0; si < num_segments; si++) {
01751 PN_stdfloat t = 2.0f * (PN_stdfloat)si / (PN_stdfloat)num_segments;
01752
01753
01754 LPoint2 p1(-1.0f + t, 1.0f);
01755 if (!extrude(p1, near_point, far_point)) {
01756
01757 return 0;
01758 }
01759 vertex.add_data3(near_point);
01760 vertex.add_data3(far_point);
01761
01762
01763 LPoint2 p2(1.0f, 1.0f - t);
01764 if (!extrude(p2, near_point, far_point)) {
01765
01766 return 0;
01767 }
01768 vertex.add_data3(near_point);
01769 vertex.add_data3(far_point);
01770
01771
01772 LPoint2 p3(1.0f - t, -1.0f);
01773 if (!extrude(p3, near_point, far_point)) {
01774
01775 return 0;
01776 }
01777 vertex.add_data3(near_point);
01778 vertex.add_data3(far_point);
01779
01780
01781 LPoint2 p4(-1.0f, -1.0f + t);
01782 if (!extrude(p4, near_point, far_point)) {
01783
01784 return 0;
01785 }
01786 vertex.add_data3(near_point);
01787 vertex.add_data3(far_point);
01788 }
01789
01790
01791 LPoint3 near_axis = LPoint3::origin(cdata->_cs) + LVector3::forward(cdata->_cs) * cdata->_near_distance;
01792 LPoint3 far_axis = LPoint3::origin(cdata->_cs) + LVector3::forward(cdata->_cs) * cdata->_far_distance;
01793 const LMatrix4 &lens_mat = do_get_lens_mat(cdata);
01794 near_axis = near_axis * lens_mat;
01795 far_axis = far_axis * lens_mat;
01796 vertex.add_data3(near_axis);
01797 vertex.add_data3(far_axis);
01798
01799 return num_segments;
01800 }
01801
01802
01803
01804
01805
01806
01807
01808
01809 void Lens::
01810 build_shear_mat(LMatrix4 &shear_mat,
01811 const LPoint3 &cul, const LPoint3 &cur,
01812 const LPoint3 &cll, const LPoint3 &clr) {
01813
01814
01815
01816
01817 LPoint3 points[4] = {
01818 cul, cur, clr, cll
01819 };
01820
01821 PN_stdfloat max_edge_length = -1.0f;
01822 int base_edge = -1;
01823 for (int i = 0; i < 4; i++) {
01824 LVector3 edge = points[(i + 1) % 4] - points[i];
01825 PN_stdfloat length = edge.length_squared();
01826 if (length > max_edge_length) {
01827 base_edge = i;
01828 max_edge_length = length;
01829 }
01830 }
01831
01832 const LPoint3 &base_origin = points[base_edge];
01833 LVector3 base_vec = points[(base_edge + 1) % 4] - base_origin;
01834
01835 PN_stdfloat base_edge_length = csqrt(max_edge_length);
01836
01837
01838
01839
01840 int a = (base_edge + 2) % 4;
01841 int b = (base_edge + 3) % 4;
01842
01843 PN_stdfloat a_dist = sqr_dist_to_line(points[a], base_origin, base_vec);
01844 PN_stdfloat b_dist = sqr_dist_to_line(points[b], base_origin, base_vec);
01845
01846 int far_point;
01847 PN_stdfloat dist;
01848 if (a_dist > b_dist) {
01849 far_point = a;
01850 dist = csqrt(a_dist);
01851 } else {
01852 far_point = b;
01853 dist = csqrt(b_dist);
01854 }
01855
01856
01857
01858 LVector3 perpendic = base_vec.cross(LVector3(0.0f, -1.0f, 0.0f));
01859 perpendic.normalize();
01860 perpendic *= dist;
01861 LPoint3 parallel_origin = points[base_edge] + perpendic;
01862
01863
01864
01865 LVector3 base_norm_vec = base_vec / base_edge_length;
01866
01867 LVector3 far_point_delta = points[far_point] - parallel_origin;
01868 PN_stdfloat far_point_pos = far_point_delta.dot(base_norm_vec);
01869
01870 if (far_point_pos < 0.0f) {
01871
01872 parallel_origin += base_norm_vec * far_point_pos;
01873
01874 } else if (far_point_pos > base_edge_length) {
01875
01876
01877 parallel_origin += base_norm_vec * (far_point_pos - base_edge_length);
01878 }
01879
01880
01881 PN_stdfloat t;
01882 PN_stdfloat Ox = parallel_origin[0];
01883 PN_stdfloat Oy = parallel_origin[2];
01884 PN_stdfloat Vx = base_vec[0];
01885 PN_stdfloat Vy = base_vec[2];
01886 PN_stdfloat Ax, Ay, Bx, By;
01887
01888 if (far_point == a) {
01889
01890 LVector3 v = points[b] - base_origin;
01891 Ax = points[b][0];
01892 Ay = points[b][2];
01893 Bx = v[0];
01894 By = v[2];
01895 } else {
01896
01897 LVector3 v = points[a] - (base_origin + base_vec);
01898 Ax = points[a][0];
01899 Ay = points[a][2];
01900 Bx = v[0];
01901 By = v[2];
01902 }
01903 t = ((Ox - Ax) * By + (Ay - Oy) * Bx) / (Bx * Vy - By * Vx);
01904
01905 if (t < 0.0f) {
01906
01907
01908 parallel_origin += base_vec * t;
01909 } else if (t > 1.0f) {
01910
01911
01912 parallel_origin += base_vec * (1.0f - t);
01913 }
01914
01915 LVector3 adjacent_norm_vec = parallel_origin - base_origin;
01916 adjacent_norm_vec.normalize();
01917
01918
01919
01920 shear_mat = LMatrix4::ident_mat();
01921
01922
01923 switch (base_edge) {
01924 case 0:
01925
01926
01927 shear_mat.set_row(0, base_norm_vec);
01928 shear_mat.set_row(2, -adjacent_norm_vec);
01929 break;
01930
01931 case 1:
01932
01933
01934 shear_mat.set_row(0, -adjacent_norm_vec);
01935 shear_mat.set_row(2, -base_norm_vec);
01936 break;
01937
01938 case 2:
01939
01940
01941 shear_mat.set_row(0, -base_norm_vec);
01942 shear_mat.set_row(2, adjacent_norm_vec);
01943 break;
01944
01945 case 3:
01946
01947
01948 shear_mat.set_row(0, adjacent_norm_vec);
01949 shear_mat.set_row(2, base_norm_vec);
01950 break;
01951
01952 default:
01953 nassertv(false);
01954 }
01955 }
01956
01957
01958
01959
01960
01961
01962
01963
01964 PN_stdfloat Lens::
01965 sqr_dist_to_line(const LPoint3 &point, const LPoint3 &origin,
01966 const LVector3 &vec) {
01967 LVector3 norm = vec;
01968 norm.normalize();
01969 LVector3 d = point - origin;
01970 PN_stdfloat hyp_2 = d.length_squared();
01971 PN_stdfloat leg = d.dot(norm);
01972 return hyp_2 - leg * leg;
01973 }
01974
01975
01976
01977
01978
01979
01980
01981 void Lens::
01982 write_datagram(BamWriter *manager, Datagram &dg) {
01983 TypedWritable::write_datagram(manager, dg);
01984 manager->write_cdata(dg, _cycler);
01985 }
01986
01987
01988
01989
01990
01991
01992
01993
01994 void Lens::
01995 fillin(DatagramIterator &scan, BamReader *manager) {
01996 TypedWritable::fillin(scan, manager);
01997 manager->read_cdata(scan, _cycler);
01998 }
01999
02000
02001
02002
02003
02004
02005 Lens::CData::
02006 CData() {
02007 clear();
02008 }
02009
02010
02011
02012
02013
02014
02015 Lens::CData::
02016 CData(const Lens::CData ©) {
02017 _change_event = copy._change_event;
02018 _cs = copy._cs;
02019 _film_size = copy._film_size;
02020 _film_offset = copy._film_offset;
02021 _focal_length = copy._focal_length;
02022 _fov = copy._fov;
02023 _aspect_ratio = copy._aspect_ratio;
02024 _near_distance = copy._near_distance;
02025 _far_distance = copy._far_distance;
02026
02027 _view_hpr = copy._view_hpr;
02028 _view_vector = copy._view_vector;
02029 _interocular_distance = copy._interocular_distance;
02030 _convergence_distance = copy._convergence_distance;
02031 _keystone = copy._keystone;
02032
02033
02034
02035
02036 _lens_mat = copy._lens_mat;
02037
02038 _user_flags = copy._user_flags;
02039 _comp_flags = 0;
02040
02041 _focal_length_seq = copy._focal_length_seq;
02042 _fov_seq = copy._fov_seq;
02043 _film_size_seq = copy._film_size_seq;
02044
02045 _geom_data = copy._geom_data;
02046 }
02047
02048
02049
02050
02051
02052
02053 CycleData *Lens::CData::
02054 make_copy() const {
02055 return new CData(*this);
02056 }
02057
02058
02059
02060
02061
02062
02063
02064 void Lens::CData::
02065 write_datagram(BamWriter *manager, Datagram &dg) const {
02066 dg.add_string(_change_event);
02067 dg.add_uint8((int)_cs);
02068 _film_size.write_datagram(dg);
02069 _film_offset.write_datagram(dg);
02070 dg.add_stdfloat(_focal_length);
02071 _fov.write_datagram(dg);
02072 dg.add_stdfloat(_aspect_ratio);
02073 dg.add_stdfloat(_near_distance);
02074 dg.add_stdfloat(_far_distance);
02075 dg.add_uint16(_user_flags);
02076 }
02077
02078
02079
02080
02081
02082
02083
02084
02085 void Lens::CData::
02086 fillin(DatagramIterator &scan, BamReader *manager) {
02087 _change_event = scan.get_string();
02088 _cs = (CoordinateSystem)scan.get_uint8();
02089 _film_size.read_datagram(scan);
02090 _film_offset.read_datagram(scan);
02091 _focal_length = scan.get_stdfloat();
02092 _fov.read_datagram(scan);
02093 _aspect_ratio = scan.get_stdfloat();
02094 _near_distance = scan.get_stdfloat();
02095 _far_distance = scan.get_stdfloat();
02096 _user_flags = scan.get_uint16();
02097
02098 _comp_flags = 0;
02099 }
02100
02101
02102
02103
02104
02105
02106 void Lens::CData::
02107 clear() {
02108 _change_event = "";
02109 _cs = CS_default;
02110 _film_size.set(1.0f, 1.0f);
02111 _film_offset.set(0.0f, 0.0f);
02112 _focal_length = 1.0f;
02113 _fov.set(default_fov, default_fov);
02114 _aspect_ratio = 1.0f;
02115 _near_distance = default_near;
02116 _far_distance = default_far;
02117 _view_hpr.set(0.0f, 0.0f, 0.0f);
02118 _view_vector.set(0.0f, 1.0f, 0.0f);
02119 _up_vector.set(0.0f, 0.0f, 1.0f);
02120 _keystone.set(0.0f, 0.0f);
02121
02122 _user_flags = 0;
02123 _comp_flags = CF_fov;
02124
02125 _interocular_distance = 0.0;
02126 _convergence_distance = 0.0;
02127
02128 if (default_keystone.has_value()) {
02129 _keystone.set(default_keystone[0], default_keystone[1]);
02130 _user_flags |= UF_keystone;
02131 }
02132
02133
02134 _film_size_seq = 0;
02135 _focal_length_seq = 1;
02136 _fov_seq = 2;
02137 }