16 #include "throw_event.h"
17 #include "compose_matrix.h"
20 #include "geomLinestrips.h"
21 #include "geomVertexWriter.h"
22 #include "boundingHexahedron.h"
24 #include "config_gobj.h"
46 Lens(
const Lens ©) : _cycler(copy._cycler) {
48 CDWriter cdata(_cycler,
true);
49 cdata->_geom_data = NULL;
58 operator = (
const Lens ©) {
59 _cycler = copy._cycler;
62 CDWriter cdata(_cycler,
true);
63 cdata->_geom_data = NULL;
77 do_adjust_comp_flags(cdata, CF_mat | CF_view_hpr | CF_view_vector, 0);
78 do_throw_change_event(cdata);
92 do_set_interocular_distance(cdata, default_iod);
93 do_set_convergence_distance(cdata, default_converge);
94 do_throw_change_event(cdata);
114 nassertv(!cnan(min_fov));
116 cdata->_min_fov = min_fov;
120 do_resequence_fov_triad(cdata, cdata->_fov_seq, cdata->_focal_length_seq, cdata->_film_size_seq);
122 if (cdata->_focal_length_seq == 0) {
124 do_adjust_user_flags(cdata, UF_focal_length | UF_vfov | UF_hfov,
128 nassertv(cdata->_film_size_seq == 0);
131 do_compute_aspect_ratio(cdata);
132 do_adjust_user_flags(cdata, UF_film_width | UF_film_height | UF_vfov | UF_hfov,
135 do_adjust_comp_flags(cdata, CF_mat | CF_focal_length | CF_fov | CF_film_size,
140 do_throw_change_event(cdata);
153 if ((cdata->_comp_flags & CF_fov) == 0) {
154 ((
Lens *)
this)->do_compute_fov((CData *)cdata.
p());
156 return cdata->_min_fov;
195 nassertv(!view_hpr.
is_nan());
197 cdata->_view_hpr = view_hpr;
198 do_adjust_user_flags(cdata, UF_view_vector | UF_view_mat,
200 do_adjust_comp_flags(cdata, CF_mat | CF_view_vector,
202 do_throw_change_event(cdata);
213 if ((cdata->_comp_flags & CF_view_hpr) == 0) {
214 ((
Lens *)
this)->do_compute_view_hpr((CData *)cdata.
p());
216 return cdata->_view_hpr;
230 nassertv(!view_vector.
is_nan());
232 cdata->_view_vector = view_vector;
233 cdata->_up_vector = up_vector;
234 do_adjust_user_flags(cdata, UF_view_hpr | UF_view_mat,
236 do_adjust_comp_flags(cdata, CF_mat | CF_view_hpr,
238 do_throw_change_event(cdata);
249 if ((cdata->_comp_flags & CF_view_vector) == 0) {
250 ((
Lens *)
this)->do_compute_view_vector((CData *)cdata.
p());
252 return cdata->_view_vector;
264 if ((cdata->_comp_flags & CF_view_vector) == 0) {
265 ((
Lens *)
this)->do_compute_view_vector((CData *)cdata.
p());
267 return cdata->_up_vector;
290 do_adjust_user_flags(cdata, 0, UF_view_vector | UF_view_hpr | UF_view_mat);
291 do_adjust_comp_flags(cdata, CF_projection_mat | CF_projection_mat_inv |
292 CF_projection_mat_left_inv | CF_projection_mat_right_inv |
293 CF_lens_mat_inv | CF_view_hpr | CF_view_vector,
295 do_throw_change_event(cdata);
317 nassertv(!keystone.
is_nan());
319 cdata->_keystone = keystone;
320 do_adjust_user_flags(cdata, 0, UF_keystone);
321 do_adjust_comp_flags(cdata, CF_projection_mat | CF_projection_mat_inv |
322 CF_projection_mat_left_inv | CF_projection_mat_right_inv |
323 CF_film_mat | CF_film_mat_inv, 0);
324 do_throw_change_event(cdata);
335 cdata->_keystone.set(0.0f, 0.0f);
336 do_adjust_user_flags(cdata, UF_keystone, 0);
337 do_adjust_comp_flags(cdata, CF_projection_mat | CF_projection_mat_inv |
338 CF_projection_mat_left_inv | CF_projection_mat_right_inv |
339 CF_film_mat | CF_film_mat_inv, 0);
340 do_throw_change_event(cdata);
357 nassertv(!custom_film_mat.
is_nan());
359 cdata->_custom_film_mat = custom_film_mat;
360 do_adjust_user_flags(cdata, 0, UF_custom_film_mat);
361 do_adjust_comp_flags(cdata, CF_projection_mat | CF_projection_mat_inv |
362 CF_projection_mat_left_inv | CF_projection_mat_right_inv |
363 CF_film_mat | CF_film_mat_inv, 0);
364 do_throw_change_event(cdata);
376 do_adjust_user_flags(cdata, UF_custom_film_mat, 0);
377 do_adjust_comp_flags(cdata, CF_projection_mat | CF_projection_mat_inv |
378 CF_projection_mat_left_inv | CF_projection_mat_right_inv |
379 CF_film_mat | CF_film_mat_inv, 0);
380 do_throw_change_event(cdata);
452 const LMatrix4 &lens_mat_inv = do_get_lens_mat_inv(cdata);
454 lens_mat_inv.
get_row3(eye_offset, 3);
461 if ((flags & FC_camera_plane) != 0) {
462 view_vector = (ul + ur + ll + lr) * 0.25;
464 LPlane plane(ll, ul, ur);
465 view_vector = plane.get_normal();
474 if (view_vector == up_vector || ((flags & FC_roll) != 0)) {
476 up_vector = view_vector.cross(top);
482 look_at(rot_mat, view_vector, up_vector, CS_zup_right);
497 nassertv(cul[1] != 0.0f && cur[1] != 0.0f && cll[1] != 0.0f && clr[1] != 0.0f);
507 if ((flags & FC_shear) != 0) {
508 build_shear_mat(shear_mat, cul, cur, cll, clr);
518 inv_view_mat.
set_row(3, eye_offset);
522 do_set_view_mat(cdata, view_mat);
530 nassertv(ful[1] != 0.0f && fur[1] != 0.0f && fll[1] != 0.0f && flr[1] != 0.0f);
538 PN_stdfloat min_x = min(min(ful[0], fur[0]), min(fll[0], flr[0]));
539 PN_stdfloat max_x = max(max(ful[0], fur[0]), max(fll[0], flr[0]));
540 PN_stdfloat min_z = min(min(ful[2], fur[2]), min(fll[2], flr[2]));
541 PN_stdfloat max_z = max(max(ful[2], fur[2]), max(fll[2], flr[2]));
543 PN_stdfloat x_spread, x_center, z_spread, z_center;
545 if ((flags & FC_off_axis) != 0) {
548 x_center = (max_x + min_x) * 0.5f;
549 z_center = (max_z + min_z) * 0.5f;
550 x_spread = x_center - min_x;
551 z_spread = z_center - min_z;
556 x_spread = max(cabs(max_x), cabs(min_x));
557 z_spread = max(cabs(max_z), cabs(min_z));
560 PN_stdfloat aspect_ratio = do_get_aspect_ratio(cdata);
561 nassertv(aspect_ratio != 0.0f);
562 if ((flags & FC_aspect_ratio) == 0) {
565 if (x_spread < z_spread * aspect_ratio) {
567 x_spread = z_spread * aspect_ratio;
568 }
else if (z_spread < x_spread / aspect_ratio) {
570 z_spread = x_spread / aspect_ratio;
574 PN_stdfloat hfov = rad_2_deg(catan(x_spread)) * 2.0f;
575 PN_stdfloat vfov = rad_2_deg(catan(z_spread)) * 2.0f;
577 do_set_fov(cdata,
LVecBase2(hfov, vfov));
579 if ((flags & FC_aspect_ratio) == 0) {
583 do_set_aspect_ratio(cdata, aspect_ratio);
586 const LVecBase2 &film_size = do_get_film_size(cdata);
587 nassertv(x_spread != 0.0f && z_spread != 0.0f);
588 do_set_film_offset(cdata,
LVecBase2(film_size[0] * x_center / (x_spread * 2.0f),
589 film_size[1] * z_center / (z_spread * 2.0f)));
603 cdata->_comp_flags = 0;
654 CDWriter cdata(_cycler,
true);
665 int num_segments = do_define_geom_data(cdata);
666 if (num_segments == 0) {
668 cdata->_geom_data.clear();
677 for (i = 0; i < 4; ++i) {
678 for (si = 0; si < num_segments; ++si) {
679 line->add_vertex(i * 2 + si * (4 * 2) + 0);
683 line->close_primitive();
686 for (i = 0; i < 4; ++i) {
687 for (si = 0; si < num_segments; ++si) {
688 line->add_vertex(i * 2 + si * (4 * 2) + 1);
692 line->close_primitive();
695 line->add_vertex(0 * 2 + 0);
696 line->add_vertex(0 * 2 + 1);
697 line->close_primitive();
699 line->add_vertex(1 * 2 + 0);
700 line->add_vertex(1 * 2 + 1);
701 line->close_primitive();
703 line->add_vertex(2 * 2 + 0);
704 line->add_vertex(2 * 2 + 1);
705 line->close_primitive();
707 line->add_vertex(3 * 2 + 0);
708 line->add_vertex(3 * 2 + 1);
709 line->close_primitive();
712 line->add_vertex(num_segments * (4 * 2) + 0);
713 line->add_vertex(num_segments * (4 * 2) + 1);
714 line->close_primitive();
716 PT(
Geom) geom = new
Geom(cdata->_geom_data);
717 geom->add_primitive(line);
731 make_bounds()
const {
732 CDReader cdata(_cycler);
741 corner.set(-1.0f, 1.0f, 0.0f);
742 if (!do_extrude(cdata, corner, nul, ful)) {
747 corner.set(1.0f, 1.0f, 0.0f);
748 if (!do_extrude(cdata, corner, nur, fur)) {
753 corner.set(1.0f, -1.0f, 0.0f);
754 if (!do_extrude(cdata, corner, nlr, flr)) {
759 corner.set(-1.0f, -1.0f, 0.0f);
760 if (!do_extrude(cdata, corner, nll, fll)) {
773 output(ostream &out)
const {
783 write(ostream &out,
int indent_level)
const {
784 indent(out, indent_level) << get_type() <<
" fov = " <<
get_fov() <<
"\n";
793 do_set_film_size(CData *cdata, PN_stdfloat width) {
794 nassertv(!cnan(width));
795 cdata->_film_size.set(width, width / do_get_aspect_ratio(cdata));
799 do_resequence_fov_triad(cdata, cdata->_film_size_seq, cdata->_focal_length_seq, cdata->_fov_seq);
801 if (cdata->_fov_seq == 0) {
803 do_adjust_user_flags(cdata, UF_hfov | UF_vfov | UF_min_fov | UF_film_height,
807 nassertv(cdata->_focal_length_seq == 0);
808 do_adjust_user_flags(cdata, UF_focal_length | UF_film_height,
811 do_adjust_comp_flags(cdata, CF_mat | CF_focal_length | CF_fov,
813 do_throw_change_event(cdata);
822 do_set_film_size(CData *cdata,
const LVecBase2 &film_size) {
823 nassertv(!film_size.
is_nan());
824 cdata->_film_size = film_size;
828 do_resequence_fov_triad(cdata, cdata->_film_size_seq, cdata->_focal_length_seq, cdata->_fov_seq);
830 if (cdata->_fov_seq == 0) {
832 do_adjust_user_flags(cdata, UF_hfov | UF_vfov | UF_min_fov | UF_aspect_ratio,
833 UF_film_width | UF_film_height);
836 nassertv(cdata->_focal_length_seq == 0);
837 do_adjust_user_flags(cdata, UF_focal_length | UF_vfov | UF_aspect_ratio,
838 UF_film_width | UF_film_height);
840 do_adjust_comp_flags(cdata, CF_mat | CF_focal_length | CF_fov | CF_aspect_ratio,
845 do_compute_aspect_ratio(cdata);
846 do_adjust_user_flags(cdata, 0, UF_aspect_ratio);
848 do_throw_change_event(cdata);
857 do_get_film_size(
const CData *cdata)
const {
858 if ((cdata->_comp_flags & CF_film_size) == 0) {
862 ((
Lens *)
this)->do_compute_film_size((CData *)cdata);
864 return cdata->_film_size;
873 do_set_focal_length(CData *cdata, PN_stdfloat focal_length) {
874 nassertv(!cnan(focal_length));
875 cdata->_focal_length = focal_length;
879 do_resequence_fov_triad(cdata, cdata->_focal_length_seq, cdata->_film_size_seq, cdata->_fov_seq);
881 if (cdata->_film_size_seq == 0) {
883 do_adjust_user_flags(cdata, UF_film_width | UF_film_height,
887 nassertv(cdata->_fov_seq == 0);
888 do_adjust_user_flags(cdata, UF_hfov | UF_vfov | UF_min_fov,
892 do_adjust_comp_flags(cdata, CF_mat | CF_fov | CF_film_size,
894 do_throw_change_event(cdata);
903 do_get_focal_length(
const CData *cdata)
const {
904 if ((cdata->_comp_flags & CF_focal_length) == 0) {
905 ((
Lens *)
this)->do_compute_focal_length((CData *)cdata);
907 return cdata->_focal_length;
916 do_set_fov(CData *cdata, PN_stdfloat hfov) {
917 nassertv(!cnan(hfov));
918 cdata->_fov[0] = hfov;
922 do_resequence_fov_triad(cdata, cdata->_fov_seq, cdata->_focal_length_seq, cdata->_film_size_seq);
924 if (cdata->_focal_length_seq == 0) {
926 do_adjust_user_flags(cdata, UF_focal_length | UF_vfov | UF_min_fov,
930 nassertv(cdata->_film_size_seq == 0);
933 do_compute_aspect_ratio(cdata);
934 do_adjust_user_flags(cdata, UF_film_width | UF_film_height | UF_vfov | UF_min_fov,
937 do_adjust_comp_flags(cdata, CF_mat | CF_focal_length | CF_fov | CF_film_size,
942 do_throw_change_event(cdata);
951 do_set_fov(CData *cdata,
const LVecBase2 &fov) {
957 do_resequence_fov_triad(cdata, cdata->_fov_seq, cdata->_focal_length_seq, cdata->_film_size_seq);
959 if (cdata->_focal_length_seq == 0) {
961 do_adjust_user_flags(cdata, UF_focal_length | UF_film_height | UF_min_fov | UF_aspect_ratio,
965 nassertv(cdata->_film_size_seq == 0);
966 do_adjust_user_flags(cdata, UF_film_width | UF_film_height | UF_min_fov | UF_aspect_ratio,
969 do_adjust_comp_flags(cdata, CF_mat | CF_focal_length | CF_film_size | CF_aspect_ratio,
974 do_compute_aspect_ratio(cdata);
975 do_adjust_user_flags(cdata, 0, UF_aspect_ratio);
977 do_throw_change_event(cdata);
986 do_get_fov(
const CData *cdata)
const {
987 if ((cdata->_comp_flags & CF_fov) == 0) {
988 ((
Lens *)
this)->do_compute_fov((CData *)cdata);
999 do_set_aspect_ratio(CData *cdata, PN_stdfloat aspect_ratio) {
1000 nassertv(!cnan(aspect_ratio));
1001 cdata->_aspect_ratio = aspect_ratio;
1002 do_adjust_user_flags(cdata, UF_film_height | UF_vfov,
1004 do_adjust_comp_flags(cdata, CF_mat | CF_film_size | CF_fov | CF_focal_length,
1006 do_throw_change_event(cdata);
1015 do_get_aspect_ratio(
const CData *cdata)
const {
1016 if ((cdata->_comp_flags & CF_aspect_ratio) == 0) {
1017 ((
Lens *)
this)->do_compute_aspect_ratio((CData *)cdata);
1019 return cdata->_aspect_ratio;
1028 do_get_projection_mat(
const CData *cdata, StereoChannel channel)
const {
1029 if ((cdata->_comp_flags & CF_projection_mat) == 0) {
1030 ((
Lens *)
this)->do_compute_projection_mat((CData *)cdata);
1035 return cdata->_projection_mat_left;
1037 return cdata->_projection_mat_right;
1040 return cdata->_projection_mat;
1043 return cdata->_projection_mat;
1052 do_get_projection_mat_inv(
const CData *cdata, StereoChannel stereo_channel)
const {
1053 switch (stereo_channel) {
1056 if ((cdata->_comp_flags & CF_projection_mat_left_inv) == 0) {
1057 const LMatrix4 &projection_mat_left = do_get_projection_mat(cdata, SC_left);
1058 ((CData *)cdata)->_projection_mat_left_inv.invert_from(projection_mat_left);
1059 ((
Lens *)
this)->do_adjust_comp_flags((CData *)cdata, 0, CF_projection_mat_left_inv);
1062 return cdata->_projection_mat_left_inv;
1066 if ((cdata->_comp_flags & CF_projection_mat_right_inv) == 0) {
1067 const LMatrix4 &projection_mat_right = do_get_projection_mat(cdata, SC_right);
1068 ((CData *)cdata)->_projection_mat_right_inv.invert_from(projection_mat_right);
1069 ((
Lens *)
this)->do_adjust_comp_flags((CData *)cdata, 0, CF_projection_mat_right_inv);
1072 return cdata->_projection_mat_right_inv;
1079 if ((cdata->_comp_flags & CF_projection_mat_inv) == 0) {
1080 const LMatrix4 &projection_mat = do_get_projection_mat(cdata);
1081 ((CData *)cdata)->_projection_mat_inv.invert_from(projection_mat);
1082 ((
Lens *)
this)->do_adjust_comp_flags((CData *)cdata, 0, CF_projection_mat_inv);
1084 return cdata->_projection_mat_inv;
1093 do_get_film_mat(
const CData *cdata)
const {
1094 if ((cdata->_comp_flags & CF_film_mat) == 0) {
1095 ((
Lens *)
this)->do_compute_film_mat((CData *)cdata);
1097 return cdata->_film_mat;
1106 do_get_film_mat_inv(
const CData *cdata)
const {
1107 if ((cdata->_comp_flags & CF_film_mat_inv) == 0) {
1108 const LMatrix4 &film_mat = do_get_film_mat(cdata);
1109 ((CData *)cdata)->_film_mat_inv.invert_from(film_mat);
1110 ((
Lens *)
this)->do_adjust_comp_flags((CData *)cdata, 0, CF_film_mat_inv);
1112 return cdata->_film_mat_inv;
1121 do_get_lens_mat(
const CData *cdata)
const {
1122 if ((cdata->_comp_flags & CF_lens_mat) == 0) {
1123 ((
Lens *)
this)->do_compute_lens_mat((CData *)cdata);
1125 return cdata->_lens_mat;
1134 do_get_lens_mat_inv(
const CData *cdata)
const {
1135 if ((cdata->_comp_flags & CF_lens_mat_inv) == 0) {
1136 const LMatrix4 &lens_mat = do_get_lens_mat(cdata);
1137 ((CData *)cdata)->_lens_mat_inv.invert_from(lens_mat);
1138 ((
Lens *)
this)->do_adjust_comp_flags((CData *)cdata, 0, CF_lens_mat_inv);
1140 return cdata->_lens_mat_inv;
1149 do_set_interocular_distance(CData *cdata, PN_stdfloat interocular_distance) {
1150 nassertv(!cnan(interocular_distance));
1151 cdata->_interocular_distance = interocular_distance;
1152 if (cdata->_interocular_distance == 0.0f) {
1153 do_adjust_user_flags(cdata, UF_interocular_distance, 0);
1155 do_adjust_user_flags(cdata, 0, UF_interocular_distance);
1158 do_adjust_comp_flags(cdata, CF_mat, 0);
1167 do_set_convergence_distance(CData *cdata, PN_stdfloat convergence_distance) {
1168 nassertv(!cnan(convergence_distance));
1169 cdata->_convergence_distance = convergence_distance;
1170 if (cdata->_convergence_distance == 0.0f) {
1171 do_adjust_user_flags(cdata, UF_convergence_distance, 0);
1173 do_adjust_user_flags(cdata, 0, UF_convergence_distance);
1176 do_adjust_comp_flags(cdata, CF_mat, 0);
1185 do_set_view_mat(CData *cdata,
const LMatrix4 &view_mat) {
1186 nassertv(!view_mat.
is_nan());
1187 cdata->_lens_mat = view_mat;
1188 do_adjust_user_flags(cdata, UF_view_vector | UF_view_hpr,
1190 do_adjust_comp_flags(cdata, CF_projection_mat | CF_projection_mat_inv |
1191 CF_projection_mat_left_inv | CF_projection_mat_right_inv |
1192 CF_lens_mat_inv | CF_view_hpr | CF_view_vector,
1194 do_throw_change_event(cdata);
1203 do_get_view_mat(
const CData *cdata)
const {
1204 if ((cdata->_comp_flags & CF_lens_mat) == 0) {
1205 ((
Lens *)
this)->do_compute_lens_mat((CData *)cdata);
1207 return cdata->_lens_mat;
1217 do_throw_change_event(CData *cdata) {
1218 ++(cdata->_last_change);
1220 if (!cdata->_change_event.empty()) {
1221 throw_event(cdata->_change_event,
this);
1224 if (!cdata->_geom_data.is_null()) {
1225 if (cdata->_geom_data->get_ref_count() == 1) {
1229 cdata->_geom_data.clear();
1233 do_define_geom_data(cdata);
1256 do_extrude(
const CData *cdata,
1258 const LMatrix4 &projection_mat_inv = do_get_projection_mat_inv(cdata);
1260 LVecBase4 full(point2d[0], point2d[1], -1.0f, 1.0f);
1261 full = projection_mat_inv.
xform(full);
1263 PN_stdfloat recip_full3 = 1.0 / max((
double)full[3], (
double)lens_far_limit);
1264 near_point.set(full[0] * recip_full3,
1265 full[1] * recip_full3,
1266 full[2] * recip_full3);
1269 LVecBase4 full(point2d[0], point2d[1], 1.0f, 1.0f);
1270 full = projection_mat_inv.
xform(full);
1277 PN_stdfloat recip_full3 = 1.0 / max((
double)full[3], (
double)lens_far_limit);
1278 far_point.set(full[0] * recip_full3,
1279 full[1] * recip_full3,
1280 full[2] * recip_full3);
1293 do_extrude_depth(
const CData *cdata,
1295 LPoint3 near_point, far_point;
1296 bool result =
extrude(point2d, near_point, far_point);
1300 PN_stdfloat t = point2d[2] * 0.5 + 0.5;
1301 point3d = near_point + (far_point - near_point) * t;
1313 do_extrude_depth_with_mat(
const CData *cdata,
1315 const LMatrix4 &projection_mat_inv = do_get_projection_mat_inv(cdata);
1350 do_extrude_vec(
const CData *cdata,
const LPoint3 &point2d,
LVector3 &vec)
const {
1374 do_project(
const CData *cdata,
const LPoint3 &point3d,
LPoint3 &point2d)
const {
1375 const LMatrix4 &projection_mat = do_get_projection_mat(cdata);
1376 LVecBase4 full(point3d[0], point3d[1], point3d[2], 1.0f);
1377 full = projection_mat.
xform(full);
1378 if (full[3] == 0.0f) {
1379 point2d.set(0.0f, 0.0f, 0.0f);
1382 PN_stdfloat recip_full3 = 1.0f/full[3];
1383 point2d.set(full[0] * recip_full3, full[1] * recip_full3, full[2] * recip_full3);
1386 (point2d[0] >= -1.0f) && (point2d[0] <= 1.0f) &&
1387 (point2d[1] >= -1.0f) && (point2d[1] <= 1.0f);
1397 do_compute_film_size(CData *cdata) {
1398 if ((cdata->_user_flags & (UF_min_fov | UF_focal_length)) == (UF_min_fov | UF_focal_length)) {
1402 PN_stdfloat fs = fov_to_film(cdata->_min_fov, cdata->_focal_length,
true);
1403 nassertv((cdata->_user_flags & UF_aspect_ratio) != 0 ||
1404 (cdata->_comp_flags & CF_aspect_ratio) != 0);
1406 if (cdata->_aspect_ratio < 1.0f) {
1407 cdata->_film_size[1] = fs / cdata->_aspect_ratio;
1408 cdata->_film_size[0] = fs;
1411 cdata->_film_size[0] = fs * cdata->_aspect_ratio;
1412 cdata->_film_size[1] = fs;
1416 if ((cdata->_user_flags & UF_film_width) == 0) {
1417 if ((cdata->_user_flags & (UF_hfov | UF_focal_length)) == (UF_hfov | UF_focal_length)) {
1418 cdata->_film_size[0] = fov_to_film(cdata->_fov[0], cdata->_focal_length,
true);
1420 cdata->_film_size[0] = 1.0f;
1424 if ((cdata->_user_flags & UF_film_height) == 0) {
1425 if ((cdata->_user_flags & (UF_vfov | UF_focal_length)) == (UF_vfov | UF_focal_length)) {
1426 cdata->_film_size[1] = fov_to_film(cdata->_fov[1], cdata->_focal_length,
false);
1428 }
else if ((cdata->_user_flags & (UF_hfov | UF_vfov)) == (UF_hfov | UF_vfov)) {
1432 if ((cdata->_comp_flags & CF_focal_length) == 0) {
1433 cdata->_focal_length = fov_to_focal_length(cdata->_fov[0], cdata->_film_size[0],
true);
1434 do_adjust_comp_flags(cdata, 0, CF_focal_length);
1436 cdata->_film_size[1] = fov_to_film(cdata->_fov[1], cdata->_focal_length,
false);
1438 }
else if ((cdata->_user_flags & UF_aspect_ratio) != 0 ||
1439 (cdata->_comp_flags & CF_aspect_ratio) != 0) {
1440 cdata->_film_size[1] = cdata->_film_size[0] / cdata->_aspect_ratio;
1444 cdata->_film_size[1] = cdata->_film_size[0];
1449 do_adjust_comp_flags(cdata, 0, CF_film_size);
1460 do_compute_focal_length(CData *cdata) {
1461 if ((cdata->_user_flags & UF_focal_length) == 0) {
1462 const LVecBase2 &film_size = do_get_film_size(cdata);
1463 const LVecBase2 &fov = do_get_fov(cdata);
1464 cdata->_focal_length = fov_to_focal_length(fov[0], film_size[0],
true);
1467 do_adjust_comp_flags(cdata, 0, CF_focal_length);
1477 do_compute_fov(CData *cdata) {
1478 const LVecBase2 &film_size = do_get_film_size(cdata);
1480 bool got_hfov = ((cdata->_user_flags & UF_hfov) != 0);
1481 bool got_vfov = ((cdata->_user_flags & UF_vfov) != 0);
1482 bool got_min_fov = ((cdata->_user_flags & UF_min_fov) != 0);
1484 if (!got_hfov && !got_vfov && !got_min_fov) {
1486 if ((cdata->_user_flags & UF_focal_length) != 0) {
1488 cdata->_fov[0] = film_to_fov(film_size[0], cdata->_focal_length,
true);
1489 cdata->_fov[1] = film_to_fov(film_size[1], cdata->_focal_length,
true);
1495 cdata->_min_fov = default_fov;
1503 if (film_size[0] < film_size[1]) {
1504 cdata->_fov[0] = cdata->_min_fov;
1507 cdata->_fov[1] = cdata->_min_fov;
1514 if ((cdata->_user_flags & UF_focal_length) == 0 &&
1515 (cdata->_comp_flags & CF_focal_length) == 0) {
1519 cdata->_focal_length = fov_to_focal_length(cdata->_fov[1], film_size[1],
true);
1520 do_adjust_comp_flags(cdata, 0, CF_focal_length);
1522 cdata->_fov[0] = film_to_fov(film_size[0], cdata->_focal_length,
false);
1527 if ((cdata->_user_flags & UF_focal_length) == 0 &&
1528 (cdata->_comp_flags & CF_focal_length) == 0) {
1532 cdata->_focal_length = fov_to_focal_length(cdata->_fov[0], film_size[0],
true);
1533 do_adjust_comp_flags(cdata, 0, CF_focal_length);
1535 cdata->_fov[1] = film_to_fov(film_size[1], cdata->_focal_length,
false);
1540 cdata->_min_fov = film_size[0] < film_size[1] ? cdata->_fov[0] : cdata->_fov[1];
1544 nassertv(got_hfov && got_vfov && got_min_fov);
1545 do_adjust_comp_flags(cdata, 0, CF_fov);
1555 do_compute_aspect_ratio(CData *cdata) {
1556 if ((cdata->_user_flags & UF_aspect_ratio) == 0) {
1557 const LVecBase2 &film_size = do_get_film_size(cdata);
1558 if (film_size[1] == 0.0f) {
1559 cdata->_aspect_ratio = 1.0f;
1561 cdata->_aspect_ratio = film_size[0] / film_size[1];
1564 do_adjust_comp_flags(cdata, 0, CF_aspect_ratio);
1574 do_compute_view_hpr(CData *cdata) {
1575 if ((cdata->_user_flags & UF_view_hpr) == 0) {
1576 const LMatrix4 &view_mat = do_get_view_mat(cdata);
1578 decompose_matrix(view_mat, scale, shear, cdata->_view_hpr, translate, cdata->_cs);
1580 do_adjust_comp_flags(cdata, 0, CF_view_hpr);
1589 do_compute_view_vector(CData *cdata) {
1590 if ((cdata->_user_flags & UF_view_vector) == 0) {
1591 const LMatrix4 &view_mat = do_get_view_mat(cdata);
1593 cdata->_up_vector =
LVector3::up(cdata->_cs) * view_mat;
1595 do_adjust_comp_flags(cdata, 0, CF_view_vector);
1605 do_compute_projection_mat(CData *lens_cdata) {
1614 CoordinateSystem cs = lens_cdata->_cs;
1615 if (cs == CS_default) {
1616 cs = get_default_coordinate_system();
1623 lens_cdata->_projection_mat_left = lens_cdata->_projection_mat_right = lens_cdata->_projection_mat;
1624 lens_cdata->_projection_mat_left_inv = lens_cdata->_projection_mat_right_inv = lens_cdata->_projection_mat_inv;
1626 do_adjust_comp_flags(lens_cdata, 0, CF_projection_mat | CF_projection_mat_inv |
1627 CF_projection_mat_left_inv | CF_projection_mat_right_inv);
1637 do_compute_film_mat(CData *cdata) {
1644 LVecBase2 film_size = do_get_film_size(cdata);
1645 LVector2 film_offset = do_get_film_offset(cdata);
1647 PN_stdfloat scale_x = 2.0f / film_size[0];
1648 PN_stdfloat scale_y = 2.0f / film_size[1];
1649 cdata->_film_mat.set(scale_x, 0.0f, 0.0f, 0.0f,
1650 0.0f, scale_y, 0.0f, 0.0f,
1651 0.0f, 0.0f, 1.0f, 0.0f,
1652 -film_offset[0] * scale_x, -film_offset[1] * scale_y, 0.0f, 1.0f);
1654 if ((cdata->_user_flags & UF_keystone) != 0) {
1655 cdata->_film_mat =
LMatrix4(1.0f, 0.0f, cdata->_keystone[0], cdata->_keystone[0],
1656 0.0f, 1.0f, cdata->_keystone[1], cdata->_keystone[1],
1657 0.0f, 0.0f, 1.0f, 0.0f,
1658 0.0f, 0.0f, 0.0f, 1.0f) * cdata->_film_mat;
1661 if ((cdata->_user_flags & UF_custom_film_mat) != 0) {
1662 cdata->_film_mat = cdata->_film_mat * cdata->_custom_film_mat;
1665 do_adjust_comp_flags(cdata, CF_film_mat_inv, CF_film_mat);
1675 do_compute_lens_mat(CData *cdata) {
1676 if ((cdata->_user_flags & UF_view_mat) == 0) {
1677 if ((cdata->_user_flags & UF_view_hpr) != 0) {
1678 compose_matrix(cdata->_lens_mat,
1682 LVecBase3(0.0f, 0.0f, 0.0f), cdata->_cs);
1684 }
else if ((cdata->_user_flags & UF_view_vector) != 0) {
1685 look_at(cdata->_lens_mat, cdata->_view_vector, cdata->_up_vector, cdata->_cs);
1691 do_adjust_comp_flags(cdata, CF_lens_mat_inv, CF_lens_mat);
1704 fov_to_film(PN_stdfloat, PN_stdfloat,
bool)
const {
1718 fov_to_focal_length(PN_stdfloat, PN_stdfloat,
bool)
const {
1732 film_to_fov(PN_stdfloat, PN_stdfloat,
bool)
const {
1751 do_resequence_fov_triad(
const CData *cdata,
char &newest,
char &older_a,
char &older_b)
const {
1752 nassertv(newest + older_a + older_b == 3);
1758 nassertv(older_a + older_b == 1);
1764 nassertv(older_b == 0);
1767 nassertv(older_a == 0 && older_b == 2);
1773 nassertv(older_a + older_b == 1);
1778 <<
"Invalid fov sequence numbers in lens: "
1779 << (int)newest <<
", " << (
int)older_a <<
", " << (int)older_b <<
"\n";
1784 if (gobj_cat.is_debug()) {
1786 <<
"Lens.do_resequence_fov_triad():";
1787 for (
int i = 2; i >= 0; --i) {
1788 if (cdata->_fov_seq == i) {
1789 gobj_cat.debug(
false)
1791 }
else if (cdata->_focal_length_seq == i) {
1792 gobj_cat.debug(
false)
1794 }
else if (cdata->_film_size_seq == i) {
1795 gobj_cat.debug(
false)
1799 gobj_cat.debug(
false)
1815 do_define_geom_data(CData *cdata) {
1816 int num_segments = 1;
1818 num_segments = lens_geom_segments;
1823 (
"lens", GeomVertexFormat::get_v3(),
1826 cdata->_geom_data->unclean_set_num_rows(num_segments * 8 + 2);
1829 LPoint3 near_point, far_point;
1830 for (
int si = 0; si < num_segments; si++) {
1831 PN_stdfloat t = 2.0f * (PN_stdfloat)si / (PN_stdfloat)num_segments;
1834 LPoint3 p1(-1.0f + t, 1.0f, 0.0f);
1835 if (!do_extrude(cdata, p1, near_point, far_point)) {
1839 vertex.set_data3(near_point);
1840 vertex.set_data3(far_point);
1843 LPoint3 p2(1.0f, 1.0f - t, 0.0f);
1844 if (!do_extrude(cdata, p2, near_point, far_point)) {
1848 vertex.set_data3(near_point);
1849 vertex.set_data3(far_point);
1852 LPoint3 p3(1.0f - t, -1.0f, 0.0f);
1853 if (!do_extrude(cdata, p3, near_point, far_point)) {
1857 vertex.set_data3(near_point);
1858 vertex.set_data3(far_point);
1861 LPoint3 p4(-1.0f, -1.0f + t, 0.0f);
1862 if (!do_extrude(cdata, p4, near_point, far_point)) {
1866 vertex.set_data3(near_point);
1867 vertex.set_data3(far_point);
1874 if (!do_extrude(cdata, pc, near_point, far_point)) {
1875 vertex.set_data3(0.0f, 0.0f, 0.0f);
1876 vertex.set_data3(0.0f, 0.0f, 0.0f);
1878 vertex.set_data3(near_point);
1879 vertex.set_data3(far_point);
1882 return num_segments;
1893 build_shear_mat(
LMatrix4 &shear_mat,
1904 PN_stdfloat max_edge_length = -1.0f;
1906 for (
int i = 0; i < 4; i++) {
1907 LVector3 edge = points[(i + 1) % 4] - points[i];
1909 if (length > max_edge_length) {
1911 max_edge_length = length;
1915 const LPoint3 &base_origin = points[base_edge];
1916 LVector3 base_vec = points[(base_edge + 1) % 4] - base_origin;
1918 PN_stdfloat base_edge_length = csqrt(max_edge_length);
1923 int a = (base_edge + 2) % 4;
1924 int b = (base_edge + 3) % 4;
1926 PN_stdfloat a_dist = sqr_dist_to_line(points[a], base_origin, base_vec);
1927 PN_stdfloat b_dist = sqr_dist_to_line(points[b], base_origin, base_vec);
1931 if (a_dist > b_dist) {
1933 dist = csqrt(a_dist);
1936 dist = csqrt(b_dist);
1944 LPoint3 parallel_origin = points[base_edge] + perpendic;
1948 LVector3 base_norm_vec = base_vec / base_edge_length;
1950 LVector3 far_point_delta = points[far_point] - parallel_origin;
1951 PN_stdfloat far_point_pos = far_point_delta.dot(base_norm_vec);
1953 if (far_point_pos < 0.0f) {
1955 parallel_origin += base_norm_vec * far_point_pos;
1957 }
else if (far_point_pos > base_edge_length) {
1960 parallel_origin += base_norm_vec * (far_point_pos - base_edge_length);
1965 PN_stdfloat Ox = parallel_origin[0];
1966 PN_stdfloat Oy = parallel_origin[2];
1967 PN_stdfloat Vx = base_vec[0];
1968 PN_stdfloat Vy = base_vec[2];
1969 PN_stdfloat Ax, Ay, Bx, By;
1971 if (far_point == a) {
1973 LVector3 v = points[b] - base_origin;
1980 LVector3 v = points[a] - (base_origin + base_vec);
1986 t = ((Ox - Ax) * By + (Ay - Oy) * Bx) / (Bx * Vy - By * Vx);
1991 parallel_origin += base_vec * t;
1992 }
else if (t > 1.0f) {
1995 parallel_origin += base_vec * (1.0f - t);
1998 LVector3 adjacent_norm_vec = parallel_origin - base_origin;
2006 switch (base_edge) {
2010 shear_mat.
set_row(0, base_norm_vec);
2011 shear_mat.
set_row(2, -adjacent_norm_vec);
2017 shear_mat.
set_row(0, -adjacent_norm_vec);
2018 shear_mat.
set_row(2, -base_norm_vec);
2024 shear_mat.
set_row(0, -base_norm_vec);
2025 shear_mat.
set_row(2, adjacent_norm_vec);
2031 shear_mat.
set_row(0, adjacent_norm_vec);
2032 shear_mat.
set_row(2, base_norm_vec);
2054 PN_stdfloat leg = d.dot(norm);
2055 return hyp_2 - leg * leg;
2099 CData(
const Lens::CData ©) {
2100 _change_event = copy._change_event;
2102 _film_size = copy._film_size;
2103 _film_offset = copy._film_offset;
2104 _focal_length = copy._focal_length;
2106 _min_fov = copy._min_fov;
2107 _aspect_ratio = copy._aspect_ratio;
2108 _near_distance = copy._near_distance;
2109 _far_distance = copy._far_distance;
2111 _view_hpr = copy._view_hpr;
2112 _view_vector = copy._view_vector;
2113 _interocular_distance = copy._interocular_distance;
2114 _convergence_distance = copy._convergence_distance;
2115 _keystone = copy._keystone;
2120 _lens_mat = copy._lens_mat;
2122 _user_flags = copy._user_flags;
2125 _focal_length_seq = copy._focal_length_seq;
2126 _fov_seq = copy._fov_seq;
2127 _film_size_seq = copy._film_size_seq;
2129 _geom_data = copy._geom_data;
2139 return new CData(*
this);
2152 _film_size.write_datagram(dg);
2153 _film_offset.write_datagram(dg);
2155 _fov.write_datagram(dg);
2172 _cs = (CoordinateSystem)scan.
get_uint8();
2173 _film_size.read_datagram(scan);
2174 _film_offset.read_datagram(scan);
2176 _fov.read_datagram(scan);
2194 _film_size.set(1.0f, 1.0f);
2195 _film_offset.set(0.0f, 0.0f);
2196 _focal_length = 1.0f;
2197 _fov.set(default_fov, default_fov);
2198 _aspect_ratio = 1.0f;
2199 _near_distance = default_near;
2200 _far_distance = default_far;
2201 _view_hpr.set(0.0f, 0.0f, 0.0f);
2202 _view_vector.set(0.0f, 1.0f, 0.0f);
2203 _up_vector.set(0.0f, 0.0f, 1.0f);
2204 _keystone.set(0.0f, 0.0f);
2208 _comp_flags = CF_fov;
2210 _interocular_distance = 0.0;
2211 _convergence_distance = 0.0;
2214 _keystone.set(default_keystone[0], default_keystone[1]);
2215 _user_flags |= UF_keystone;
2220 _focal_length_seq = 1;
bool invert_affine_from(const LMatrix4f &other)
Performs an invert of the indicated matrix, storing the result in this matrix.
static const LMatrix4f & ident_mat()
Returns an identity matrix.
This object provides a high-level interface for quickly writing a sequence of numeric values from a v...
void set_keystone(const LVecBase2 &keystone)
Indicates the ratio of keystone correction to perform on the lens, in each of three axes...
void add_uint8(PN_uint8 value)
Adds an unsigned 8-bit integer to the datagram.
This is the base class for all three-component vectors and points.
virtual bool is_orthographic() const
Returns true if the lens represents a orthographic projection (i.e.
void add_string(const string &str)
Adds a variable-length string to the datagram.
PN_stdfloat get_stdfloat()
Extracts either a 32-bit or a 64-bit floating-point number, according to Datagram::set_stdfloat_doubl...
A base class for any number of different kinds of lenses, linear and otherwise.
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
void read_cdata(DatagramIterator &scan, PipelineCyclerBase &cycler)
Reads in the indicated CycleData object.
const LVecBase3 & get_view_hpr() const
Returns the direction in which the lens is facing.
void clear()
Resets all lens parameters to their initial default settings.
const LVector3 & get_view_vector() const
Returns the axis along which the lens is facing.
A single page of data maintained by a PipelineCycler.
bool is_nan() const
Returns true if any component of the vector is not-a-number, false otherwise.
void write_cdata(Datagram &packet, const PipelineCyclerBase &cycler)
Writes out the indicated CycleData object.
void set_coordinate_system(CoordinateSystem cs)
Specifies the coordinate system that all 3-d computations are performed within for this Lens...
float length_squared() const
Returns the square of the vector's length, cheap and easy.
bool has_value() const
Returns true if this variable has an explicit value, either from a prc file or locally set...
const LMatrix4 & get_view_mat() const
Returns the direction in which the lens is facing.
This is a three-component vector distance (as opposed to a three-component point, which represents a ...
const LVecBase2 & get_fov() const
Returns the horizontal and vertical film size of the virtual film.
This is a three-component point in space (as opposed to a three-component vector, which represents a ...
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
PN_uint8 get_uint8()
Extracts an unsigned 8-bit integer.
bool is_nan() const
Returns true if any component of the vector is not-a-number, false otherwise.
static const LMatrix4f & convert_mat(CoordinateSystem from, CoordinateSystem to)
Returns a matrix that transforms from the indicated coordinate system to the indicated coordinate sys...
const LVector3 & get_up_vector() const
Returns the axis perpendicular to the camera's view vector that indicates the "up" direction...
string get_string()
Extracts a variable-length string.
virtual void fillin(DatagramIterator &scan, BamReader *manager)
This internal function is intended to be called by each class's make_from_bam() method to read in all...
PN_uint16 get_uint16()
Extracts an unsigned 16-bit integer.
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
static PN_stdfloat get_default_far()
Returns the default far plane distance that will be assigned to each newly-created lens...
This template class calls PipelineCycler::read_unlocked(), and then provides a transparent read-only ...
static LVector3f forward(CoordinateSystem cs=CS_default)
Returns the forward vector for the given coordinate system.
const CycleDataType * p() const
This allows the CycleDataReader to be passed to any function that expects a const CycleDataType point...
void add_stdfloat(PN_stdfloat value)
Adds either a 32-bit or a 64-bit floating-point number, according to set_stdfloat_double().
virtual bool is_perspective() const
Returns true if the lens represents a perspective projection (i.e.
bool extrude(const LPoint2 &point2d, LPoint3 &near_point, LPoint3 &far_point) const
Given a 2-d point in the range (-1,1) in both dimensions, where (0,0) is the center of the lens and (...
This is an abstract class for any volume in any sense which can be said to define the locality of ref...
void set_frustum_from_corners(const LVecBase3 &ul, const LVecBase3 &ur, const LVecBase3 &ll, const LVecBase3 &lr, int flags)
Sets up the lens to use the frustum defined by the four indicated points.
void set_view_hpr(PN_stdfloat h, PN_stdfloat p, PN_stdfloat r)
Sets the direction in which the lens is facing.
virtual bool is_linear() const
Returns true if the lens represents a linear projection (e.g.
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
This is a 4-by-4 transform matrix.
void set_min_fov(PN_stdfloat min_fov)
Sets the field of view of the smallest dimension of the window.
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
A container for geometry primitives.
bool invert_from(const LMatrix4f &other)
Computes the inverse of the other matrix, and stores the result in this matrix.
This is the base class for all two-component vectors and points.
static PN_stdfloat get_default_near()
Returns the default near plane distance that will be assigned to each newly-created lens...
This template class calls PipelineCycler::write() in the constructor and PipelineCycler::release_writ...
LVecBase3f xform_point_general(const LVecBase3f &v) const
The matrix transforms a 3-component point (including translation component) and returns the result...
void add_uint16(PN_uint16 value)
Adds an unsigned 16-bit integer to the datagram.
This is the base class for all three-component vectors and points.
LVecBase4f xform(const LVecBase4f &v) const
4-component vector or point times matrix.
This is a two-component vector offset.
Defines a series of line strips.
void recompute_all()
Forces all internal parameters of the Lens to be recomputed.
void clear_keystone()
Disables the lens keystone correction.
void set_row(int row, const LVecBase4f &v)
Replaces the indicated row of the matrix.
LVecBase3f get_row3(int row) const
Retrieves the row column of the matrix as a 3-component vector, ignoring the last column...
A class to retrieve the individual data elements previously stored in a Datagram. ...
TypeHandle is the identifier used to differentiate C++ class types.
PN_stdfloat get_min_fov() const
Returns the field of view of the narrowest dimension of the window.
bool normalize()
Normalizes the vector in place.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
LPoint3 get_nodal_point() const
Returns the center point of the lens: the point from which the lens is viewing.
void set_view_vector(PN_stdfloat x, PN_stdfloat y, PN_stdfloat z, PN_stdfloat i, PN_stdfloat j, PN_stdfloat k)
Specifies the direction in which the lens is facing by giving an axis to look along, and a perpendicular (or at least non-parallel) up axis.
void clear_custom_film_mat()
Disables the lens custom_film_mat correction.
static LVector3f up(CoordinateSystem cs=CS_default)
Returns the up vector for the given coordinate system.
bool is_nan() const
Returns true if any component of the matrix is not-a-number, false otherwise.
This defines a bounding convex hexahedron.
LVecBase3f xform_point(const LVecBase3f &v) const
The matrix transforms a 3-component point (including translation component) and returns the result...
void set_custom_film_mat(const LMatrix4 &custom_film_mat)
Specifies a custom matrix to transform the points on the film after they have been converted into nom...
void clear_view_mat()
Resets the lens transform to identity.