86
85
/* for ndof prints */
87
86
// #define DEBUG_NDOF_MOTION
88
static void view3d_offset_lock_report(ReportList *reports)
90
BKE_report(reports, RPT_WARNING, "View offset is locked");
93
bool ED_view3d_offset_lock_check(struct View3D *v3d, struct RegionView3D *rv3d)
95
return (rv3d->persp != RV3D_CAMOB) && (v3d->ob_centre_cursor || v3d->ob_centre);
98
#define VIEW3D_OP_OFS_LOCK_TEST(C, op) \
100
View3D *v3d_tmp = CTX_wm_view3d(C); \
101
RegionView3D *rv3d_tmp = CTX_wm_region_view3d(C); \
102
if (ED_view3d_offset_lock_check(v3d_tmp, rv3d_tmp)) { \
103
view3d_offset_lock_report((op)->reports); \
104
return OPERATOR_CANCELLED; \
89
109
/* ********************** view3d_edit: view manipulations ********************* */
91
int ED_view3d_camera_lock_check(View3D *v3d, RegionView3D *rv3d)
111
bool ED_view3d_camera_lock_check(View3D *v3d, RegionView3D *rv3d)
93
113
return ((v3d->camera) &&
94
114
(v3d->camera->id.lib == NULL) &&
125
147
ED_view3d_to_m4(view_mat, rv3d->ofs, rv3d->viewquat, rv3d->dist);
127
invert_m4_m4(v3d->camera->imat, v3d->camera->obmat);
128
mult_m4_m4m4(diff_mat, view_mat, v3d->camera->imat);
130
mult_m4_m4m4(parent_mat, diff_mat, root_parent->obmat);
149
normalize_m4_m4(tmat, v3d->camera->obmat);
151
invert_m4_m4(imat, tmat);
152
mul_m4_m4m4(diff_mat, view_mat, imat);
154
mul_m4_m4m4(parent_mat, diff_mat, root_parent->obmat);
132
156
BKE_object_tfm_protected_backup(root_parent, &obtfm);
133
BKE_object_apply_mat4(root_parent, parent_mat, TRUE, FALSE);
157
BKE_object_apply_mat4(root_parent, parent_mat, true, false);
134
158
BKE_object_tfm_protected_restore(root_parent, &obtfm, root_parent->protectflag);
136
160
ob_update = v3d->camera;
168
/* always maintain the same scale */
169
const short protect_scale_all = (OB_LOCK_SCALEX | OB_LOCK_SCALEY | OB_LOCK_SCALEZ);
144
170
BKE_object_tfm_protected_backup(v3d->camera, &obtfm);
145
171
ED_view3d_to_object(v3d->camera, rv3d->ofs, rv3d->viewquat, rv3d->dist);
146
BKE_object_tfm_protected_restore(v3d->camera, &obtfm, v3d->camera->protectflag);
172
BKE_object_tfm_protected_restore(v3d->camera, &obtfm, v3d->camera->protectflag | protect_scale_all);
148
174
DAG_id_tag_update(&v3d->camera->id, OB_RECALC_OB);
149
175
WM_main_add_notifier(NC_OBJECT | ND_TRANSFORM, v3d->camera);
365
391
float viewquat[4]; /* working copy of rv3d->viewquat */
366
392
float trackvec[3];
367
393
float mousevec[3]; /* dolly only */
368
float reverse, dist0, camzoom0;
395
float dist_prev, camzoom_prev;
370
short axis_snap; /* view rotate only */
397
bool axis_snap; /* view rotate only */
372
400
/* use for orbit selection and auto-dist */
373
401
float ofs[3], dyn_ofs[3];
376
404
int origx, origy, oldx, oldy;
377
405
int origkey; /* the key that triggered the operator */
424
452
* we may want to make this optional but for now its needed always */
425
453
ED_view3d_camera_lock_init(vod->v3d, vod->rv3d);
427
vod->dist0 = rv3d->dist;
428
vod->camzoom0 = rv3d->camzoom;
455
vod->dist_prev = rv3d->dist;
456
vod->camzoom_prev = rv3d->camzoom;
429
457
copy_qt_qt(vod->viewquat, rv3d->viewquat);
430
458
copy_qt_qt(vod->oldquat, rv3d->viewquat);
431
459
vod->origx = vod->oldx = event->x;
432
460
vod->origy = vod->oldy = event->y;
433
461
vod->origkey = event->type; /* the key that triggered the operator. */
434
vod->use_dyn_ofs = (U.uiflag & USER_ORBIT_SELECTION) ? 1 : 0;
462
vod->use_dyn_ofs = (U.uiflag & USER_ORBIT_SELECTION) != 0;
435
463
copy_v3_v3(vod->ofs, rv3d->ofs);
437
465
if (vod->use_dyn_ofs) {
438
466
Scene *scene = CTX_data_scene(C);
439
467
Object *ob = OBACT;
441
if (ob && ob->mode & OB_MODE_ALL_PAINT) {
442
/* transformation is disabled for painting modes, which will make it
443
* so previous offset is used. This is annoying when you open file
444
* saved with active object in painting mode
469
if (ob && (ob->mode & OB_MODE_ALL_PAINT) && (BKE_object_pose_armature_get(ob) == NULL)) {
470
/* in case of sculpting use last average stroke position as a rotation
471
* center, in other cases it's not clear what rotation center shall be
472
* so just rotate around object origin
446
copy_v3_v3(lastofs, ob->obmat[3]);
474
if (ob->mode & OB_MODE_SCULPT) {
476
ED_sculpt_get_average_stroke(ob, stroke);
477
copy_v3_v3(lastofs, stroke);
480
copy_v3_v3(lastofs, ob->obmat[3]);
449
484
/* If there's no selection, lastofs is unmodified and last value since static */
453
488
negate_v3_v3(vod->dyn_ofs, lastofs);
455
490
else if (U.uiflag & USER_ZBUF_ORBIT) {
491
Scene *scene = CTX_data_scene(C);
457
493
view3d_operator_needs_opengl(C); /* needed for zbuf drawing */
459
if ((vod->use_dyn_ofs = ED_view3d_autodist(CTX_data_scene(C), vod->ar, vod->v3d, event->mval, vod->dyn_ofs))) {
495
if ((vod->use_dyn_ofs = ED_view3d_autodist(scene, vod->ar, vod->v3d, event->mval, vod->dyn_ofs, true))) {
460
496
if (rv3d->is_persp) {
461
497
float my_origin[3]; /* original G.vd->ofs */
462
498
float my_pivot[3]; /* view */
505
541
calctrackballvec(&vod->ar->winrct, event->x, event->y, vod->trackvec);
507
initgrabz(rv3d, -rv3d->ofs[0], -rv3d->ofs[1], -rv3d->ofs[2]);
545
negate_v3_v3(tvec, rv3d->ofs);
546
vod->zfac = ED_view3d_calc_zfac(rv3d, tvec, NULL);
509
549
vod->reverse = 1.0f;
510
550
if (rv3d->persmat[2][1] < 0.0f)
996
1036
/* NDOF utility functions
997
1037
* (should these functions live in this file?)
999
float ndof_to_axis_angle(struct wmNDOFMotionData *ndof, float axis[3])
1039
float ndof_to_axis_angle(const struct wmNDOFMotionData *ndof, float axis[3])
1001
1041
return ndof->dt * normalize_v3_v3(axis, ndof->rvec);
1004
void ndof_to_quat(struct wmNDOFMotionData *ndof, float q[4])
1044
void ndof_to_quat(const struct wmNDOFMotionData *ndof, float q[4])
1010
1050
axis_angle_to_quat(q, axis, angle);
1053
static void view3d_ndof_orbit(const struct wmNDOFMotionData *ndof, RegionView3D *rv3d, const float view_inv[4],
1054
const float rot_sensitivity, const float dt,
1055
/* optional, can be NULL*/
1058
if (U.ndof_flag & NDOF_TURNTABLE) {
1060
/* turntable view code by John Aughey, adapted for 3D mouse by [mce] */
1061
float angle, rot[4];
1062
float xvec[3] = {1, 0, 0};
1064
/* Determine the direction of the x vector (for rotating up and down) */
1065
mul_qt_v3(view_inv, xvec);
1067
/* Perform the up/down rotation */
1068
angle = rot_sensitivity * dt * ndof->rx;
1069
if (U.ndof_flag & NDOF_TILT_INVERT_AXIS)
1071
rot[0] = cosf(angle);
1072
mul_v3_v3fl(rot + 1, xvec, sin(angle));
1073
mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rot);
1075
/* Perform the orbital rotation */
1076
angle = rot_sensitivity * dt * ndof->ry;
1077
if (U.ndof_flag & NDOF_ROTATE_INVERT_AXIS)
1080
/* update the onscreen doo-dad */
1081
rv3d->rot_angle = angle;
1082
rv3d->rot_axis[0] = 0;
1083
rv3d->rot_axis[1] = 0;
1084
rv3d->rot_axis[2] = 1;
1086
rot[0] = cosf(angle);
1087
rot[1] = rot[2] = 0.0;
1088
rot[3] = sinf(angle);
1089
mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rot);
1095
float angle = rot_sensitivity * ndof_to_axis_angle(ndof, axis);
1097
if (U.ndof_flag & NDOF_ROLL_INVERT_AXIS) axis[2] = -axis[2];
1098
if (U.ndof_flag & NDOF_TILT_INVERT_AXIS) axis[0] = -axis[0];
1099
if (U.ndof_flag & NDOF_ROTATE_INVERT_AXIS) axis[1] = -axis[1];
1102
/* transform rotation axis from view to world coordinates */
1103
mul_qt_v3(view_inv, axis);
1105
/* update the onscreen doo-dad */
1106
rv3d->rot_angle = angle;
1107
copy_v3_v3(rv3d->rot_axis, axis);
1109
axis_angle_to_quat(rot, axis, angle);
1111
/* apply rotation */
1112
mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rot);
1115
/* rotate around custom center */
1116
if (vod && vod->use_dyn_ofs) {
1119
/* compute the post multiplication quat, to rotate the offset correctly */
1120
conjugate_qt_qt(q1, vod->oldquat);
1121
mul_qt_qtqt(q1, q1, rv3d->viewquat);
1123
conjugate_qt(q1); /* conj == inv for unit quat */
1124
copy_v3_v3(rv3d->ofs, vod->ofs);
1125
sub_v3_v3(rv3d->ofs, vod->dyn_ofs);
1126
mul_qt_v3(q1, rv3d->ofs);
1127
add_v3_v3(rv3d->ofs, vod->dyn_ofs);
1013
1131
/* -- "orbit" navigation (trackball/turntable)
1015
1133
* -- panning in rotationally-locked views
1017
static int ndof_orbit_invoke(bContext *C, wmOperator *op, wmEvent *event)
1135
static int ndof_orbit_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1020
1138
if (event->type != NDOF_MOTION)
1067
1185
if (has_rotation) {
1069
1186
rv3d->view = RV3D_VIEW_USER;
1071
if (U.ndof_flag & NDOF_TURNTABLE) {
1073
/* turntable view code by John Aughey, adapted for 3D mouse by [mce] */
1074
float angle, rot[4];
1075
float xvec[3] = {1, 0, 0};
1077
/* Determine the direction of the x vector (for rotating up and down) */
1078
mul_qt_v3(view_inv, xvec);
1080
/* Perform the up/down rotation */
1081
angle = rot_sensitivity * dt * ndof->rx;
1082
if (U.ndof_flag & NDOF_TILT_INVERT_AXIS)
1084
rot[0] = cos(angle);
1085
mul_v3_v3fl(rot + 1, xvec, sin(angle));
1086
mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rot);
1088
/* Perform the orbital rotation */
1089
angle = rot_sensitivity * dt * ndof->ry;
1090
if (U.ndof_flag & NDOF_ROTATE_INVERT_AXIS)
1093
/* update the onscreen doo-dad */
1094
rv3d->rot_angle = angle;
1095
rv3d->rot_axis[0] = 0;
1096
rv3d->rot_axis[1] = 0;
1097
rv3d->rot_axis[2] = 1;
1099
rot[0] = cos(angle);
1100
rot[1] = rot[2] = 0.0;
1101
rot[3] = sin(angle);
1102
mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rot);
1108
float angle = rot_sensitivity * ndof_to_axis_angle(ndof, axis);
1110
if (U.ndof_flag & NDOF_ROLL_INVERT_AXIS)
1113
if (U.ndof_flag & NDOF_TILT_INVERT_AXIS)
1116
if (U.ndof_flag & NDOF_ROTATE_INVERT_AXIS)
1120
/* transform rotation axis from view to world coordinates */
1121
mul_qt_v3(view_inv, axis);
1123
/* update the onscreen doo-dad */
1124
rv3d->rot_angle = angle;
1125
copy_v3_v3(rv3d->rot_axis, axis);
1127
axis_angle_to_quat(rot, axis, angle);
1129
/* apply rotation */
1130
mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rot);
1134
/* rotate around custom center */
1135
if (vod && vod->use_dyn_ofs) {
1138
/* compute the post multiplication quat, to rotate the offset correctly */
1139
conjugate_qt_qt(q1, vod->oldquat);
1140
mul_qt_qtqt(q1, q1, rv3d->viewquat);
1142
conjugate_qt(q1); /* conj == inv for unit quat */
1143
copy_v3_v3(rv3d->ofs, vod->ofs);
1144
sub_v3_v3(rv3d->ofs, vod->dyn_ofs);
1145
mul_qt_v3(q1, rv3d->ofs);
1146
add_v3_v3(rv3d->ofs, vod->dyn_ofs);
1187
view3d_ndof_orbit(ndof, rv3d, view_inv, rot_sensitivity, dt, vod);
1241
1281
if (has_rotation) {
1243
1282
rv3d->view = RV3D_VIEW_USER;
1245
if (U.ndof_flag & NDOF_TURNTABLE) {
1247
/* turntable view code by John Aughey, adapted for 3D mouse by [mce] */
1248
float angle, rot[4];
1249
float xvec[3] = {1, 0, 0};
1251
/* Determine the direction of the x vector (for rotating up and down) */
1252
mul_qt_v3(view_inv, xvec);
1254
/* Perform the up/down rotation */
1255
angle = rot_sensitivity * dt * ndof->rx;
1256
if (U.ndof_flag & NDOF_TILT_INVERT_AXIS)
1258
rot[0] = cos(angle);
1259
mul_v3_v3fl(rot + 1, xvec, sin(angle));
1260
mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rot);
1262
/* Perform the orbital rotation */
1263
angle = rot_sensitivity * dt * ndof->ry;
1264
if (U.ndof_flag & NDOF_ROTATE_INVERT_AXIS)
1267
/* update the onscreen doo-dad */
1268
rv3d->rot_angle = angle;
1269
rv3d->rot_axis[0] = 0;
1270
rv3d->rot_axis[1] = 0;
1271
rv3d->rot_axis[2] = 1;
1273
rot[0] = cos(angle);
1274
rot[1] = rot[2] = 0.0;
1275
rot[3] = sin(angle);
1276
mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rot);
1282
float angle = rot_sensitivity * ndof_to_axis_angle(ndof, axis);
1284
if (U.ndof_flag & NDOF_ROLL_INVERT_AXIS)
1287
if (U.ndof_flag & NDOF_TILT_INVERT_AXIS)
1290
if (U.ndof_flag & NDOF_ROTATE_INVERT_AXIS)
1294
/* transform rotation axis from view to world coordinates */
1295
mul_qt_v3(view_inv, axis);
1297
/* update the onscreen doo-dad */
1298
rv3d->rot_angle = angle;
1299
copy_v3_v3(rv3d->rot_axis, axis);
1301
axis_angle_to_quat(rot, axis, angle);
1303
/* apply rotation */
1304
mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rot);
1308
/* rotate around custom center */
1309
if (vod && vod->use_dyn_ofs) {
1312
/* compute the post multiplication quat, to rotate the offset correctly */
1313
conjugate_qt_qt(q1, vod->oldquat);
1314
mul_qt_qtqt(q1, q1, rv3d->viewquat);
1316
conjugate_qt(q1); /* conj == inv for unit quat */
1317
copy_v3_v3(rv3d->ofs, vod->ofs);
1318
sub_v3_v3(rv3d->ofs, vod->dyn_ofs);
1319
mul_qt_v3(q1, rv3d->ofs);
1320
add_v3_v3(rv3d->ofs, vod->dyn_ofs);
1283
view3d_ndof_orbit(ndof, rv3d, view_inv, rot_sensitivity, dt, vod);
1503
1467
/* move center of view opposite of hand motion (this is camera mode, not object mode) */
1504
1468
sub_v3_v3(rv3d->ofs, pan_vec);
1506
if (U.ndof_flag & NDOF_TURNTABLE) {
1507
/* turntable view code by John Aughey, adapted for 3D mouse by [mce] */
1508
float angle, rot[4];
1509
float xvec[3] = {1, 0, 0};
1511
/* Determine the direction of the x vector (for rotating up and down) */
1512
mul_qt_v3(view_inv, xvec);
1514
/* Perform the up/down rotation */
1515
angle = rot_sensitivity * dt * ndof->rx;
1516
if (U.ndof_flag & NDOF_TILT_INVERT_AXIS)
1518
rot[0] = cos(angle);
1519
mul_v3_v3fl(rot + 1, xvec, sin(angle));
1520
mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rot);
1522
/* Perform the orbital rotation */
1523
angle = rot_sensitivity * dt * ndof->ry;
1524
if (U.ndof_flag & NDOF_ROTATE_INVERT_AXIS)
1527
/* update the onscreen doo-dad */
1528
rv3d->rot_angle = angle;
1529
rv3d->rot_axis[0] = 0;
1530
rv3d->rot_axis[1] = 0;
1531
rv3d->rot_axis[2] = 1;
1533
rot[0] = cos(angle);
1534
rot[1] = rot[2] = 0.0;
1535
rot[3] = sin(angle);
1536
mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rot);
1543
float angle = rot_sensitivity * ndof_to_axis_angle(ndof, axis);
1545
if (U.ndof_flag & NDOF_ROLL_INVERT_AXIS)
1548
if (U.ndof_flag & NDOF_TILT_INVERT_AXIS)
1551
if (U.ndof_flag & NDOF_ROTATE_INVERT_AXIS)
1554
/* transform rotation axis from view to world coordinates */
1555
mul_qt_v3(view_inv, axis);
1557
/* update the onscreen doo-dad */
1558
rv3d->rot_angle = angle;
1559
copy_v3_v3(rv3d->rot_axis, axis);
1561
axis_angle_to_quat(rot, axis, angle);
1563
/* apply rotation */
1564
mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rot);
1568
/* rotate around custom center */
1569
if (vod->use_dyn_ofs) {
1572
/* compute the post multiplication quat, to rotate the offset correctly */
1573
conjugate_qt_qt(q1, vod->oldquat);
1574
mul_qt_qtqt(q1, q1, rv3d->viewquat);
1576
conjugate_qt(q1); /* conj == inv for unit quat */
1577
copy_v3_v3(rv3d->ofs, vod->ofs);
1578
sub_v3_v3(rv3d->ofs, vod->dyn_ofs);
1579
mul_qt_v3(q1, rv3d->ofs);
1580
add_v3_v3(rv3d->ofs, vod->dyn_ofs);
1470
view3d_ndof_orbit(ndof, rv3d, view_inv, rot_sensitivity, dt, vod);
1585
1473
viewops_data_free(C, op);
1722
1610
return OPERATOR_RUNNING_MODAL;
1725
static int viewmove_invoke(bContext *C, wmOperator *op, wmEvent *event)
1613
static int viewmove_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1727
1615
ViewOpsData *vod;
1617
VIEW3D_OP_OFS_LOCK_TEST(C, op);
1729
1619
/* makes op->customdata */
1730
1620
viewops_data_create(C, op, event);
1731
1621
vod = op->customdata;
1820
1710
float mval_f[2];
1821
1711
float new_dist;
1823
1714
negate_v3_v3(tpos, rv3d->ofs);
1825
/* Project cursor position into 3D space */
1826
initgrabz(rv3d, tpos[0], tpos[1], tpos[2]);
1828
1716
mval_f[0] = (float)(((mx - ar->winrct.xmin) * 2) - ar->winx) / 2.0f;
1829
1717
mval_f[1] = (float)(((my - ar->winrct.ymin) * 2) - ar->winy) / 2.0f;
1830
ED_view3d_win_to_delta(ar, mval_f, dvec);
1719
/* Project cursor position into 3D space */
1720
zfac = ED_view3d_calc_zfac(rv3d, tpos, NULL);
1721
ED_view3d_win_to_delta(ar, mval_f, dvec, zfac);
1832
1723
/* Calculate view target position for dolly */
1833
1724
add_v3_v3v3(tvec, tpos, dvec);
1851
1742
static void viewzoom_apply(ViewOpsData *vod, const int x, const int y, const short viewzoom, const short zoom_invert)
1853
1744
float zfac = 1.0;
1856
1747
use_cam_zoom = (vod->rv3d->persp == RV3D_CAMOB) && !(vod->rv3d->is_persp && ED_view3d_camera_lock_check(vod->v3d, vod->rv3d));
1858
1749
if (use_cam_zoom) {
1860
1751
delta = (x - vod->origx + y - vod->origy) / 10.0f;
1861
vod->rv3d->camzoom = vod->camzoom0 + (zoom_invert ? -delta : delta);
1752
vod->rv3d->camzoom = vod->camzoom_prev + (zoom_invert ? -delta : delta);
1863
1754
CLAMP(vod->rv3d->camzoom, RV3D_CAMZOOM_MIN, RV3D_CAMZOOM_MAX);
2301
2192
/* copied from viewzoom_invoke(), changes here may apply there */
2302
static int viewdolly_invoke(bContext *C, wmOperator *op, wmEvent *event)
2193
static int viewdolly_invoke(bContext *C, wmOperator *op, const wmEvent *event)
2304
2195
ViewOpsData *vod;
2197
VIEW3D_OP_OFS_LOCK_TEST(C, op);
2306
2199
/* makes op->customdata */
2307
2200
viewops_data_create(C, op, event);
2308
2201
vod = op->customdata;
2498
2391
Scene *scene = CTX_data_scene(C);
2501
const short use_all_regions = RNA_boolean_get(op->ptr, "use_all_regions");
2502
const short skip_camera = (ED_view3d_camera_lock_check(v3d, ar->regiondata) ||
2503
/* any one of the regions may be locked */
2504
(use_all_regions && v3d->flag2 & V3D_LOCK_CAMERA));
2505
int center = RNA_boolean_get(op->ptr, "center");
2394
const bool use_all_regions = RNA_boolean_get(op->ptr, "use_all_regions");
2395
const bool skip_camera = (ED_view3d_camera_lock_check(v3d, ar->regiondata) ||
2396
/* any one of the regions may be locked */
2397
(use_all_regions && v3d->flag2 & V3D_LOCK_CAMERA));
2398
const bool center = RNA_boolean_get(op->ptr, "center");
2507
2400
float min[3], max[3];
2508
int ok = 1, onedone = FALSE;
2401
bool change = false;
2511
2404
/* in 2.4x this also move the cursor to (0, 0, 0) (with shift+c). */
2521
2414
for (base = scene->base.first; base; base = base->next) {
2522
2415
if (BASE_VISIBLE(v3d, base)) {
2525
2418
if (skip_camera && base->object == v3d->camera) {
2529
BKE_object_minmax(base->object, min, max, FALSE);
2422
BKE_object_minmax(base->object, min, max, false);
2533
2426
ED_region_tag_redraw(ar);
2534
2427
/* TODO - should this be cancel?
2535
2428
* I think no, because we always move the cursor, with or without
2541
2434
return OPERATOR_FINISHED;
2545
return OPERATOR_FINISHED;
2548
2437
if (use_all_regions) {
2549
view3d_from_minmax_multi(C, v3d, min, max, TRUE);
2438
view3d_from_minmax_multi(C, v3d, min, max, true);
2552
view3d_from_minmax(C, v3d, ar, min, max, TRUE);
2441
view3d_from_minmax(C, v3d, ar, min, max, true);
2555
2444
return OPERATOR_FINISHED;
2586
2475
Object *ob = OBACT;
2587
2476
Object *obedit = CTX_data_edit_object(C);
2588
2477
float min[3], max[3];
2589
int ok = 0, ok_dist = 1;
2590
const short use_all_regions = RNA_boolean_get(op->ptr, "use_all_regions");
2591
const short skip_camera = (ED_view3d_camera_lock_check(v3d, ar->regiondata) ||
2592
/* any one of the regions may be locked */
2593
(use_all_regions && v3d->flag2 & V3D_LOCK_CAMERA));
2478
bool ok = false, ok_dist = true;
2479
const bool use_all_regions = RNA_boolean_get(op->ptr, "use_all_regions");
2480
const bool skip_camera = (ED_view3d_camera_lock_check(v3d, ar->regiondata) ||
2481
/* any one of the regions may be locked */
2482
(use_all_regions && v3d->flag2 & V3D_LOCK_CAMERA));
2595
2484
INIT_MINMAX(min, max);
2655
2544
/* account for duplis */
2656
if (BKE_object_minmax_dupli(scene, base->object, min, max, FALSE) == 0)
2657
BKE_object_minmax(base->object, min, max, FALSE); /* use if duplis not found */
2545
if (BKE_object_minmax_dupli(scene, base->object, min, max, false) == 0)
2546
BKE_object_minmax(base->object, min, max, false); /* use if duplis not found */
2708
static int viewcenter_pick_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
2710
View3D *v3d = CTX_wm_view3d(C);
2711
RegionView3D *rv3d = CTX_wm_region_view3d(C);
2712
Scene *scene = CTX_data_scene(C);
2713
ARegion *ar = CTX_wm_region(C);
2718
view3d_operator_needs_opengl(C);
2720
if (ED_view3d_autodist(scene, ar, v3d, event->mval, new_ofs, false)) {
2724
/* fallback to simple pan */
2725
negate_v3_v3(new_ofs, rv3d->ofs);
2726
ED_view3d_win_to_3d_int(ar, new_ofs, event->mval, new_ofs);
2729
view3d_smooth_view(C, v3d, ar, NULL, NULL, new_ofs, NULL, NULL, NULL);
2732
return OPERATOR_FINISHED;
2735
void VIEW3D_OT_view_center_pick(wmOperatorType *ot)
2738
ot->name = "Center View to Mouse";
2739
ot->description = "Center the view to the Z-depth position under the mouse cursor";
2740
ot->idname = "VIEW3D_OT_view_center_pick";
2743
ot->invoke = viewcenter_pick_invoke;
2744
ot->poll = ED_operator_view3d_active;
2819
2750
static int view3d_center_camera_exec(bContext *C, wmOperator *UNUSED(op)) /* was view3d_home() in 2.4x */
2821
2752
Scene *scene = CTX_data_scene(C);
3113
3044
float mval_f[2];
3114
3047
/* We cant use the depth, fallback to the old way that dosnt set the center depth */
3115
3048
copy_v3_v3(new_ofs, rv3d->ofs);
3117
initgrabz(rv3d, -new_ofs[0], -new_ofs[1], -new_ofs[2]);
3052
negate_v3_v3(tvec, new_ofs);
3053
zfac = ED_view3d_calc_zfac(rv3d, tvec, NULL);
3119
3056
mval_f[0] = (rect.xmin + rect.xmax - vb[0]) / 2.0f;
3120
3057
mval_f[1] = (rect.ymin + rect.ymax - vb[1]) / 2.0f;
3121
ED_view3d_win_to_delta(ar, mval_f, dvec);
3058
ED_view3d_win_to_delta(ar, mval_f, dvec, zfac);
3122
3059
/* center the view to the center of the rectangle */
3123
3060
sub_v3_v3(new_ofs, dvec);
3249
3186
static void axis_set_view(bContext *C, View3D *v3d, ARegion *ar,
3250
3187
float q1, float q2, float q3, float q4,
3251
short view, int perspo, int align_active)
3188
short view, int perspo, bool align_active)
3253
3190
RegionView3D *rv3d = ar->regiondata; /* no NULL check is needed, poll checks */
3254
3191
float new_quat[4];
3262
3199
Object *obact = CTX_data_active_object(C);
3263
3200
if (obact == NULL) {
3264
3201
/* no active object, ignore this option */
3265
align_active = FALSE;
3202
align_active = false;
3205
const float z_flip_quat[4] = {0.0f, 0.0f, 0.0f, 1.0f};
3268
3206
float obact_quat[4];
3269
3207
float twmat[3][3];
3209
/* flip the input, the end result being that an object
3210
* with no rotation behaves as if 'align_active' is off */
3211
mul_qt_qtqt(new_quat, new_quat, z_flip_quat);
3271
3213
/* same as transform manipulator when normal is set */
3272
ED_getTransformOrientationMatrix(C, twmat, FALSE);
3214
ED_getTransformOrientationMatrix(C, twmat, false);
3274
3216
mat3_to_quat(obact_quat, twmat);
3275
3217
invert_qt(obact_quat);
3567
3510
static int viewpan_exec(bContext *C, wmOperator *op)
3512
ScrArea *sa = CTX_wm_area(C);
3569
3513
ARegion *ar = CTX_wm_region(C);
3514
View3D *v3d = CTX_wm_view3d(C);
3570
3515
RegionView3D *rv3d = CTX_wm_region_view3d(C);
3517
const float co_zero[3] = {0.0f};
3572
3518
float mval_f[2] = {0.0f, 0.0f};
3522
VIEW3D_OP_OFS_LOCK_TEST(C, op);
3575
3524
pandir = RNA_enum_get(op->ptr, "type");
3577
initgrabz(rv3d, 0.0, 0.0, 0.0);
3578
if (pandir == V3D_VIEW_PANRIGHT) { mval_f[0] = -32.0f; ED_view3d_win_to_delta(ar, mval_f, vec); }
3579
else if (pandir == V3D_VIEW_PANLEFT) { mval_f[0] = 32.0f; ED_view3d_win_to_delta(ar, mval_f, vec); }
3580
else if (pandir == V3D_VIEW_PANUP) { mval_f[1] = -25.0f; ED_view3d_win_to_delta(ar, mval_f, vec); }
3581
else if (pandir == V3D_VIEW_PANDOWN) { mval_f[1] = 25.0f; ED_view3d_win_to_delta(ar, mval_f, vec); }
3526
ED_view3d_camera_lock_init(v3d, rv3d);
3528
zfac = ED_view3d_calc_zfac(rv3d, co_zero, NULL);
3529
if (pandir == V3D_VIEW_PANRIGHT) { mval_f[0] = -32.0f; }
3530
else if (pandir == V3D_VIEW_PANLEFT) { mval_f[0] = 32.0f; }
3531
else if (pandir == V3D_VIEW_PANUP) { mval_f[1] = -25.0f; }
3532
else if (pandir == V3D_VIEW_PANDOWN) { mval_f[1] = 25.0f; }
3533
ED_view3d_win_to_delta(ar, mval_f, vec, zfac);
3582
3534
add_v3_v3(rv3d->ofs, vec);
3584
3536
if (rv3d->viewlock & RV3D_BOXVIEW)
3585
view3d_boxview_sync(CTX_wm_area(C), ar);
3537
view3d_boxview_sync(sa, ar);
3539
ED_view3d_depth_tag_update(rv3d);
3541
ED_view3d_camera_lock_sync(v3d, rv3d);
3587
3543
ED_region_tag_redraw(ar);
3756
3714
/* ********************* set clipping operator ****************** */
3758
static void calc_clipping_plane(float clip[6][4], BoundBox *clipbb)
3716
static void calc_clipping_plane(float clip[6][4], const BoundBox *clipbb)
3762
3720
for (val = 0; val < 4; val++) {
3764
3721
normal_tri_v3(clip[val], clipbb->vec[val], clipbb->vec[val == 3 ? 0 : val + 1], clipbb->vec[val + 4]);
3766
/* TODO - this is just '-dot_v3v3(clip[val], clipbb->vec[val])' isnt it? - sould replace */
3767
clip[val][3] = -clip[val][0] * clipbb->vec[val][0] -
3768
clip[val][1] * clipbb->vec[val][1] -
3769
clip[val][2] * clipbb->vec[val][2];
3722
clip[val][3] = -dot_v3v3(clip[val], clipbb->vec[val]);
3859
3812
/* cursor position in vec, result in vec, mval in region coords */
3860
3813
/* note: cannot use event->mval here (called by object_add() */
3861
void ED_view3d_cursor3d_position(bContext *C, float *fp, int mx, int my)
3814
void ED_view3d_cursor3d_position(bContext *C, float fp[3], const int mval[2])
3863
3816
Scene *scene = CTX_data_scene(C);
3864
3817
ARegion *ar = CTX_wm_region(C);
3865
3818
View3D *v3d = CTX_wm_view3d(C);
3866
3819
RegionView3D *rv3d = CTX_wm_region_view3d(C);
3867
3820
float mval_fl[2];
3871
mval[0] = mx - ar->winrct.xmin;
3872
mval[1] = my - ar->winrct.ymin;
3874
flip = initgrabz(rv3d, fp[0], fp[1], fp[2]);
3824
zfac = ED_view3d_calc_zfac(rv3d, fp, &flip);
3876
3826
/* reset the depth based on the view offset (we _know_ the offset is infront of us) */
3878
3828
negate_v3_v3(fp, rv3d->ofs);
3879
3829
/* re initialize, no need to check flip again */
3880
/* flip = */ initgrabz(rv3d, fp[0], fp[1], fp[2]);
3830
zfac = ED_view3d_calc_zfac(rv3d, fp, NULL /* &flip */ );
3883
3833
if (ED_view3d_project_float_global(ar, fp, mval_fl, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
3884
short depth_used = FALSE;
3834
bool depth_used = false;
3886
3836
if (U.uiflag & USER_ZBUF_CURSOR) { /* maybe this should be accessed some other way */
3887
3837
view3d_operator_needs_opengl(C);
3888
if (ED_view3d_autodist(scene, ar, v3d, mval, fp))
3838
if (ED_view3d_autodist(scene, ar, v3d, mval, fp, true))
3892
if (depth_used == FALSE) {
3842
if (depth_used == false) {
3894
3844
VECSUB2D(mval_fl, mval_fl, mval);
3895
ED_view3d_win_to_delta(ar, mval_fl, dvec);
3845
ED_view3d_win_to_delta(ar, mval_fl, dvec, zfac);
3896
3846
sub_v3_v3(fp, dvec);
3900
const float dx = ((float)(mval[0] - (ar->winx / 2))) * rv3d->zfac / (ar->winx / 2);
3901
const float dy = ((float)(mval[1] - (ar->winy / 2))) * rv3d->zfac / (ar->winy / 2);
3850
const float dx = ((float)(mval[0] - (ar->winx / 2))) * zfac / (ar->winx / 2);
3851
const float dy = ((float)(mval[1] - (ar->winy / 2))) * zfac / (ar->winy / 2);
3902
3852
const float fz = (rv3d->persmat[0][3] * fp[0] +
3903
3853
rv3d->persmat[1][3] * fp[1] +
3904
3854
rv3d->persmat[2][3] * fp[2] +
3905
rv3d->persmat[3][3]) / rv3d->zfac;
3855
rv3d->persmat[3][3]) / zfac;
3907
3857
fp[0] = (rv3d->persinv[0][0] * dx + rv3d->persinv[1][0] * dy + rv3d->persinv[2][0] * fz) - rv3d->ofs[0];
3908
3858
fp[1] = (rv3d->persinv[0][1] * dx + rv3d->persinv[1][1] * dy + rv3d->persinv[2][1] * fz) - rv3d->ofs[1];
3914
static int view3d_cursor3d_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
3864
static int view3d_cursor3d_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
3916
3866
Scene *scene = CTX_data_scene(C);
3917
3867
View3D *v3d = CTX_wm_view3d(C);
3918
3868
float *fp = give_cursor(scene, v3d);
3920
ED_view3d_cursor3d_position(C, fp, event->x, event->y);
3870
ED_view3d_cursor3d_position(C, fp, event->mval);
3922
3872
if (v3d && v3d->localvd)
3923
3873
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
4059
4009
/* XXX todo Zooms in on a border drawn by the user */
4060
int ED_view3d_autodist(Scene *scene, ARegion *ar, View3D *v3d, const int mval[2], float mouse_worldloc[3])
4010
bool ED_view3d_autodist(Scene *scene, ARegion *ar, View3D *v3d, const int mval[2], float mouse_worldloc[3], bool alphaoverride)
4062
4012
bglMats mats; /* ZBuffer depth vars */
4063
float depth_close = FLT_MAX;
4064
4014
double cent[2], p[3];
4066
4016
/* Get Z Depths, needed for perspective, nice for ortho */
4067
4017
bgl_get_mats(&mats);
4068
draw_depth(scene, ar, v3d, NULL);
4018
draw_depth(scene, ar, v3d, NULL, alphaoverride);
4070
4020
depth_close = view_autodist_depth_margin(ar, mval, 4);
4072
4022
if (depth_close == FLT_MAX)
4075
4025
cent[0] = (double)mval[0];
4076
4026
cent[1] = (double)mval[1];
4078
4028
if (!gluUnProject(cent[0], cent[1], depth_close,
4079
4029
mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2]))
4084
4034
mouse_worldloc[0] = (float)p[0];
4085
4035
mouse_worldloc[1] = (float)p[1];
4086
4036
mouse_worldloc[2] = (float)p[2];
4090
int ED_view3d_autodist_init(Scene *scene, ARegion *ar, View3D *v3d, int mode)
4040
void ED_view3d_autodist_init(Scene *scene, ARegion *ar, View3D *v3d, int mode)
4092
4042
/* Get Z Depths, needed for perspective, nice for ortho */
4093
4043
switch (mode) {
4095
draw_depth(scene, ar, v3d, NULL);
4045
draw_depth(scene, ar, v3d, NULL, true);
4098
4048
draw_depth_gpencil(scene, ar, v3d);
4105
/* no 4x4 sampling, run view_autodist_init first */
4106
int ED_view3d_autodist_simple(ARegion *ar, const int mval[2], float mouse_worldloc[3],
4107
int margin, float *force_depth)
4053
/* no 4x4 sampling, run #ED_view3d_autodist_init first */
4054
bool ED_view3d_autodist_simple(ARegion *ar, const int mval[2], float mouse_worldloc[3],
4055
int margin, float *force_depth)
4109
4057
bglMats mats; /* ZBuffer depth vars, could cache? */
4127
4075
if (!gluUnProject(cent[0], cent[1], depth,
4128
4076
mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2]))
4133
4081
mouse_worldloc[0] = (float)p[0];
4134
4082
mouse_worldloc[1] = (float)p[1];
4135
4083
mouse_worldloc[2] = (float)p[2];
4139
int ED_view3d_autodist_depth(ARegion *ar, const int mval[2], int margin, float *depth)
4087
bool ED_view3d_autodist_depth(ARegion *ar, const int mval[2], int margin, float *depth)
4141
4089
*depth = view_autodist_depth_margin(ar, mval, margin);
4143
return (*depth == FLT_MAX) ? 0 : 1;
4091
return (*depth != FLT_MAX);
4146
static int depth_segment_cb(int x, int y, void *userData)
4094
static bool depth_segment_cb(int x, int y, void *userData)
4148
4096
struct { ARegion *ar; int margin; float depth; } *data = userData;