4 * ***** BEGIN GPL LICENSE BLOCK *****
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 * The Original Code is Copyright (C) 2008 Blender Foundation.
21 * All rights reserved.
24 * Contributor(s): Blender Foundation
26 * ***** END GPL LICENSE BLOCK *****
34 #include "DNA_action_types.h"
35 #include "DNA_armature_types.h"
36 #include "DNA_camera_types.h"
37 #include "DNA_lamp_types.h"
38 #include "DNA_object_types.h"
39 #include "DNA_space_types.h"
40 #include "DNA_scene_types.h"
41 #include "DNA_screen_types.h"
42 #include "DNA_userdef_types.h"
43 #include "DNA_view3d_types.h"
44 #include "DNA_world_types.h"
46 #include "MEM_guardedalloc.h"
48 #include "BLI_blenlib.h"
49 #include "BLI_arithb.h"
52 #include "BKE_action.h"
53 #include "BKE_context.h"
54 #include "BKE_depsgraph.h"
55 #include "BKE_object.h"
56 #include "BKE_global.h"
57 #include "BKE_scene.h"
58 #include "BKE_screen.h"
59 #include "BKE_utildefines.h"
61 #include "RE_pipeline.h" // make_stars
64 #include "BIF_retopo.h"
69 #include "RNA_access.h"
70 #include "RNA_define.h"
72 #include "ED_space_api.h"
73 #include "ED_screen.h"
76 #include "UI_interface.h"
77 #include "UI_resources.h"
78 #include "UI_view2d.h"
80 #include "PIL_time.h" /* smoothview */
82 #include "view3d_intern.h" // own include
84 /* ********************** view3d_edit: view manipulations ********************* */
86 /* ************************** init for view ops **********************************/
88 typedef struct ViewOpsData {
94 float ofs[3], obofs[3];
98 int origx, origy, oldx, oldy;
103 #define TRACKBALLSIZE (1.1)
105 static void calctrackballvec(rcti *rect, int mx, int my, float *vec)
107 float x, y, radius, d, z, t;
109 radius= TRACKBALLSIZE;
111 /* normalize x and y */
112 x= (rect->xmax + rect->xmin)/2 - mx;
113 x/= (float)((rect->xmax - rect->xmin)/4);
114 y= (rect->ymax + rect->ymin)/2 - my;
115 y/= (float)((rect->ymax - rect->ymin)/2);
118 if (d < radius*M_SQRT1_2) /* Inside sphere */
119 z = sqrt(radius*radius - d*d);
122 t = radius / M_SQRT2;
128 vec[2]= -z; /* yah yah! */
132 static void viewops_data(bContext *C, wmOperator *op, wmEvent *event)
134 View3D *v3d = CTX_wm_view3d(C);
136 ViewOpsData *vod= MEM_callocN(sizeof(ViewOpsData), "viewops data");
140 vod->ar= CTX_wm_region(C);
141 vod->rv3d= rv3d= vod->ar->regiondata;
142 vod->dist0= rv3d->dist;
143 QUATCOPY(vod->oldquat, rv3d->viewquat);
144 vod->origx= vod->oldx= event->x;
145 vod->origy= vod->oldy= event->y;
146 vod->origkey= event->type;
148 /* lookup, we dont pass on v3d to prevent confusement */
149 vod->grid= v3d->grid;
152 calctrackballvec(&vod->ar->winrct, event->x, event->y, vod->trackvec);
154 initgrabz(rv3d, -rv3d->ofs[0], -rv3d->ofs[1], -rv3d->ofs[2]);
157 if (rv3d->persmat[2][1] < 0.0f)
162 /* ************************** viewrotate **********************************/
164 static const float thres = 0.93f; //cos(20 deg);
166 #define COS45 0.70710678118654746
169 static float snapquats[39][6] = {
170 /*{q0, q1, q3, q4, view, oposite_direction}*/
171 {COS45, -SIN45, 0.0, 0.0, 1, 0}, //front
172 {0.0, 0.0, -SIN45, -SIN45, 1, 1}, //back
173 {1.0, 0.0, 0.0, 0.0, 7, 0}, //top
174 {0.0, -1.0, 0.0, 0.0, 7, 1}, //bottom
175 {0.5, -0.5, -0.5, -0.5, 3, 0}, //left
176 {0.5, -0.5, 0.5, 0.5, 3, 1}, //right
178 /* some more 45 deg snaps */
179 {0.65328145027160645, -0.65328145027160645, 0.27059805393218994, 0.27059805393218994, 0, 0},
180 {0.92387950420379639, 0.0, 0.0, 0.38268342614173889, 0, 0},
181 {0.0, -0.92387950420379639, 0.38268342614173889, 0.0, 0, 0},
182 {0.35355335474014282, -0.85355335474014282, 0.35355338454246521, 0.14644660055637360, 0, 0},
183 {0.85355335474014282, -0.35355335474014282, 0.14644660055637360, 0.35355338454246521, 0, 0},
184 {0.49999994039535522, -0.49999994039535522, 0.49999997019767761, 0.49999997019767761, 0, 0},
185 {0.27059802412986755, -0.65328145027160645, 0.65328145027160645, 0.27059802412986755, 0, 0},
186 {0.65328145027160645, -0.27059802412986755, 0.27059802412986755, 0.65328145027160645, 0, 0},
187 {0.27059799432754517, -0.27059799432754517, 0.65328139066696167, 0.65328139066696167, 0, 0},
188 {0.38268336653709412, 0.0, 0.0, 0.92387944459915161, 0, 0},
189 {0.0, -0.38268336653709412, 0.92387944459915161, 0.0, 0, 0},
190 {0.14644658565521240, -0.35355335474014282, 0.85355335474014282, 0.35355335474014282, 0, 0},
191 {0.35355335474014282, -0.14644658565521240, 0.35355335474014282, 0.85355335474014282, 0, 0},
192 {0.0, 0.0, 0.92387944459915161, 0.38268336653709412, 0, 0},
193 {-0.0, 0.0, 0.38268336653709412, 0.92387944459915161, 0, 0},
194 {-0.27059802412986755, 0.27059802412986755, 0.65328133106231689, 0.65328133106231689, 0, 0},
195 {-0.38268339633941650, 0.0, 0.0, 0.92387938499450684, 0, 0},
196 {0.0, 0.38268339633941650, 0.92387938499450684, 0.0, 0, 0},
197 {-0.14644658565521240, 0.35355338454246521, 0.85355329513549805, 0.35355332493782043, 0, 0},
198 {-0.35355338454246521, 0.14644658565521240, 0.35355332493782043, 0.85355329513549805, 0, 0},
199 {-0.49999991059303284, 0.49999991059303284, 0.49999985098838806, 0.49999985098838806, 0, 0},
200 {-0.27059799432754517, 0.65328145027160645, 0.65328139066696167, 0.27059799432754517, 0, 0},
201 {-0.65328145027160645, 0.27059799432754517, 0.27059799432754517, 0.65328139066696167, 0, 0},
202 {-0.65328133106231689, 0.65328133106231689, 0.27059793472290039, 0.27059793472290039, 0, 0},
203 {-0.92387932538986206, 0.0, 0.0, 0.38268333673477173, 0, 0},
204 {0.0, 0.92387932538986206, 0.38268333673477173, 0.0, 0, 0},
205 {-0.35355329513549805, 0.85355329513549805, 0.35355329513549805, 0.14644657075405121, 0, 0},
206 {-0.85355329513549805, 0.35355329513549805, 0.14644657075405121, 0.35355329513549805, 0, 0},
207 {-0.38268330693244934, 0.92387938499450684, 0.0, 0.0, 0, 0},
208 {-0.92387938499450684, 0.38268330693244934, 0.0, 0.0, 0, 0},
209 {-COS45, 0.0, 0.0, SIN45, 0, 0},
210 {COS45, 0.0, 0.0, SIN45, 0, 0},
211 {0.0, 0.0, 0.0, 1.0, 0, 0}
215 static void viewrotate_apply(ViewOpsData *vod, int x, int y, int ctrl)
217 RegionView3D *rv3d= vod->rv3d;
218 int use_sel= 0; /* XXX */
220 rv3d->view= 0; /* need to reset everytime because of view snapping */
222 if (U.flag & USER_TRACKBALL) {
223 float phi, si, q1[4], dvec[3], newvec[3];
225 calctrackballvec(&vod->ar->winrct, x, y, newvec);
227 VecSubf(dvec, newvec, vod->trackvec);
229 si= sqrt(dvec[0]*dvec[0]+ dvec[1]*dvec[1]+ dvec[2]*dvec[2]);
230 si/= (2.0*TRACKBALLSIZE);
232 Crossf(q1+1, vod->trackvec, newvec);
235 /* Allow for rotation beyond the interval
240 /* This relation is used instead of
241 * phi = asin(si) so that the angle
242 * of rotation is linearly proportional
243 * to the distance that the mouse is
245 phi = si * M_PI / 2.0;
252 QuatMul(rv3d->viewquat, q1, vod->oldquat);
255 /* compute the post multiplication quat, to rotate the offset correctly */
256 QUATCOPY(q1, vod->oldquat);
258 QuatMul(q1, q1, rv3d->viewquat);
260 QuatConj(q1); /* conj == inv for unit quat */
261 VECCOPY(rv3d->ofs, vod->ofs);
262 VecSubf(rv3d->ofs, rv3d->ofs, vod->obofs);
263 QuatMulVecf(q1, rv3d->ofs);
264 VecAddf(rv3d->ofs, rv3d->ofs, vod->obofs);
268 /* New turntable view code by John Aughey */
269 float si, phi, q1[4];
272 float xvec[3] = {1,0,0};
273 /* Sensitivity will control how fast the viewport rotates. 0.0035 was
274 obtained experimentally by looking at viewport rotation sensitivities
275 on other modeling programs. */
276 /* Perhaps this should be a configurable user parameter. */
277 const float sensitivity = 0.0035;
279 /* Get the 3x3 matrix and its inverse from the quaternion */
280 QuatToMat3(rv3d->viewquat, m);
283 /* Determine the direction of the x vector (for rotating up and down) */
284 /* This can likely be compuated directly from the quaternion. */
285 Mat3MulVecfl(m_inv,xvec);
287 /* Perform the up/down rotation */
288 phi = sensitivity * -(y - vod->oldy);
291 q1[1] = si * xvec[0];
292 q1[2] = si * xvec[1];
293 q1[3] = si * xvec[2];
294 QuatMul(rv3d->viewquat, rv3d->viewquat, q1);
297 QuatConj(q1); /* conj == inv for unit quat */
298 VecSubf(rv3d->ofs, rv3d->ofs, vod->obofs);
299 QuatMulVecf(q1, rv3d->ofs);
300 VecAddf(rv3d->ofs, rv3d->ofs, vod->obofs);
303 /* Perform the orbital rotation */
304 phi = sensitivity * vod->reverse * (x - vod->oldx);
308 QuatMul(rv3d->viewquat, rv3d->viewquat, q1);
312 VecSubf(rv3d->ofs, rv3d->ofs, vod->obofs);
313 QuatMulVecf(q1, rv3d->ofs);
314 VecAddf(rv3d->ofs, rv3d->ofs, vod->obofs);
318 /* check for view snap */
324 QuatToMat3(rv3d->viewquat, viewmat);
326 for (i = 0 ; i < 39; i++){
328 float view = (int)snapquats[i][4];
329 float oposite_dir = (int)snapquats[i][5];
331 QuatToMat3(snapquats[i], snapmat);
333 if ((Inpf(snapmat[0], viewmat[0]) > thres) &&
334 (Inpf(snapmat[1], viewmat[1]) > thres) &&
335 (Inpf(snapmat[2], viewmat[2]) > thres)){
337 QUATCOPY(rv3d->viewquat, snapquats[i]);
342 rv3d->rflag |= RV3D_OPP_DIRECTION_NAME;
344 rv3d->rflag &= ~RV3D_OPP_DIRECTION_NAME;
355 ED_region_tag_redraw(vod->ar);
358 static int viewrotate_modal(bContext *C, wmOperator *op, wmEvent *event)
360 ViewOpsData *vod= op->customdata;
362 /* execute the events */
363 switch(event->type) {
365 viewrotate_apply(vod, event->x, event->y, event->ctrl);
369 if(event->type==vod->origkey && event->val==0) {
372 op->customdata= NULL;
374 return OPERATOR_FINISHED;
378 return OPERATOR_RUNNING_MODAL;
381 static int viewrotate_invoke(bContext *C, wmOperator *op, wmEvent *event)
385 /* makes op->customdata */
386 viewops_data(C, op, event);
389 /* switch from camera view when: */
390 if(vod->rv3d->persp != V3D_PERSP) {
392 if (U.uiflag & USER_AUTOPERSP)
393 vod->rv3d->persp= V3D_PERSP;
394 else if(vod->rv3d->persp==V3D_CAMOB)
395 vod->rv3d->persp= V3D_PERSP;
396 ED_region_tag_redraw(vod->ar);
399 /* add temp handler */
400 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
402 return OPERATOR_RUNNING_MODAL;
406 void VIEW3D_OT_viewrotate(wmOperatorType *ot)
410 ot->name= "Rotate view";
411 ot->idname= "VIEW3D_OT_viewrotate";
414 ot->invoke= viewrotate_invoke;
415 ot->modal= viewrotate_modal;
416 ot->poll= ED_operator_view3d_active;
419 /* ************************ viewmove ******************************** */
421 static void viewmove_apply(ViewOpsData *vod, int x, int y)
423 if(vod->rv3d->persp==V3D_CAMOB) {
424 float max= (float)MAX2(vod->ar->winx, vod->ar->winy);
426 vod->rv3d->camdx += (vod->oldx - x)/(max);
427 vod->rv3d->camdy += (vod->oldy - y)/(max);
428 CLAMP(vod->rv3d->camdx, -1.0f, 1.0f);
429 CLAMP(vod->rv3d->camdy, -1.0f, 1.0f);
430 // XXX preview3d_event= 0;
435 window_to_3d(vod->ar, dvec, x-vod->oldx, y-vod->oldy);
436 VecAddf(vod->rv3d->ofs, vod->rv3d->ofs, dvec);
442 ED_region_tag_redraw(vod->ar);
446 static int viewmove_modal(bContext *C, wmOperator *op, wmEvent *event)
448 ViewOpsData *vod= op->customdata;
450 /* execute the events */
451 switch(event->type) {
453 viewmove_apply(vod, event->x, event->y);
457 if(event->type==vod->origkey && event->val==0) {
460 op->customdata= NULL;
462 return OPERATOR_FINISHED;
466 return OPERATOR_RUNNING_MODAL;
469 static int viewmove_invoke(bContext *C, wmOperator *op, wmEvent *event)
471 /* makes op->customdata */
472 viewops_data(C, op, event);
474 /* add temp handler */
475 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
477 return OPERATOR_RUNNING_MODAL;
481 void VIEW3D_OT_viewmove(wmOperatorType *ot)
485 ot->name= "Rotate view";
486 ot->idname= "VIEW3D_OT_viewmove";
489 ot->invoke= viewmove_invoke;
490 ot->modal= viewmove_modal;
491 ot->poll= ED_operator_view3d_active;
494 /* ************************ viewzoom ******************************** */
496 static void view_zoom_mouseloc(ARegion *ar, float dfac, int mx, int my)
498 RegionView3D *rv3d= ar->regiondata;
500 if(U.uiflag & USER_ZOOM_TO_MOUSEPOS) {
505 short vb[2], mouseloc[2];
507 mouseloc[0]= mx - ar->winrct.xmin;
508 mouseloc[1]= my - ar->winrct.ymin;
510 /* find the current window width and height */
514 tpos[0] = -rv3d->ofs[0];
515 tpos[1] = -rv3d->ofs[1];
516 tpos[2] = -rv3d->ofs[2];
518 /* Project cursor position into 3D space */
519 initgrabz(rv3d, tpos[0], tpos[1], tpos[2]);
520 window_to_3d(ar, dvec, mouseloc[0]-vb[0]/2, mouseloc[1]-vb[1]/2);
522 /* Calculate view target position for dolly */
523 tvec[0] = -(tpos[0] + dvec[0]);
524 tvec[1] = -(tpos[1] + dvec[1]);
525 tvec[2] = -(tpos[2] + dvec[2]);
527 /* Offset to target position and dolly */
528 new_dist = rv3d->dist * dfac;
530 VECCOPY(rv3d->ofs, tvec);
531 rv3d->dist = new_dist;
533 /* Calculate final offset */
534 dvec[0] = tvec[0] + dvec[0] * dfac;
535 dvec[1] = tvec[1] + dvec[1] * dfac;
536 dvec[2] = tvec[2] + dvec[2] * dfac;
538 VECCOPY(rv3d->ofs, dvec);
545 static void viewzoom_apply(ViewOpsData *vod, int x, int y)
549 if(U.viewzoom==USER_ZOOM_CONT) {
551 zfac = 1.0+(float)(vod->origx - x + vod->origy - y)/1000.0;
553 else if(U.viewzoom==USER_ZOOM_SCALE) {
554 int ctr[2], len1, len2;
555 // method which zooms based on how far you move the mouse
557 ctr[0] = (vod->ar->winrct.xmax + vod->ar->winrct.xmin)/2;
558 ctr[1] = (vod->ar->winrct.ymax + vod->ar->winrct.ymin)/2;
560 len1 = (int)sqrt((ctr[0] - x)*(ctr[0] - x) + (ctr[1] - y)*(ctr[1] - y)) + 5;
561 len2 = (int)sqrt((ctr[0] - vod->origx)*(ctr[0] - vod->origx) + (ctr[1] - vod->origy)*(ctr[1] - vod->origy)) + 5;
563 zfac = vod->dist0 * ((float)len2/len1) / vod->rv3d->dist;
565 else { /* USER_ZOOM_DOLLY */
566 float len1 = (vod->ar->winrct.ymax - y) + 5;
567 float len2 = (vod->ar->winrct.ymax - vod->origy) + 5;
568 zfac = vod->dist0 * (2.0*((len2/len1)-1.0) + 1.0) / vod->rv3d->dist;
571 if(zfac != 1.0 && zfac*vod->rv3d->dist > 0.001*vod->grid &&
572 zfac*vod->rv3d->dist < 10.0*vod->far)
573 view_zoom_mouseloc(vod->ar, zfac, vod->oldx, vod->oldy);
576 if ((U.uiflag & USER_ORBIT_ZBUF) && (U.viewzoom==USER_ZOOM_CONT) && (vod->rv3d->persp==V3D_PERSP)) {
577 float upvec[3], mat[3][3];
579 /* Secret apricot feature, translate the view when in continues mode */
580 upvec[0] = upvec[1] = 0.0f;
581 upvec[2] = (vod->dist0 - vod->rv3d->dist) * vod->grid;
582 vod->rv3d->dist = vod->dist0;
583 Mat3CpyMat4(mat, vod->rv3d->viewinv);
584 Mat3MulVecfl(mat, upvec);
585 VecAddf(vod->rv3d->ofs, vod->rv3d->ofs, upvec);
587 /* these limits were in old code too */
588 if(vod->rv3d->dist<0.001*vod->grid) vod->rv3d->dist= 0.001*vod->grid;
589 if(vod->rv3d->dist>10.0*vod->far) vod->rv3d->dist=10.0*vod->far;
592 // XXX if(vod->rv3d->persp==V3D_ORTHO || vod->rv3d->persp==V3D_CAMOB) preview3d_event= 0;
594 ED_region_tag_redraw(vod->ar);
598 static int viewzoom_modal(bContext *C, wmOperator *op, wmEvent *event)
600 ViewOpsData *vod= op->customdata;
602 /* execute the events */
603 switch(event->type) {
605 viewzoom_apply(vod, event->x, event->y);
609 if(event->type==vod->origkey && event->val==0) {
612 op->customdata= NULL;
614 return OPERATOR_FINISHED;
618 return OPERATOR_RUNNING_MODAL;
621 static int viewzoom_exec(bContext *C, wmOperator *op)
623 View3D *v3d = CTX_wm_view3d(C);
624 RegionView3D *rv3d= CTX_wm_region_view3d(C);
625 int delta= RNA_int_get(op->ptr, "delta");
628 /* this min and max is also in viewmove() */
629 if(rv3d->persp==V3D_CAMOB) {
631 if(rv3d->camzoom<-30) rv3d->camzoom= -30;
633 else if(rv3d->dist<10.0*v3d->far) rv3d->dist*=1.2f;
636 if(rv3d->persp==V3D_CAMOB) {
638 if(rv3d->camzoom>300) rv3d->camzoom= 300;
640 else if(rv3d->dist> 0.001*v3d->grid) rv3d->dist*=.83333f;
643 ED_region_tag_redraw(CTX_wm_region(C));
645 return OPERATOR_FINISHED;
648 static int viewzoom_invoke(bContext *C, wmOperator *op, wmEvent *event)
650 int delta= RNA_int_get(op->ptr, "delta");
653 viewzoom_exec(C, op);
656 /* makes op->customdata */
657 viewops_data(C, op, event);
659 /* add temp handler */
660 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
662 return OPERATOR_RUNNING_MODAL;
664 return OPERATOR_FINISHED;
668 void VIEW3D_OT_viewzoom(wmOperatorType *ot)
671 ot->name= "Rotate view";
672 ot->idname= "VIEW3D_OT_viewzoom";
675 ot->invoke= viewzoom_invoke;
676 ot->exec= viewzoom_exec;
677 ot->modal= viewzoom_modal;
678 ot->poll= ED_operator_view3d_active;
680 RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
683 static int viewhome_exec(bContext *C, wmOperator *op) /* was view3d_home() in 2.4x */
685 ARegion *ar= CTX_wm_region(C);
686 View3D *v3d = CTX_wm_view3d(C);
687 RegionView3D *rv3d= CTX_wm_region_view3d(C);
688 Scene *scene= CTX_data_scene(C);
691 int center= RNA_boolean_get(op->ptr, "center");
693 float size, min[3], max[3], afm[3];
694 int ok= 1, onedone=0;
697 min[0]= min[1]= min[2]= 0.0f;
698 max[0]= max[1]= max[2]= 0.0f;
701 INIT_MINMAX(min, max);
704 for(base= scene->base.first; base; base= base->next) {
705 if(base->lay & v3d->lay) {
707 minmax_object(base->object, min, max);
710 if(!onedone) return OPERATOR_FINISHED; /* TODO - should this be cancel? */
712 afm[0]= (max[0]-min[0]);
713 afm[1]= (max[1]-min[1]);
714 afm[2]= (max[2]-min[2]);
715 size= 0.7f*MAX3(afm[0], afm[1], afm[2]);
723 new_ofs[0]= -(min[0]+max[0])/2.0f;
724 new_ofs[1]= -(min[1]+max[1])/2.0f;
725 new_ofs[2]= -(min[2]+max[2])/2.0f;
727 // correction for window aspect ratio
728 if(ar->winy>2 && ar->winx>2) {
729 size= (float)ar->winx/(float)ar->winy;
730 if(size<1.0) size= 1.0f/size;
734 if (rv3d->persp==V3D_CAMOB) {
735 rv3d->persp= V3D_PERSP;
736 smooth_view(C, NULL, v3d->camera, new_ofs, NULL, &new_dist, NULL);
739 // XXX BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
741 return OPERATOR_FINISHED;
744 void VIEW3D_OT_viewhome(wmOperatorType *ot)
747 ot->name= "View home";
748 ot->idname= "VIEW3D_OT_viewhome";
751 ot->exec= viewhome_exec;
752 ot->poll= ED_operator_view3d_active;
754 RNA_def_boolean(ot->srna, "center", 0, "Center", "");
757 static int viewcenter_exec(bContext *C, wmOperator *op) /* like a localview without local!, was centerview() in 2.4x */
759 ARegion *ar= CTX_wm_region(C);
760 View3D *v3d = CTX_wm_view3d(C);
761 RegionView3D *rv3d= CTX_wm_region_view3d(C);
762 Scene *scene= CTX_data_scene(C);
764 Object *obedit= CTX_data_edit_object(C);
765 float size, min[3], max[3], afm[3];
772 INIT_MINMAX(min, max);
774 if (G.f & G_WEIGHTPAINT) {
775 /* hardcoded exception, we look for the one selected armature */
776 /* this is weak code this way, we should make a generic active/selection callback interface once... */
778 for(base=scene->base.first; base; base= base->next) {
779 if(TESTBASELIB(v3d, base)) {
780 if(base->object->type==OB_ARMATURE)
781 if(base->object->flag & OB_POSEMODE)
791 // XXX ok = minmax_verts(min, max); /* only selected */
793 else if(ob && (ob->flag & OB_POSEMODE)) {
795 bArmature *arm= ob->data;
799 for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
800 if(pchan->bone->flag & BONE_SELECTED) {
801 if(pchan->bone->layer & arm->layer) {
803 VECCOPY(vec, pchan->pose_head);
804 Mat4MulVecfl(ob->obmat, vec);
805 DO_MINMAX(vec, min, max);
806 VECCOPY(vec, pchan->pose_tail);
807 Mat4MulVecfl(ob->obmat, vec);
808 DO_MINMAX(vec, min, max);
814 else if (FACESEL_PAINT_TEST) {
815 // XXX ok= minmax_tface(min, max);
817 else if (G.f & G_PARTICLEEDIT) {
818 // XXX ok= PE_minmax(min, max);
821 Base *base= FIRSTBASE;
823 if(TESTBASE(v3d, base)) {
824 minmax_object(base->object, min, max);
825 /* account for duplis */
826 minmax_object_duplis(scene, base->object, min, max);
834 if(ok==0) return OPERATOR_FINISHED;
836 afm[0]= (max[0]-min[0]);
837 afm[1]= (max[1]-min[1]);
838 afm[2]= (max[2]-min[2]);
839 size= 0.7f*MAX3(afm[0], afm[1], afm[2]);
841 if(size <= v3d->near*1.5f) size= v3d->near*1.5f;
843 new_ofs[0]= -(min[0]+max[0])/2.0f;
844 new_ofs[1]= -(min[1]+max[1])/2.0f;
845 new_ofs[2]= -(min[2]+max[2])/2.0f;
849 /* correction for window aspect ratio */
850 if(ar->winy>2 && ar->winx>2) {
851 size= (float)ar->winx/(float)ar->winy;
852 if(size<1.0f) size= 1.0f/size;
856 v3d->cursor[0]= -new_ofs[0];
857 v3d->cursor[1]= -new_ofs[1];
858 v3d->cursor[2]= -new_ofs[2];
860 if (rv3d->persp==V3D_CAMOB) {
861 rv3d->persp= V3D_PERSP;
862 smooth_view(C, v3d->camera, NULL, new_ofs, NULL, &new_dist, NULL);
865 smooth_view(C, NULL, NULL, new_ofs, NULL, &new_dist, NULL);
868 // XXX BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
870 return OPERATOR_FINISHED;
872 void VIEW3D_OT_viewcenter(wmOperatorType *ot)
876 ot->name= "View center";
877 ot->idname= "VIEW3D_OT_viewcenter";
880 ot->exec= viewcenter_exec;
881 ot->poll= ED_operator_view3d_active;
884 /* ********************* Set render border operator ****************** */
886 static int render_border_exec(bContext *C, wmOperator *op)
888 View3D *v3d = CTX_wm_view3d(C);
889 ARegion *ar= CTX_wm_region(C);
890 Scene *scene= CTX_data_scene(C);
895 /* get border select values using rna */
896 rect.xmin= RNA_int_get(op->ptr, "xmin");
897 rect.ymin= RNA_int_get(op->ptr, "ymin");
898 rect.xmax= RNA_int_get(op->ptr, "xmax");
899 rect.ymax= RNA_int_get(op->ptr, "ymax");
901 /* calculate range */
902 calc_viewborder(scene, ar, v3d, &vb);
904 scene->r.border.xmin= ((float)rect.xmin-vb.xmin)/(vb.xmax-vb.xmin);
905 scene->r.border.ymin= ((float)rect.ymin-vb.ymin)/(vb.ymax-vb.ymin);
906 scene->r.border.xmax= ((float)rect.xmax-vb.xmin)/(vb.xmax-vb.xmin);
907 scene->r.border.ymax= ((float)rect.ymax-vb.ymin)/(vb.ymax-vb.ymin);
909 /* actually set border */
910 CLAMP(scene->r.border.xmin, 0.0, 1.0);
911 CLAMP(scene->r.border.ymin, 0.0, 1.0);
912 CLAMP(scene->r.border.xmax, 0.0, 1.0);
913 CLAMP(scene->r.border.ymax, 0.0, 1.0);
915 /* drawing a border surrounding the entire camera view switches off border rendering
916 * or the border covers no pixels */
917 if ((scene->r.border.xmin <= 0.0 && scene->r.border.xmax >= 1.0 &&
918 scene->r.border.ymin <= 0.0 && scene->r.border.ymax >= 1.0) ||
919 (scene->r.border.xmin == scene->r.border.xmax ||
920 scene->r.border.ymin == scene->r.border.ymax ))
922 scene->r.mode &= ~R_BORDER;
924 scene->r.mode |= R_BORDER;
927 return OPERATOR_FINISHED;
931 static int view3d_render_border_invoke(bContext *C, wmOperator *op, wmEvent *event)
933 RegionView3D *rv3d= CTX_wm_region_view3d(C);
935 /* if not in camera view do not exec the operator*/
936 if (rv3d->persp == V3D_CAMOB) return WM_border_select_invoke(C, op, event);
937 else return OPERATOR_PASS_THROUGH;
940 void VIEW3D_OT_render_border(wmOperatorType *ot)
943 ot->name= "Set Render Border";
944 ot->idname= "VIEW3D_OT_render_border";
947 ot->invoke= view3d_render_border_invoke;
948 ot->exec= render_border_exec;
949 ot->modal= WM_border_select_modal;
951 ot->poll= ED_operator_view3d_active;
954 RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
955 RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
956 RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
957 RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
960 /* ********************* Border Zoom operator ****************** */
962 static int view3d_border_zoom_exec(bContext *C, wmOperator *op)
964 ARegion *ar= CTX_wm_region(C);
965 View3D *v3d = CTX_wm_view3d(C);
966 RegionView3D *rv3d= CTX_wm_region_view3d(C);
967 Scene *scene= CTX_data_scene(C);
969 /* Zooms in on a border drawn by the user */
971 float dvec[3], vb[2], xscale, yscale, scale;
977 /* ZBuffer depth vars */
979 float depth, depth_close= MAXFLOAT;
981 double cent[2], p[3];
984 /* note; otherwise opengl won't work */
985 view3d_operator_needs_opengl(C);
987 /* get border select values using rna */
988 rect.xmin= RNA_int_get(op->ptr, "xmin");
989 rect.ymin= RNA_int_get(op->ptr, "ymin");
990 rect.xmax= RNA_int_get(op->ptr, "xmax");
991 rect.ymax= RNA_int_get(op->ptr, "ymax");
993 /* Get Z Depths, needed for perspective, nice for ortho */
995 draw_depth(scene, ar, v3d, NULL);
1000 rv3d->depths->damaged = 1;
1003 view3d_update_depths(ar, v3d);
1005 /* Constrain rect to depth bounds */
1006 if (rect.xmin < 0) rect.xmin = 0;
1007 if (rect.ymin < 0) rect.ymin = 0;
1008 if (rect.xmax >= rv3d->depths->w) rect.xmax = rv3d->depths->w-1;
1009 if (rect.ymax >= rv3d->depths->h) rect.ymax = rv3d->depths->h-1;
1011 /* Find the closest Z pixel */
1012 for (xs=rect.xmin; xs < rect.xmax; xs++) {
1013 for (ys=rect.ymin; ys < rect.ymax; ys++) {
1014 depth= rv3d->depths->depths[ys*rv3d->depths->w+xs];
1015 if(depth < rv3d->depths->depth_range[1] && depth > rv3d->depths->depth_range[0]) {
1016 if (depth_close > depth) {
1017 depth_close = depth;
1024 MEM_freeN(rv3d->depths->depths);
1025 rv3d->depths->depths = NULL;
1027 rv3d->depths->damaged = 1;
1029 cent[0] = (((double)rect.xmin)+((double)rect.xmax)) / 2;
1030 cent[1] = (((double)rect.ymin)+((double)rect.ymax)) / 2;
1032 if (rv3d->persp==V3D_PERSP) {
1035 /* no depths to use, we cant do anything! */
1036 if (depth_close==MAXFLOAT)
1037 return OPERATOR_CANCELLED;
1039 /* convert border to 3d coordinates */
1040 if (( !gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2])) ||
1041 ( !gluUnProject((double)rect.xmin, (double)rect.ymin, depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p_corner[0], &p_corner[1], &p_corner[2])))
1042 return OPERATOR_CANCELLED;
1044 dvec[0] = p[0]-p_corner[0];
1045 dvec[1] = p[1]-p_corner[1];
1046 dvec[2] = p[2]-p_corner[2];
1048 new_dist = VecLength(dvec);
1049 if(new_dist <= v3d->near*1.5) new_dist= v3d->near*1.5;
1055 } else { /* othographic */
1056 /* find the current window width and height */
1060 new_dist = rv3d->dist;
1062 /* convert the drawn rectangle into 3d space */
1063 if (depth_close!=MAXFLOAT && gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2])) {
1068 /* We cant use the depth, fallback to the old way that dosnt set the center depth */
1069 new_ofs[0] = rv3d->ofs[0];
1070 new_ofs[1] = rv3d->ofs[1];
1071 new_ofs[2] = rv3d->ofs[2];
1073 initgrabz(rv3d, -new_ofs[0], -new_ofs[1], -new_ofs[2]);
1075 window_to_3d(ar, dvec, (rect.xmin+rect.xmax-vb[0])/2, (rect.ymin+rect.ymax-vb[1])/2);
1076 /* center the view to the center of the rectangle */
1077 VecSubf(new_ofs, new_ofs, dvec);
1080 /* work out the ratios, so that everything selected fits when we zoom */
1081 xscale = ((rect.xmax-rect.xmin)/vb[0]);
1082 yscale = ((rect.ymax-rect.ymin)/vb[1]);
1083 scale = (xscale >= yscale)?xscale:yscale;
1085 /* zoom in as required, or as far as we can go */
1086 new_dist = ((new_dist*scale) >= 0.001*v3d->grid)? new_dist*scale:0.001*v3d->grid;
1089 smooth_view(C, NULL, NULL, new_ofs, NULL, &new_dist, NULL);
1091 return OPERATOR_FINISHED;
1094 static int view3d_border_zoom_invoke(bContext *C, wmOperator *op, wmEvent *event)
1096 RegionView3D *rv3d= CTX_wm_region_view3d(C);
1098 /* if in camera view do not exec the operator so we do not conflict with set render border*/
1099 if (rv3d->persp != V3D_CAMOB)
1100 return WM_border_select_invoke(C, op, event);
1102 return OPERATOR_PASS_THROUGH;
1105 void VIEW3D_OT_border_zoom(wmOperatorType *ot)
1109 ot->name= "Border Zoom";
1110 ot->idname= "VIEW3D_OT_border_zoom";
1113 ot->invoke= view3d_border_zoom_invoke;
1114 ot->exec= view3d_border_zoom_exec;
1115 ot->modal= WM_border_select_modal;
1117 ot->poll= ED_operator_view3d_active;
1120 RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
1121 RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
1122 RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
1123 RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
1126 /* ********************* Changing view operator ****************** */
1128 static EnumPropertyItem prop_view_items[] = {
1129 {V3D_VIEW_FRONT, "FRONT", "Front", "View From the Front"},
1130 {V3D_VIEW_BACK, "BACK", "Back", "View From the Back"},
1131 {V3D_VIEW_LEFT, "LEFT", "Left", "View From the Left"},
1132 {V3D_VIEW_RIGHT, "RIGHT", "Right", "View From the Right"},
1133 {V3D_VIEW_TOP, "TOP", "Top", "View From the Top"},
1134 {V3D_VIEW_BOTTOM, "BOTTOM", "Bottom", "View From the Bottom"},
1135 {V3D_VIEW_PERSPORTHO, "PERSPORTHO", "Persp-Ortho", "Switch between Perspecive and Orthographic View"},
1136 {V3D_VIEW_CAMERA, "CAMERA", "Camera", "View From the active amera"},
1137 {V3D_VIEW_STEPLEFT, "STEPLEFT", "Step Left", "Step the view around to the Left"},
1138 {V3D_VIEW_STEPRIGHT, "STEPRIGHT", "Step Right", "Step the view around to the Right"},
1139 {V3D_VIEW_STEPUP, "STEPUP", "Step Up", "Step the view Up"},
1140 {V3D_VIEW_STEPDOWN, "STEPDOWN", "Step Down", "Step the view Down"},
1141 {V3D_VIEW_PANLEFT, "PANLEFT", "Pan Left", "Pan the view to the Left"},
1142 {V3D_VIEW_PANRIGHT, "PANRIGHT", "Pan Right", "Pan the view to the Right"},
1143 {V3D_VIEW_PANUP, "PANUP", "Pan Up", "Pan the view Up"},
1144 {V3D_VIEW_PANDOWN, "PANDOWN", "Pan Down", "Pan the view Down"},
1145 {0, NULL, NULL, NULL}};
1147 static void axis_set_view(bContext *C, float q1, float q2, float q3, float q4, short view, int perspo)
1149 View3D *v3d = CTX_wm_view3d(C);
1150 RegionView3D *rv3d= CTX_wm_region_view3d(C);
1153 new_quat[0]= q1; new_quat[1]= q2;
1154 new_quat[2]= q3; new_quat[3]= q4;
1158 if (rv3d->persp==V3D_CAMOB && v3d->camera) {
1160 if (U.uiflag & USER_AUTOPERSP) rv3d->persp= V3D_ORTHO;
1161 else if(rv3d->persp==V3D_CAMOB) rv3d->persp= perspo;
1163 smooth_view(C, v3d->camera, NULL, rv3d->ofs, new_quat, NULL, NULL);
1167 if (U.uiflag & USER_AUTOPERSP) rv3d->persp= V3D_ORTHO;
1168 else if(rv3d->persp==V3D_CAMOB) rv3d->persp= perspo;
1170 smooth_view(C, NULL, NULL, NULL, new_quat, NULL, NULL);
1176 static int viewnumpad_exec(bContext *C, wmOperator *op)
1178 ARegion *ar= CTX_wm_region(C);
1179 View3D *v3d = CTX_wm_view3d(C);
1180 RegionView3D *rv3d= CTX_wm_region_view3d(C);
1181 Scene *scene= CTX_data_scene(C);
1182 float phi, si, q1[4], vec[3];
1183 static int perspo=V3D_PERSP;
1186 viewnum = RNA_enum_get(op->ptr, "view");
1188 /* Use this to test if we started out with a camera */
1190 /* Indicate that this view is inverted,
1191 * but only if it actually _was_ inverted (jobbe) */
1192 if (viewnum == V3D_VIEW_BOTTOM || viewnum == V3D_VIEW_BACK || viewnum == V3D_VIEW_LEFT)
1193 rv3d->rflag |= RV3D_OPP_DIRECTION_NAME;
1194 else if (viewnum != V3D_VIEW_PERSPORTHO)
1195 rv3d->rflag &= ~RV3D_OPP_DIRECTION_NAME;
1198 case V3D_VIEW_BOTTOM :
1199 axis_set_view(C, 0.0, -1.0, 0.0, 0.0, 7, perspo);
1203 axis_set_view(C, 0.0, 0.0, (float)-cos(M_PI/4.0), (float)-cos(M_PI/4.0), 1, perspo);
1207 axis_set_view(C, 0.5, -0.5, 0.5, 0.5, 3, perspo);
1211 axis_set_view(C, 1.0, 0.0, 0.0, 0.0, 7, perspo);
1214 case V3D_VIEW_FRONT:
1215 axis_set_view(C, (float)cos(M_PI/4.0), (float)-sin(M_PI/4.0), 0.0, 0.0, 1, perspo);
1218 case V3D_VIEW_RIGHT:
1219 axis_set_view(C, 0.5, -0.5, -0.5, -0.5, 3, perspo);
1222 case V3D_VIEW_PERSPORTHO:
1224 if(rv3d->persp!=V3D_ORTHO)
1225 rv3d->persp=V3D_ORTHO;
1226 else rv3d->persp=V3D_PERSP;
1228 ED_region_tag_redraw(ar);
1231 case V3D_VIEW_CAMERA:
1234 if(rv3d->persp != V3D_CAMOB) {
1235 /* store settings of current view before allowing overwriting with camera view */
1236 QUATCOPY(rv3d->lviewquat, rv3d->viewquat);
1237 rv3d->lview= rv3d->view;
1238 rv3d->lpersp= rv3d->persp;
1241 if(G.qual==LR_ALTKEY) {
1242 if(oldcamera && is_an_active_object(oldcamera)) {
1243 v3d->camera= oldcamera;
1245 handle_view3d_lock();
1250 /* check both G.vd as G.scene cameras */
1251 if((v3d->camera==NULL || scene->camera==NULL) && OBACT->type==OB_CAMERA) {
1253 /*handle_view3d_lock();*/
1257 if(v3d->camera==NULL) {
1258 v3d->camera= scene_find_camera(scene);
1259 /*handle_view3d_lock();*/
1261 rv3d->persp= V3D_CAMOB;
1262 smooth_view(C, NULL, v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, &v3d->lens);
1266 /* return to settings of last view */
1267 /* does smooth_view too */
1268 axis_set_view(C, rv3d->lviewquat[0], rv3d->lviewquat[1], rv3d->lviewquat[2], rv3d->lviewquat[3], rv3d->lview, rv3d->lpersp);
1272 case V3D_VIEW_STEPLEFT:
1273 case V3D_VIEW_STEPRIGHT:
1274 case V3D_VIEW_STEPUP:
1275 case V3D_VIEW_STEPDOWN:
1277 if(rv3d->persp != V3D_CAMOB) {
1278 if(viewnum == V3D_VIEW_STEPLEFT || viewnum == V3D_VIEW_STEPRIGHT) {
1280 phi= (float)(M_PI/360.0)*U.pad_rot_angle;
1281 if(viewnum == V3D_VIEW_STEPRIGHT) phi= -phi;
1282 si= (float)sin(phi);
1283 q1[0]= (float)cos(phi);
1286 QuatMul(rv3d->viewquat, rv3d->viewquat, q1);
1289 if(viewnum == V3D_VIEW_STEPDOWN || viewnum == V3D_VIEW_STEPUP) {
1290 /* horizontal axis */
1291 VECCOPY(q1+1, rv3d->viewinv[0]);
1294 phi= (float)(M_PI/360.0)*U.pad_rot_angle;
1295 if(viewnum == V3D_VIEW_STEPDOWN) phi= -phi;
1296 si= (float)sin(phi);
1297 q1[0]= (float)cos(phi);
1301 QuatMul(rv3d->viewquat, rv3d->viewquat, q1);
1304 ED_region_tag_redraw(ar);
1308 case V3D_VIEW_PANRIGHT:
1309 case V3D_VIEW_PANLEFT:
1310 case V3D_VIEW_PANUP:
1311 case V3D_VIEW_PANDOWN:
1313 initgrabz(rv3d, 0.0, 0.0, 0.0);
1315 if(viewnum == V3D_VIEW_PANRIGHT) window_to_3d(ar, vec, -32, 0);
1316 else if(viewnum == V3D_VIEW_PANLEFT) window_to_3d(ar, vec, 32, 0);
1317 else if(viewnum == V3D_VIEW_PANUP) window_to_3d(ar, vec, 0, -25);
1318 else if(viewnum == V3D_VIEW_PANDOWN) window_to_3d(ar, vec, 0, 25);
1319 rv3d->ofs[0]+= vec[0];
1320 rv3d->ofs[1]+= vec[1];
1321 rv3d->ofs[2]+= vec[2];
1323 ED_region_tag_redraw(ar);
1330 if(rv3d->persp != V3D_CAMOB) perspo= rv3d->persp;
1332 return OPERATOR_FINISHED;
1336 void VIEW3D_OT_viewnumpad(wmOperatorType *ot)
1339 ot->name= "View numpad";
1340 ot->idname= "VIEW3D_OT_viewnumpad";
1343 ot->exec= viewnumpad_exec;
1344 ot->poll= ED_operator_view3d_active;
1345 ot->flag= OPTYPE_REGISTER;
1347 RNA_def_enum(ot->srna, "view", prop_view_items, 0, "View", "");
1350 /* ********************* set clipping operator ****************** */
1352 static int view3d_clipping_exec(bContext *C, wmOperator *op)
1354 RegionView3D *rv3d= CTX_wm_region_view3d(C);
1356 double mvmatrix[16];
1357 double projmatrix[16];
1358 double xs, ys, p[3];
1362 rect.xmin= RNA_int_get(op->ptr, "xmin");
1363 rect.ymin= RNA_int_get(op->ptr, "ymin");
1364 rect.xmax= RNA_int_get(op->ptr, "xmax");
1365 rect.ymax= RNA_int_get(op->ptr, "ymax");
1367 rv3d->rflag |= RV3D_CLIPPING;
1368 rv3d->clipbb= MEM_callocN(sizeof(BoundBox), "clipbb");
1370 /* note; otherwise opengl won't work */
1371 view3d_operator_needs_opengl(C);
1373 /* Get the matrices needed for gluUnProject */
1374 glGetIntegerv(GL_VIEWPORT, viewport);
1375 glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
1376 glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
1378 /* near zero floating point values can give issues with gluUnProject
1379 in side view on some implementations */
1380 if(fabs(mvmatrix[0]) < 1e-6) mvmatrix[0]= 0.0;
1381 if(fabs(mvmatrix[5]) < 1e-6) mvmatrix[5]= 0.0;
1383 /* Set up viewport so that gluUnProject will give correct values */
1387 /* four clipping planes and bounding volume */
1388 /* first do the bounding volume */
1389 for(val=0; val<4; val++) {
1391 xs= (val==0||val==3)?rect.xmin:rect.xmax;
1392 ys= (val==0||val==1)?rect.ymin:rect.ymax;
1394 gluUnProject(xs, ys, 0.0, mvmatrix, projmatrix, viewport, &p[0], &p[1], &p[2]);
1395 VECCOPY(rv3d->clipbb->vec[val], p);
1397 gluUnProject(xs, ys, 1.0, mvmatrix, projmatrix, viewport, &p[0], &p[1], &p[2]);
1398 VECCOPY(rv3d->clipbb->vec[4+val], p);
1401 /* then plane equations */
1402 for(val=0; val<4; val++) {
1404 CalcNormFloat(rv3d->clipbb->vec[val], rv3d->clipbb->vec[val==3?0:val+1], rv3d->clipbb->vec[val+4],
1407 rv3d->clip[val][3]= - rv3d->clip[val][0]*rv3d->clipbb->vec[val][0]
1408 - rv3d->clip[val][1]*rv3d->clipbb->vec[val][1]
1409 - rv3d->clip[val][2]*rv3d->clipbb->vec[val][2];
1411 return OPERATOR_FINISHED;
1414 static int view3d_clipping_invoke(bContext *C, wmOperator *op, wmEvent *event)
1416 RegionView3D *rv3d= CTX_wm_region_view3d(C);
1417 ARegion *ar= CTX_wm_region(C);
1419 if(rv3d->rflag & RV3D_CLIPPING) {
1420 rv3d->rflag &= ~RV3D_CLIPPING;
1421 ED_region_tag_redraw(ar);
1422 if(rv3d->clipbb) MEM_freeN(rv3d->clipbb);
1424 return OPERATOR_FINISHED;
1427 return WM_border_select_invoke(C, op, event);
1432 void VIEW3D_OT_clipping(wmOperatorType *ot)
1436 ot->name= "Border Select";
1437 ot->idname= "VIEW3D_OT_clipping";
1440 ot->invoke= view3d_clipping_invoke;
1441 ot->exec= view3d_clipping_exec;
1442 ot->modal= WM_border_select_modal;
1444 ot->poll= ED_operator_view3d_active;
1447 RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
1448 RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
1449 RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
1450 RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
1453 /* ********************* draw type operator ****************** */
1455 static int view3d_drawtype_exec(bContext *C, wmOperator *op)
1457 View3D *v3d = CTX_wm_view3d(C);
1460 dt = RNA_int_get(op->ptr, "draw_type");
1461 dt_alt = RNA_int_get(op->ptr, "draw_type_alternate");
1464 if (v3d->drawtype == dt)
1465 v3d->drawtype = dt_alt;
1472 ED_area_tag_redraw(CTX_wm_area(C));
1474 return OPERATOR_FINISHED;
1477 static int view3d_drawtype_invoke(bContext *C, wmOperator *op, wmEvent *event)
1479 return view3d_drawtype_exec(C, op);
1483 void VIEW3D_OT_drawtype(wmOperatorType *ot)
1486 ot->name= "Change draw type";
1487 ot->idname= "VIEW3D_OT_drawtype";
1490 ot->invoke= view3d_drawtype_invoke;
1491 ot->exec= view3d_drawtype_exec;
1493 ot->poll= ED_operator_view3d_active;
1495 /* rna XXX should become enum */
1496 RNA_def_int(ot->srna, "draw_type", 0, INT_MIN, INT_MAX, "Draw Type", "", INT_MIN, INT_MAX);
1497 RNA_def_int(ot->srna, "draw_type_alternate", -1, INT_MIN, INT_MAX, "Draw Type Alternate", "", INT_MIN, INT_MAX);
1500 /* ***************** 3d cursor cursor op ******************* */
1502 /* mx my in region coords */
1503 static int set_3dcursor_invoke(bContext *C, wmOperator *op, wmEvent *event)
1505 Scene *scene= CTX_data_scene(C);
1506 ARegion *ar= CTX_wm_region(C);
1507 View3D *v3d = CTX_wm_view3d(C);
1508 RegionView3D *rv3d= CTX_wm_region_view3d(C);
1509 float dx, dy, fz, *fp = NULL, dvec[3], oldcurs[3];
1510 short mx, my, mval[2];
1511 // short ctrl= 0; // XXX
1513 fp= give_cursor(scene, v3d);
1515 // if(obedit && ctrl) lr_click= 1;
1516 VECCOPY(oldcurs, fp);
1518 mx= event->x - ar->winrct.xmin;
1519 my= event->y - ar->winrct.ymin;
1520 project_short_noclip(ar, fp, mval);
1522 initgrabz(rv3d, fp[0], fp[1], fp[2]);
1524 if(mval[0]!=IS_CLIPPED) {
1526 window_to_3d(ar, dvec, mval[0]-mx, mval[1]-my);
1527 VecSubf(fp, fp, dvec);
1531 dx= ((float)(mx-(ar->winx/2)))*rv3d->zfac/(ar->winx/2);
1532 dy= ((float)(my-(ar->winy/2)))*rv3d->zfac/(ar->winy/2);
1534 fz= rv3d->persmat[0][3]*fp[0]+ rv3d->persmat[1][3]*fp[1]+ rv3d->persmat[2][3]*fp[2]+ rv3d->persmat[3][3];
1537 fp[0]= (rv3d->persinv[0][0]*dx + rv3d->persinv[1][0]*dy+ rv3d->persinv[2][0]*fz)-rv3d->ofs[0];
1538 fp[1]= (rv3d->persinv[0][1]*dx + rv3d->persinv[1][1]*dy+ rv3d->persinv[2][1]*fz)-rv3d->ofs[1];
1539 fp[2]= (rv3d->persinv[0][2]*dx + rv3d->persinv[1][2]*dy+ rv3d->persinv[2][2]*fz)-rv3d->ofs[2];
1543 // XXX if(obedit->type==OB_MESH) add_click_mesh();
1544 // else if ELEM(obedit->type, OB_CURVE, OB_SURF) addvert_Nurb(0);
1545 // else if (obedit->type==OB_ARMATURE) addvert_armature();
1546 // VECCOPY(fp, oldcurs);
1548 // XXX notifier for scene */
1549 ED_region_tag_redraw(ar);
1551 /* prevent other mouse ops to fail */
1552 return OPERATOR_PASS_THROUGH;
1555 void VIEW3D_OT_cursor3d(wmOperatorType *ot)
1559 ot->name= "Set 3D Cursor";
1560 ot->idname= "VIEW3D_OT_cursor3d";
1563 ot->invoke= set_3dcursor_invoke;
1565 ot->poll= ED_operator_view3d_active;
1572 /* ************************* below the line! *********************** */
1575 /* XXX todo Zooms in on a border drawn by the user */
1576 int view_autodist(Scene *scene, ARegion *ar, View3D *v3d, short *mval, float mouse_worldloc[3] ) //, float *autodist )
1578 RegionView3D *rv3d= ar->regiondata;
1579 bglMats mats; /* ZBuffer depth vars */
1581 float depth, depth_close= MAXFLOAT;
1583 double cent[2], p[3];
1586 rect.xmax = mval[0] + 4;
1587 rect.ymax = mval[1] + 4;
1589 rect.xmin = mval[0] - 4;
1590 rect.ymin = mval[1] - 4;
1592 /* Get Z Depths, needed for perspective, nice for ortho */
1593 bgl_get_mats(&mats);
1594 draw_depth(scene, ar, v3d, NULL);
1596 /* force updating */
1599 rv3d->depths->damaged = 1;
1602 view3d_update_depths(ar, v3d);
1604 /* Constrain rect to depth bounds */
1605 if (rect.xmin < 0) rect.xmin = 0;
1606 if (rect.ymin < 0) rect.ymin = 0;
1607 if (rect.xmax >= rv3d->depths->w) rect.xmax = rv3d->depths->w-1;
1608 if (rect.ymax >= rv3d->depths->h) rect.ymax = rv3d->depths->h-1;
1610 /* Find the closest Z pixel */
1611 for (xs=rect.xmin; xs < rect.xmax; xs++) {
1612 for (ys=rect.ymin; ys < rect.ymax; ys++) {
1613 depth= rv3d->depths->depths[ys*rv3d->depths->w+xs];
1614 if(depth < rv3d->depths->depth_range[1] && depth > rv3d->depths->depth_range[0]) {
1615 if (depth_close > depth) {
1616 depth_close = depth;
1622 if (depth_close==MAXFLOAT)
1626 MEM_freeN(rv3d->depths->depths);
1627 rv3d->depths->depths = NULL;
1629 rv3d->depths->damaged = 1;
1631 cent[0] = (double)mval[0];
1632 cent[1] = (double)mval[1];
1634 if (!gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2]))
1637 mouse_worldloc[0] = (float)p[0];
1638 mouse_worldloc[1] = (float)p[1];
1639 mouse_worldloc[2] = (float)p[2];
1645 /* ********************* NDOF ************************ */
1646 /* note: this code is confusing and unclear... (ton) */
1647 /* **************************************************** */
1649 // ndof scaling will be moved to user setting.
1650 // In the mean time this is just a place holder.
1652 // Note: scaling in the plugin and ghostwinlay.c
1653 // should be removed. With driver default setting,
1654 // each axis returns approx. +-200 max deflection.
1656 // The values I selected are based on the older
1657 // polling i/f. With event i/f, the sensistivity
1658 // can be increased for improved response from
1659 // small deflections of the device input.
1662 // lukep notes : i disagree on the range.
1663 // the normal 3Dconnection driver give +/-400
1664 // on defaut range in other applications
1665 // and up to +/- 1000 if set to maximum
1666 // because i remove the scaling by delta,
1667 // which was a bad idea as it depend of the system
1668 // speed and os, i changed the scaling values, but
1669 // those are still not ok
1672 float ndof_axis_scale[6] = {
1681 void filterNDOFvalues(float *sbval)
1687 if (fabs(sbval[i]) > max)
1688 max = fabs(sbval[i]);
1690 if (fabs(sbval[i]) != max )
1694 // statics for controlling rv3d->dist corrections.
1695 // viewmoveNDOF zeros and adjusts rv3d->ofs.
1696 // viewmove restores based on dz_flag state.
1701 void viewmoveNDOFfly(ARegion *ar, View3D *v3d, int mode)
1703 RegionView3D *rv3d= ar->regiondata;
1707 // static fval[6] for low pass filter; device input vector is dval[6]
1708 static float fval[6];
1709 float tvec[3],rvec[3];
1715 /*----------------------------------------------------
1716 * sometimes this routine is called from headerbuttons
1717 * viewmove needs to refresh the screen
1719 // XXX areawinset(ar->win);
1722 // fetch the current state of the ndof device
1723 // XXX getndof(dval);
1725 if (v3d->ndoffilter)
1726 filterNDOFvalues(fval);
1728 // Scale input values
1730 // if(dval[6] == 0) return; // guard against divide by zero
1735 dval[i] = dval[i] * ndof_axis_scale[i];
1739 // low pass filter with zero crossing reset
1742 if((dval[i] * fval[i]) >= 0)
1743 dval[i] = (fval[i] * 15 + dval[i]) / 16;
1749 // force perspective mode. This is a hack and is
1750 // incomplete. It doesn't actually effect the view
1751 // until the first draw and doesn't update the menu
1752 // to reflect persp mode.
1754 rv3d->persp = V3D_PERSP;
1757 // Correct the distance jump if rv3d->dist != 0
1759 // This is due to a side effect of the original
1760 // mouse view rotation code. The rotation point is
1761 // set a distance in front of the viewport to
1762 // make rotating with the mouse look better.
1763 // The distance effect is written at a low level
1764 // in the view management instead of the mouse
1765 // view function. This means that all other view
1766 // movement devices must subtract this from their
1767 // view transformations.
1769 if(rv3d->dist != 0.0) {
1771 m_dist = rv3d->dist;
1772 upvec[0] = upvec[1] = 0;
1773 upvec[2] = rv3d->dist;
1774 Mat3CpyMat4(mat, rv3d->viewinv);
1775 Mat3MulVecfl(mat, upvec);
1776 VecSubf(rv3d->ofs, rv3d->ofs, upvec);
1782 // Rotations feel relatively faster than translations only in fly mode, so
1783 // we have no choice but to fix that here (not in the plugins)
1784 rvec[0] = -0.5 * dval[3];
1785 rvec[1] = -0.5 * dval[4];
1786 rvec[2] = -0.5 * dval[5];
1788 // rotate device x and y by view z
1790 Mat3CpyMat4(mat, rv3d->viewinv);
1792 Mat3MulVecfl(mat, rvec);
1796 phi = Normalize(rvec);
1798 VecRotToQuat(rvec,phi,q1);
1799 QuatMul(rv3d->viewquat, rv3d->viewquat, q1);
1803 // Apply translation
1809 // the next three lines rotate the x and y translation coordinates
1810 // by the current z axis angle
1812 Mat3CpyMat4(mat, rv3d->viewinv);
1814 Mat3MulVecfl(mat, tvec);
1816 // translate the view
1818 VecSubf(rv3d->ofs, rv3d->ofs, tvec);
1821 /*----------------------------------------------------
1822 * refresh the screen XXX
1825 // update render preview window
1827 // XXX BIF_view3d_previewrender_signal(ar, PR_DBASE|PR_DISPRECT);
1830 void viewmoveNDOF(Scene *scene, ARegion *ar, View3D *v3d, int mode)
1832 RegionView3D *rv3d= ar->regiondata;
1835 float sbadjust = 1.0f;
1841 float xvec[3] = {1,0,0};
1842 float yvec[3] = {0,-1,0};
1843 float zvec[3] = {0,0,1};
1849 float d, curareaX, curareaY;
1853 /* Sensitivity will control how fast the view rotates. The value was
1854 * obtained experimentally by tweaking until the author didn't get dizzy watching.
1855 * Perhaps this should be a configurable user parameter.
1857 float psens = 0.005f * (float) U.ndof_pan; /* pan sensitivity */
1858 float rsens = 0.005f * (float) U.ndof_rotate; /* rotate sensitivity */
1859 float zsens = 0.3f; /* zoom sensitivity */
1861 const float minZoom = -30.0f;
1862 const float maxZoom = 300.0f;
1866 //printf("passing here \n");
1868 if (scene->obedit==NULL && ob && !(ob->flag & OB_POSEMODE)) {
1872 if((dz_flag)||rv3d->dist==0) {
1874 rv3d->dist = m_dist;
1875 upvec[0] = upvec[1] = 0;
1876 upvec[2] = rv3d->dist;
1877 Mat3CpyMat4(mat, rv3d->viewinv);
1878 Mat3MulVecfl(mat, upvec);
1879 VecAddf(rv3d->ofs, rv3d->ofs, upvec);
1882 /*----------------------------------------------------
1883 * sometimes this routine is called from headerbuttons
1884 * viewmove needs to refresh the screen
1886 // XXX areawinset(curarea->win);
1888 /*----------------------------------------------------
1889 * record how much time has passed. clamp at 10 Hz
1890 * pretend the previous frame occured at the clamped time
1892 // now = PIL_check_seconds_timer();
1893 // frametime = (now - prevTime);
1894 // if (frametime > 0.1f){ /* if more than 1/10s */
1895 // frametime = 1.0f/60.0; /* clamp at 1/60s so no jumps when starting to move */
1898 // sbadjust *= 60 * frametime; /* normalize ndof device adjustments to 100Hz for framerate independence */
1900 /* fetch the current state of the ndof device & enforce dominant mode if selected */
1901 // XXX getndof(fval);
1902 if (v3d->ndoffilter)
1903 filterNDOFvalues(fval);
1906 // put scaling back here, was previously in ghostwinlay
1907 fval[0] = fval[0] * (1.0f/600.0f);
1908 fval[1] = fval[1] * (1.0f/600.0f);
1909 fval[2] = fval[2] * (1.0f/1100.0f);
1910 fval[3] = fval[3] * 0.00005f;
1911 fval[4] =-fval[4] * 0.00005f;
1912 fval[5] = fval[5] * 0.00005f;
1913 fval[6] = fval[6] / 1000000.0f;
1915 // scale more if not in perspective mode
1916 if (rv3d->persp == V3D_ORTHO) {
1917 fval[0] = fval[0] * 0.05f;
1918 fval[1] = fval[1] * 0.05f;
1919 fval[2] = fval[2] * 0.05f;
1920 fval[3] = fval[3] * 0.9f;
1921 fval[4] = fval[4] * 0.9f;
1922 fval[5] = fval[5] * 0.9f;
1926 /* set object offset */
1928 obofs[0] = -ob->obmat[3][0];
1929 obofs[1] = -ob->obmat[3][1];
1930 obofs[2] = -ob->obmat[3][2];
1933 VECCOPY(obofs, rv3d->ofs);
1936 /* calc an adjustment based on distance from camera
1937 disabled per patch 14402 */
1941 VecSubf(diff, obofs, rv3d->ofs);
1942 d = VecLength(diff);
1946 reverse = (rv3d->persmat[2][1] < 0.0f) ? -1.0f : 1.0f;
1948 /*----------------------------------------------------
1952 curareaX = sbadjust * psens * fval[0];
1953 curareaY = sbadjust * psens * fval[1];
1954 dvec[0] = curareaX * rv3d->persinv[0][0] + curareaY * rv3d->persinv[1][0];
1955 dvec[1] = curareaX * rv3d->persinv[0][1] + curareaY * rv3d->persinv[1][1];
1956 dvec[2] = curareaX * rv3d->persinv[0][2] + curareaY * rv3d->persinv[1][2];
1957 VecAddf(rv3d->ofs, rv3d->ofs, dvec);
1959 /*----------------------------------------------------
1962 len = zsens * sbadjust * fval[2];
1964 if (rv3d->persp==V3D_CAMOB) {
1965 if(rv3d->persp==V3D_CAMOB) { /* This is stupid, please fix - TODO */
1966 rv3d->camzoom+= 10.0f * -len;
1968 if (rv3d->camzoom < minZoom) rv3d->camzoom = minZoom;
1969 else if (rv3d->camzoom > maxZoom) rv3d->camzoom = maxZoom;
1971 else if ((rv3d->dist> 0.001*v3d->grid) && (rv3d->dist<10.0*v3d->far)) {
1972 rv3d->dist*=(1.0 + len);
1976 /*----------------------------------------------------
1977 * ndof device turntable
1978 * derived from the turntable code in viewmove
1981 /* Get the 3x3 matrix and its inverse from the quaternion */
1982 QuatToMat3(rv3d->viewquat, m);
1985 /* Determine the direction of the x vector (for rotating up and down) */
1986 /* This can likely be compuated directly from the quaternion. */
1987 Mat3MulVecfl(m_inv,xvec);
1988 Mat3MulVecfl(m_inv,yvec);
1989 Mat3MulVecfl(m_inv,zvec);
1991 /* Perform the up/down rotation */
1992 phi = sbadjust * rsens * /*0.5f * */ fval[3]; /* spin vertically half as fast as horizontally */
1995 q1[1] = si * xvec[0];
1996 q1[2] = si * xvec[1];
1997 q1[3] = si * xvec[2];
1998 QuatMul(rv3d->viewquat, rv3d->viewquat, q1);
2001 QuatConj(q1); /* conj == inv for unit quat */
2002 VecSubf(v3d->ofs, v3d->ofs, obofs);
2003 QuatMulVecf(q1, rv3d->ofs);
2004 VecAddf(rv3d->ofs, rv3d->ofs, obofs);
2007 /* Perform the orbital rotation */
2008 /* Perform the orbital rotation
2009 If the seen Up axis is parallel to the zoom axis, rotation should be
2010 achieved with a pure Roll motion (no Spin) on the device. When you start
2011 to tilt, moving from Top to Side view, Spinning will increasingly become
2012 more relevant while the Roll component will decrease. When a full
2013 Side view is reached, rotations around the world's Up axis are achieved
2014 with a pure Spin-only motion. In other words the control of the spinning
2015 around the world's Up axis should move from the device's Spin axis to the
2016 device's Roll axis depending on the orientation of the world's Up axis
2017 relative to the screen. */
2018 //phi = sbadjust * rsens * reverse * fval[4]; /* spin the knob, y axis */
2019 phi = sbadjust * rsens * (yvec[2] * fval[4] + zvec[2] * fval[5]);
2021 q1[1] = q1[2] = 0.0;
2023 QuatMul(rv3d->viewquat, rv3d->viewquat, q1);
2027 VecSubf(rv3d->ofs, rv3d->ofs, obofs);
2028 QuatMulVecf(q1, rv3d->ofs);
2029 VecAddf(rv3d->ofs, rv3d->ofs, obofs);
2032 /*----------------------------------------------------
2033 * refresh the screen
2035 // XXX scrarea_do_windraw(curarea);