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_report.h"
58 #include "BKE_scene.h"
59 #include "BKE_screen.h"
60 #include "BKE_utildefines.h"
62 #include "RE_pipeline.h" // make_stars
69 #include "RNA_access.h"
70 #include "RNA_define.h"
72 #include "ED_particle.h"
73 #include "ED_retopo.h"
74 #include "ED_space_api.h"
75 #include "ED_screen.h"
76 #include "ED_transform.h"
79 #include "UI_interface.h"
80 #include "UI_resources.h"
81 #include "UI_view2d.h"
83 #include "PIL_time.h" /* smoothview */
85 #include "view3d_intern.h" // own include
87 /* ********************** view3d_edit: view manipulations ********************* */
89 /* ********************* box view support ***************** */
91 static void view3d_boxview_clip(ScrArea *sa)
94 BoundBox *bb = MEM_callocN(sizeof(BoundBox), "clipbb");
96 float x1= 0.0f, y1= 0.0f, z1= 0.0f, ofs[3];
99 /* create bounding box */
100 for(ar= sa->regionbase.first; ar; ar= ar->next) {
101 if(ar->regiontype==RGN_TYPE_WINDOW) {
102 RegionView3D *rv3d= ar->regiondata;
104 if(rv3d->viewlock & RV3D_BOXCLIP) {
105 if(ELEM(rv3d->view, V3D_VIEW_TOP, V3D_VIEW_BOTTOM)) {
106 if(ar->winx>ar->winy) x1= rv3d->dist;
107 else x1= ar->winx*rv3d->dist/ar->winy;
109 if(ar->winx>ar->winy) y1= ar->winy*rv3d->dist/ar->winx;
112 ofs[0]= rv3d->ofs[0];
113 ofs[1]= rv3d->ofs[1];
115 else if(ELEM(rv3d->view, V3D_VIEW_FRONT, V3D_VIEW_BACK)) {
116 ofs[2]= rv3d->ofs[2];
118 if(ar->winx>ar->winy) z1= ar->winy*rv3d->dist/ar->winx;
125 for(val=0; val<8; val++) {
126 if(ELEM4(val, 0, 3, 4, 7))
127 bb->vec[val][0]= -x1 - ofs[0];
129 bb->vec[val][0]= x1 - ofs[0];
131 if(ELEM4(val, 0, 1, 4, 5))
132 bb->vec[val][1]= -y1 - ofs[1];
134 bb->vec[val][1]= y1 - ofs[1];
137 bb->vec[val][2]= -z1 - ofs[2];
139 bb->vec[val][2]= z1 - ofs[2];
142 /* normals for plane equations */
143 CalcNormFloat(bb->vec[0], bb->vec[1], bb->vec[4], clip[0]);
144 CalcNormFloat(bb->vec[1], bb->vec[2], bb->vec[5], clip[1]);
145 CalcNormFloat(bb->vec[2], bb->vec[3], bb->vec[6], clip[2]);
146 CalcNormFloat(bb->vec[3], bb->vec[0], bb->vec[7], clip[3]);
147 CalcNormFloat(bb->vec[4], bb->vec[5], bb->vec[6], clip[4]);
148 CalcNormFloat(bb->vec[0], bb->vec[2], bb->vec[1], clip[5]);
150 /* then plane equations */
151 for(val=0; val<5; val++) {
152 clip[val][3]= - clip[val][0]*bb->vec[val][0] - clip[val][1]*bb->vec[val][1] - clip[val][2]*bb->vec[val][2];
154 clip[5][3]= - clip[5][0]*bb->vec[0][0] - clip[5][1]*bb->vec[0][1] - clip[5][2]*bb->vec[0][2];
156 /* create bounding box */
157 for(ar= sa->regionbase.first; ar; ar= ar->next) {
158 if(ar->regiontype==RGN_TYPE_WINDOW) {
159 RegionView3D *rv3d= ar->regiondata;
161 if(rv3d->viewlock & RV3D_BOXCLIP) {
162 rv3d->rflag |= RV3D_CLIPPING;
163 memcpy(rv3d->clip, clip, sizeof(clip));
170 /* sync center/zoom view of region to others, for view transforms */
171 static void view3d_boxview_sync(ScrArea *sa, ARegion *ar)
174 RegionView3D *rv3d= ar->regiondata;
176 for(artest= sa->regionbase.first; artest; artest= artest->next) {
177 if(artest!=ar && artest->regiontype==RGN_TYPE_WINDOW) {
178 RegionView3D *rv3dtest= artest->regiondata;
180 if(rv3dtest->viewlock) {
181 rv3dtest->dist= rv3d->dist;
183 if( ELEM(rv3d->view, V3D_VIEW_TOP, V3D_VIEW_BOTTOM) ) {
184 if( ELEM(rv3dtest->view, V3D_VIEW_FRONT, V3D_VIEW_BACK))
185 rv3dtest->ofs[0]= rv3d->ofs[0];
186 else if( ELEM(rv3dtest->view, V3D_VIEW_RIGHT, V3D_VIEW_LEFT))
187 rv3dtest->ofs[1]= rv3d->ofs[1];
189 else if( ELEM(rv3d->view, V3D_VIEW_FRONT, V3D_VIEW_BACK) ) {
190 if( ELEM(rv3dtest->view, V3D_VIEW_TOP, V3D_VIEW_BOTTOM))
191 rv3dtest->ofs[0]= rv3d->ofs[0];
192 else if( ELEM(rv3dtest->view, V3D_VIEW_RIGHT, V3D_VIEW_LEFT))
193 rv3dtest->ofs[2]= rv3d->ofs[2];
195 else if( ELEM(rv3d->view, V3D_VIEW_RIGHT, V3D_VIEW_LEFT) ) {
196 if( ELEM(rv3dtest->view, V3D_VIEW_TOP, V3D_VIEW_BOTTOM))
197 rv3dtest->ofs[1]= rv3d->ofs[1];
198 if( ELEM(rv3dtest->view, V3D_VIEW_FRONT, V3D_VIEW_BACK))
199 rv3dtest->ofs[2]= rv3d->ofs[2];
202 ED_region_tag_redraw(artest);
206 view3d_boxview_clip(sa);
209 /* for home, center etc */
210 void view3d_boxview_copy(ScrArea *sa, ARegion *ar)
213 RegionView3D *rv3d= ar->regiondata;
215 for(artest= sa->regionbase.first; artest; artest= artest->next) {
216 if(artest!=ar && artest->regiontype==RGN_TYPE_WINDOW) {
217 RegionView3D *rv3dtest= artest->regiondata;
219 if(rv3dtest->viewlock) {
220 rv3dtest->dist= rv3d->dist;
221 VECCOPY(rv3dtest->ofs, rv3d->ofs);
222 ED_region_tag_redraw(artest);
226 view3d_boxview_clip(sa);
229 /* ************************** init for view ops **********************************/
231 typedef struct ViewOpsData {
238 float ofs[3], obofs[3];
239 float reverse, dist0;
242 int origx, origy, oldx, oldy;
247 #define TRACKBALLSIZE (1.1)
249 static void calctrackballvec(rcti *rect, int mx, int my, float *vec)
251 float x, y, radius, d, z, t;
253 radius= TRACKBALLSIZE;
255 /* normalize x and y */
256 x= (rect->xmax + rect->xmin)/2 - mx;
257 x/= (float)((rect->xmax - rect->xmin)/4);
258 y= (rect->ymax + rect->ymin)/2 - my;
259 y/= (float)((rect->ymax - rect->ymin)/2);
262 if (d < radius*M_SQRT1_2) /* Inside sphere */
263 z = sqrt(radius*radius - d*d);
266 t = radius / M_SQRT2;
272 vec[2]= -z; /* yah yah! */
276 static void viewops_data(bContext *C, wmOperator *op, wmEvent *event)
278 View3D *v3d = CTX_wm_view3d(C);
280 ViewOpsData *vod= MEM_callocN(sizeof(ViewOpsData), "viewops data");
284 vod->sa= CTX_wm_area(C);
285 vod->ar= CTX_wm_region(C);
286 vod->rv3d= rv3d= vod->ar->regiondata;
287 vod->dist0= rv3d->dist;
288 QUATCOPY(vod->oldquat, rv3d->viewquat);
289 vod->origx= vod->oldx= event->x;
290 vod->origy= vod->oldy= event->y;
291 vod->origkey= event->type;
293 /* lookup, we dont pass on v3d to prevent confusement */
294 vod->grid= v3d->grid;
297 calctrackballvec(&vod->ar->winrct, event->x, event->y, vod->trackvec);
299 initgrabz(rv3d, -rv3d->ofs[0], -rv3d->ofs[1], -rv3d->ofs[2]);
302 if (rv3d->persmat[2][1] < 0.0f)
307 /* ************************** viewrotate **********************************/
309 static const float thres = 0.93f; //cos(20 deg);
311 #define COS45 0.70710678118654746
314 static float snapquats[39][6] = {
315 /*{q0, q1, q3, q4, view, oposite_direction}*/
316 {COS45, -SIN45, 0.0, 0.0, V3D_VIEW_FRONT, 0}, //front
317 {0.0, 0.0, -SIN45, -SIN45, V3D_VIEW_BACK, 0}, //back
318 {1.0, 0.0, 0.0, 0.0, V3D_VIEW_TOP, 0}, //top
319 {0.0, -1.0, 0.0, 0.0, V3D_VIEW_BOTTOM, 0}, //bottom
320 {0.5, -0.5, -0.5, -0.5, V3D_VIEW_LEFT, 0}, //left
321 {0.5, -0.5, 0.5, 0.5, V3D_VIEW_RIGHT, 0}, //right
323 /* some more 45 deg snaps */
324 {0.65328145027160645, -0.65328145027160645, 0.27059805393218994, 0.27059805393218994, 0, 0},
325 {0.92387950420379639, 0.0, 0.0, 0.38268342614173889, 0, 0},
326 {0.0, -0.92387950420379639, 0.38268342614173889, 0.0, 0, 0},
327 {0.35355335474014282, -0.85355335474014282, 0.35355338454246521, 0.14644660055637360, 0, 0},
328 {0.85355335474014282, -0.35355335474014282, 0.14644660055637360, 0.35355338454246521, 0, 0},
329 {0.49999994039535522, -0.49999994039535522, 0.49999997019767761, 0.49999997019767761, 0, 0},
330 {0.27059802412986755, -0.65328145027160645, 0.65328145027160645, 0.27059802412986755, 0, 0},
331 {0.65328145027160645, -0.27059802412986755, 0.27059802412986755, 0.65328145027160645, 0, 0},
332 {0.27059799432754517, -0.27059799432754517, 0.65328139066696167, 0.65328139066696167, 0, 0},
333 {0.38268336653709412, 0.0, 0.0, 0.92387944459915161, 0, 0},
334 {0.0, -0.38268336653709412, 0.92387944459915161, 0.0, 0, 0},
335 {0.14644658565521240, -0.35355335474014282, 0.85355335474014282, 0.35355335474014282, 0, 0},
336 {0.35355335474014282, -0.14644658565521240, 0.35355335474014282, 0.85355335474014282, 0, 0},
337 {0.0, 0.0, 0.92387944459915161, 0.38268336653709412, 0, 0},
338 {-0.0, 0.0, 0.38268336653709412, 0.92387944459915161, 0, 0},
339 {-0.27059802412986755, 0.27059802412986755, 0.65328133106231689, 0.65328133106231689, 0, 0},
340 {-0.38268339633941650, 0.0, 0.0, 0.92387938499450684, 0, 0},
341 {0.0, 0.38268339633941650, 0.92387938499450684, 0.0, 0, 0},
342 {-0.14644658565521240, 0.35355338454246521, 0.85355329513549805, 0.35355332493782043, 0, 0},
343 {-0.35355338454246521, 0.14644658565521240, 0.35355332493782043, 0.85355329513549805, 0, 0},
344 {-0.49999991059303284, 0.49999991059303284, 0.49999985098838806, 0.49999985098838806, 0, 0},
345 {-0.27059799432754517, 0.65328145027160645, 0.65328139066696167, 0.27059799432754517, 0, 0},
346 {-0.65328145027160645, 0.27059799432754517, 0.27059799432754517, 0.65328139066696167, 0, 0},
347 {-0.65328133106231689, 0.65328133106231689, 0.27059793472290039, 0.27059793472290039, 0, 0},
348 {-0.92387932538986206, 0.0, 0.0, 0.38268333673477173, 0, 0},
349 {0.0, 0.92387932538986206, 0.38268333673477173, 0.0, 0, 0},
350 {-0.35355329513549805, 0.85355329513549805, 0.35355329513549805, 0.14644657075405121, 0, 0},
351 {-0.85355329513549805, 0.35355329513549805, 0.14644657075405121, 0.35355329513549805, 0, 0},
352 {-0.38268330693244934, 0.92387938499450684, 0.0, 0.0, 0, 0},
353 {-0.92387938499450684, 0.38268330693244934, 0.0, 0.0, 0, 0},
354 {-COS45, 0.0, 0.0, SIN45, 0, 0},
355 {COS45, 0.0, 0.0, SIN45, 0, 0},
356 {0.0, 0.0, 0.0, 1.0, 0, 0}
360 static void viewrotate_apply(ViewOpsData *vod, int x, int y, int ctrl)
362 RegionView3D *rv3d= vod->rv3d;
363 int use_sel= 0; /* XXX */
365 rv3d->view= 0; /* need to reset everytime because of view snapping */
367 if (U.flag & USER_TRACKBALL) {
368 float phi, si, q1[4], dvec[3], newvec[3];
370 calctrackballvec(&vod->ar->winrct, x, y, newvec);
372 VecSubf(dvec, newvec, vod->trackvec);
374 si= sqrt(dvec[0]*dvec[0]+ dvec[1]*dvec[1]+ dvec[2]*dvec[2]);
375 si/= (2.0*TRACKBALLSIZE);
377 Crossf(q1+1, vod->trackvec, newvec);
380 /* Allow for rotation beyond the interval
385 /* This relation is used instead of
386 * phi = asin(si) so that the angle
387 * of rotation is linearly proportional
388 * to the distance that the mouse is
390 phi = si * M_PI / 2.0;
397 QuatMul(rv3d->viewquat, q1, vod->oldquat);
400 /* compute the post multiplication quat, to rotate the offset correctly */
401 QUATCOPY(q1, vod->oldquat);
403 QuatMul(q1, q1, rv3d->viewquat);
405 QuatConj(q1); /* conj == inv for unit quat */
406 VECCOPY(rv3d->ofs, vod->ofs);
407 VecSubf(rv3d->ofs, rv3d->ofs, vod->obofs);
408 QuatMulVecf(q1, rv3d->ofs);
409 VecAddf(rv3d->ofs, rv3d->ofs, vod->obofs);
413 /* New turntable view code by John Aughey */
414 float si, phi, q1[4];
417 float xvec[3] = {1,0,0};
418 /* Sensitivity will control how fast the viewport rotates. 0.0035 was
419 obtained experimentally by looking at viewport rotation sensitivities
420 on other modeling programs. */
421 /* Perhaps this should be a configurable user parameter. */
422 const float sensitivity = 0.0035;
424 /* Get the 3x3 matrix and its inverse from the quaternion */
425 QuatToMat3(rv3d->viewquat, m);
428 /* Determine the direction of the x vector (for rotating up and down) */
429 /* This can likely be compuated directly from the quaternion. */
430 Mat3MulVecfl(m_inv,xvec);
432 /* Perform the up/down rotation */
433 phi = sensitivity * -(y - vod->oldy);
436 q1[1] = si * xvec[0];
437 q1[2] = si * xvec[1];
438 q1[3] = si * xvec[2];
439 QuatMul(rv3d->viewquat, rv3d->viewquat, q1);
442 QuatConj(q1); /* conj == inv for unit quat */
443 VecSubf(rv3d->ofs, rv3d->ofs, vod->obofs);
444 QuatMulVecf(q1, rv3d->ofs);
445 VecAddf(rv3d->ofs, rv3d->ofs, vod->obofs);
448 /* Perform the orbital rotation */
449 phi = sensitivity * vod->reverse * (x - vod->oldx);
453 QuatMul(rv3d->viewquat, rv3d->viewquat, q1);
457 VecSubf(rv3d->ofs, rv3d->ofs, vod->obofs);
458 QuatMulVecf(q1, rv3d->ofs);
459 VecAddf(rv3d->ofs, rv3d->ofs, vod->obofs);
463 /* check for view snap */
469 QuatToMat3(rv3d->viewquat, viewmat);
471 for (i = 0 ; i < 39; i++){
473 float view = (int)snapquats[i][4];
475 QuatToMat3(snapquats[i], snapmat);
477 if ((Inpf(snapmat[0], viewmat[0]) > thres) &&
478 (Inpf(snapmat[1], viewmat[1]) > thres) &&
479 (Inpf(snapmat[2], viewmat[2]) > thres)){
481 QUATCOPY(rv3d->viewquat, snapquats[i]);
492 ED_region_tag_redraw(vod->ar);
495 static int viewrotate_modal(bContext *C, wmOperator *op, wmEvent *event)
497 ViewOpsData *vod= op->customdata;
499 /* execute the events */
500 switch(event->type) {
502 viewrotate_apply(vod, event->x, event->y, event->ctrl);
506 /* origkey may be zero when invoked from a button */
507 if(ELEM3(event->type, ESCKEY, LEFTMOUSE, RIGHTMOUSE) || (event->type==vod->origkey && event->val==0)) {
508 request_depth_update(CTX_wm_region_view3d(C));
511 op->customdata= NULL;
513 return OPERATOR_FINISHED;
517 return OPERATOR_RUNNING_MODAL;
520 static int viewrotate_invoke(bContext *C, wmOperator *op, wmEvent *event)
522 RegionView3D *rv3d= CTX_wm_region_view3d(C);
526 return OPERATOR_CANCELLED;
528 /* makes op->customdata */
529 viewops_data(C, op, event);
532 /* switch from camera view when: */
533 if(vod->rv3d->persp != V3D_PERSP) {
535 if (U.uiflag & USER_AUTOPERSP)
536 vod->rv3d->persp= V3D_PERSP;
537 else if(vod->rv3d->persp==V3D_CAMOB)
538 vod->rv3d->persp= V3D_PERSP;
539 ED_region_tag_redraw(vod->ar);
542 /* add temp handler */
543 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
545 return OPERATOR_RUNNING_MODAL;
549 void VIEW3D_OT_viewrotate(wmOperatorType *ot)
553 ot->name= "Rotate view";
554 ot->description = "Rotate the view.";
555 ot->idname= "VIEW3D_OT_viewrotate";
558 ot->invoke= viewrotate_invoke;
559 ot->modal= viewrotate_modal;
560 ot->poll= ED_operator_view3d_active;
563 ot->flag= OPTYPE_REGISTER|OPTYPE_BLOCKING;
566 /* ************************ viewmove ******************************** */
568 static void viewmove_apply(ViewOpsData *vod, int x, int y)
570 if(vod->rv3d->persp==V3D_CAMOB) {
571 float max= (float)MAX2(vod->ar->winx, vod->ar->winy);
573 vod->rv3d->camdx += (vod->oldx - x)/(max);
574 vod->rv3d->camdy += (vod->oldy - y)/(max);
575 CLAMP(vod->rv3d->camdx, -1.0f, 1.0f);
576 CLAMP(vod->rv3d->camdy, -1.0f, 1.0f);
577 // XXX preview3d_event= 0;
582 window_to_3d_delta(vod->ar, dvec, x-vod->oldx, y-vod->oldy);
583 VecAddf(vod->rv3d->ofs, vod->rv3d->ofs, dvec);
585 if(vod->rv3d->viewlock & RV3D_BOXVIEW)
586 view3d_boxview_sync(vod->sa, vod->ar);
592 ED_region_tag_redraw(vod->ar);
596 static int viewmove_modal(bContext *C, wmOperator *op, wmEvent *event)
598 ViewOpsData *vod= op->customdata;
600 /* execute the events */
601 switch(event->type) {
603 viewmove_apply(vod, event->x, event->y);
607 /* origkey may be zero when invoked from a button */
608 if(ELEM3(event->type, ESCKEY, LEFTMOUSE, RIGHTMOUSE) || (event->type==vod->origkey && event->val==0)) {
609 request_depth_update(CTX_wm_region_view3d(C));
612 op->customdata= NULL;
614 return OPERATOR_FINISHED;
618 return OPERATOR_RUNNING_MODAL;
621 static int viewmove_invoke(bContext *C, wmOperator *op, wmEvent *event)
623 /* makes op->customdata */
624 viewops_data(C, op, event);
626 /* add temp handler */
627 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
629 return OPERATOR_RUNNING_MODAL;
633 void VIEW3D_OT_viewmove(wmOperatorType *ot)
637 ot->name= "Move view";
638 ot->description = "Move the view.";
639 ot->idname= "VIEW3D_OT_viewmove";
642 ot->invoke= viewmove_invoke;
643 ot->modal= viewmove_modal;
644 ot->poll= ED_operator_view3d_active;
647 ot->flag= OPTYPE_REGISTER|OPTYPE_BLOCKING;
650 /* ************************ viewzoom ******************************** */
652 static void view_zoom_mouseloc(ARegion *ar, float dfac, int mx, int my)
654 RegionView3D *rv3d= ar->regiondata;
656 if(U.uiflag & USER_ZOOM_TO_MOUSEPOS) {
661 short vb[2], mouseloc[2];
663 mouseloc[0]= mx - ar->winrct.xmin;
664 mouseloc[1]= my - ar->winrct.ymin;
666 /* find the current window width and height */
670 tpos[0] = -rv3d->ofs[0];
671 tpos[1] = -rv3d->ofs[1];
672 tpos[2] = -rv3d->ofs[2];
674 /* Project cursor position into 3D space */
675 initgrabz(rv3d, tpos[0], tpos[1], tpos[2]);
676 window_to_3d_delta(ar, dvec, mouseloc[0]-vb[0]/2, mouseloc[1]-vb[1]/2);
678 /* Calculate view target position for dolly */
679 tvec[0] = -(tpos[0] + dvec[0]);
680 tvec[1] = -(tpos[1] + dvec[1]);
681 tvec[2] = -(tpos[2] + dvec[2]);
683 /* Offset to target position and dolly */
684 new_dist = rv3d->dist * dfac;
686 VECCOPY(rv3d->ofs, tvec);
687 rv3d->dist = new_dist;
689 /* Calculate final offset */
690 dvec[0] = tvec[0] + dvec[0] * dfac;
691 dvec[1] = tvec[1] + dvec[1] * dfac;
692 dvec[2] = tvec[2] + dvec[2] * dfac;
694 VECCOPY(rv3d->ofs, dvec);
701 static void viewzoom_apply(ViewOpsData *vod, int x, int y)
705 if(U.viewzoom==USER_ZOOM_CONT) {
707 zfac = 1.0+(float)(vod->origx - x + vod->origy - y)/1000.0;
709 else if(U.viewzoom==USER_ZOOM_SCALE) {
710 int ctr[2], len1, len2;
711 // method which zooms based on how far you move the mouse
713 ctr[0] = (vod->ar->winrct.xmax + vod->ar->winrct.xmin)/2;
714 ctr[1] = (vod->ar->winrct.ymax + vod->ar->winrct.ymin)/2;
716 len1 = (int)sqrt((ctr[0] - x)*(ctr[0] - x) + (ctr[1] - y)*(ctr[1] - y)) + 5;
717 len2 = (int)sqrt((ctr[0] - vod->origx)*(ctr[0] - vod->origx) + (ctr[1] - vod->origy)*(ctr[1] - vod->origy)) + 5;
719 zfac = vod->dist0 * ((float)len2/len1) / vod->rv3d->dist;
721 else { /* USER_ZOOM_DOLLY */
722 float len1 = (vod->ar->winrct.ymax - y) + 5;
723 float len2 = (vod->ar->winrct.ymax - vod->origy) + 5;
724 zfac = vod->dist0 * (2.0*((len2/len1)-1.0) + 1.0) / vod->rv3d->dist;
727 if(zfac != 1.0 && zfac*vod->rv3d->dist > 0.001*vod->grid &&
728 zfac*vod->rv3d->dist < 10.0*vod->far)
729 view_zoom_mouseloc(vod->ar, zfac, vod->oldx, vod->oldy);
732 if ((U.uiflag & USER_ORBIT_ZBUF) && (U.viewzoom==USER_ZOOM_CONT) && (vod->rv3d->persp==V3D_PERSP)) {
733 float upvec[3], mat[3][3];
735 /* Secret apricot feature, translate the view when in continues mode */
736 upvec[0] = upvec[1] = 0.0f;
737 upvec[2] = (vod->dist0 - vod->rv3d->dist) * vod->grid;
738 vod->rv3d->dist = vod->dist0;
739 Mat3CpyMat4(mat, vod->rv3d->viewinv);
740 Mat3MulVecfl(mat, upvec);
741 VecAddf(vod->rv3d->ofs, vod->rv3d->ofs, upvec);
743 /* these limits were in old code too */
744 if(vod->rv3d->dist<0.001*vod->grid) vod->rv3d->dist= 0.001*vod->grid;
745 if(vod->rv3d->dist>10.0*vod->far) vod->rv3d->dist=10.0*vod->far;
748 // XXX if(vod->rv3d->persp==V3D_ORTHO || vod->rv3d->persp==V3D_CAMOB) preview3d_event= 0;
750 if(vod->rv3d->viewlock & RV3D_BOXVIEW)
751 view3d_boxview_sync(vod->sa, vod->ar);
753 ED_region_tag_redraw(vod->ar);
757 static int viewzoom_modal(bContext *C, wmOperator *op, wmEvent *event)
759 ViewOpsData *vod= op->customdata;
761 /* execute the events */
762 switch(event->type) {
764 viewzoom_apply(vod, event->x, event->y);
768 /* origkey may be zero when invoked from a button */
769 if(ELEM3(event->type, ESCKEY, LEFTMOUSE, RIGHTMOUSE) || (event->type==vod->origkey && event->val==0)) {
770 request_depth_update(CTX_wm_region_view3d(C));
773 op->customdata= NULL;
775 return OPERATOR_FINISHED;
779 return OPERATOR_RUNNING_MODAL;
782 static int viewzoom_exec(bContext *C, wmOperator *op)
784 View3D *v3d = CTX_wm_view3d(C);
785 RegionView3D *rv3d= CTX_wm_region_view3d(C);
786 int delta= RNA_int_get(op->ptr, "delta");
789 /* this min and max is also in viewmove() */
790 if(rv3d->persp==V3D_CAMOB) {
792 if(rv3d->camzoom<-30) rv3d->camzoom= -30;
794 else if(rv3d->dist<10.0*v3d->far) rv3d->dist*=1.2f;
797 if(rv3d->persp==V3D_CAMOB) {
799 if(rv3d->camzoom>300) rv3d->camzoom= 300;
801 else if(rv3d->dist> 0.001*v3d->grid) rv3d->dist*=.83333f;
804 if(rv3d->viewlock & RV3D_BOXVIEW)
805 view3d_boxview_sync(CTX_wm_area(C), CTX_wm_region(C));
807 request_depth_update(CTX_wm_region_view3d(C));
808 ED_region_tag_redraw(CTX_wm_region(C));
810 return OPERATOR_FINISHED;
813 static int viewzoom_invoke(bContext *C, wmOperator *op, wmEvent *event)
815 int delta= RNA_int_get(op->ptr, "delta");
818 viewzoom_exec(C, op);
821 /* makes op->customdata */
822 viewops_data(C, op, event);
824 /* add temp handler */
825 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
827 return OPERATOR_RUNNING_MODAL;
829 return OPERATOR_FINISHED;
833 void VIEW3D_OT_zoom(wmOperatorType *ot)
836 ot->name= "Zoom view";
837 ot->description = "Zoom in/out in the view.";
838 ot->idname= "VIEW3D_OT_zoom";
841 ot->invoke= viewzoom_invoke;
842 ot->exec= viewzoom_exec;
843 ot->modal= viewzoom_modal;
844 ot->poll= ED_operator_view3d_active;
847 ot->flag= OPTYPE_REGISTER|OPTYPE_BLOCKING;
849 RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
852 static int viewhome_exec(bContext *C, wmOperator *op) /* was view3d_home() in 2.4x */
854 ARegion *ar= CTX_wm_region(C);
855 View3D *v3d = CTX_wm_view3d(C);
856 RegionView3D *rv3d= CTX_wm_region_view3d(C);
857 Scene *scene= CTX_data_scene(C);
860 int center= RNA_boolean_get(op->ptr, "center");
862 float size, min[3], max[3], afm[3];
863 int ok= 1, onedone=0;
866 min[0]= min[1]= min[2]= 0.0f;
867 max[0]= max[1]= max[2]= 0.0f;
870 INIT_MINMAX(min, max);
873 for(base= scene->base.first; base; base= base->next) {
874 if(base->lay & v3d->lay) {
876 minmax_object(base->object, min, max);
879 if(!onedone) return OPERATOR_FINISHED; /* TODO - should this be cancel? */
881 afm[0]= (max[0]-min[0]);
882 afm[1]= (max[1]-min[1]);
883 afm[2]= (max[2]-min[2]);
884 size= 0.7f*MAX3(afm[0], afm[1], afm[2]);
892 new_ofs[0]= -(min[0]+max[0])/2.0f;
893 new_ofs[1]= -(min[1]+max[1])/2.0f;
894 new_ofs[2]= -(min[2]+max[2])/2.0f;
896 // correction for window aspect ratio
897 if(ar->winy>2 && ar->winx>2) {
898 size= (float)ar->winx/(float)ar->winy;
899 if(size<1.0) size= 1.0f/size;
903 if (rv3d->persp==V3D_CAMOB) {
904 rv3d->persp= V3D_PERSP;
905 smooth_view(C, NULL, v3d->camera, new_ofs, NULL, &new_dist, NULL);
908 // XXX BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
910 if(rv3d->viewlock & RV3D_BOXVIEW)
911 view3d_boxview_copy(CTX_wm_area(C), ar);
913 return OPERATOR_FINISHED;
916 void VIEW3D_OT_view_all(wmOperatorType *ot)
919 ot->name= "View home";
920 ot->description = "View all objects in scene.";
921 ot->idname= "VIEW3D_OT_view_all";
924 ot->exec= viewhome_exec;
925 ot->poll= ED_operator_view3d_active;
928 ot->flag= OPTYPE_REGISTER;
930 RNA_def_boolean(ot->srna, "center", 0, "Center", "");
933 static int viewcenter_exec(bContext *C, wmOperator *op) /* like a localview without local!, was centerview() in 2.4x */
935 ARegion *ar= CTX_wm_region(C);
936 View3D *v3d = CTX_wm_view3d(C);
937 RegionView3D *rv3d= CTX_wm_region_view3d(C);
938 Scene *scene= CTX_data_scene(C);
940 Object *obedit= CTX_data_edit_object(C);
941 float size, min[3], max[3], afm[3];
948 INIT_MINMAX(min, max);
950 if (G.f & G_WEIGHTPAINT) {
951 /* hardcoded exception, we look for the one selected armature */
952 /* this is weak code this way, we should make a generic active/selection callback interface once... */
954 for(base=scene->base.first; base; base= base->next) {
955 if(TESTBASELIB(v3d, base)) {
956 if(base->object->type==OB_ARMATURE)
957 if(base->object->flag & OB_POSEMODE)
967 ok = minmax_verts(obedit, min, max); /* only selected */
969 else if(ob && (ob->flag & OB_POSEMODE)) {
971 bArmature *arm= ob->data;
975 for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
976 if(pchan->bone->flag & BONE_SELECTED) {
977 if(pchan->bone->layer & arm->layer) {
979 VECCOPY(vec, pchan->pose_head);
980 Mat4MulVecfl(ob->obmat, vec);
981 DO_MINMAX(vec, min, max);
982 VECCOPY(vec, pchan->pose_tail);
983 Mat4MulVecfl(ob->obmat, vec);
984 DO_MINMAX(vec, min, max);
990 else if (FACESEL_PAINT_TEST) {
991 // XXX ok= minmax_tface(min, max);
993 else if (G.f & G_PARTICLEEDIT) {
994 ok= PE_minmax(scene, min, max);
997 Base *base= FIRSTBASE;
999 if(TESTBASE(v3d, base)) {
1000 minmax_object(base->object, min, max);
1001 /* account for duplis */
1002 minmax_object_duplis(scene, base->object, min, max);
1010 if(ok==0) return OPERATOR_FINISHED;
1012 afm[0]= (max[0]-min[0]);
1013 afm[1]= (max[1]-min[1]);
1014 afm[2]= (max[2]-min[2]);
1015 size= MAX3(afm[0], afm[1], afm[2]);
1016 /* perspective should be a bit farther away to look nice */
1017 if(rv3d->persp==V3D_ORTHO)
1020 if(size <= v3d->near*1.5f) size= v3d->near*1.5f;
1022 new_ofs[0]= -(min[0]+max[0])/2.0f;
1023 new_ofs[1]= -(min[1]+max[1])/2.0f;
1024 new_ofs[2]= -(min[2]+max[2])/2.0f;
1028 /* correction for window aspect ratio */
1029 if(ar->winy>2 && ar->winx>2) {
1030 size= (float)ar->winx/(float)ar->winy;
1031 if(size<1.0f) size= 1.0f/size;
1035 v3d->cursor[0]= -new_ofs[0];
1036 v3d->cursor[1]= -new_ofs[1];
1037 v3d->cursor[2]= -new_ofs[2];
1039 if (rv3d->persp==V3D_CAMOB) {
1040 rv3d->persp= V3D_PERSP;
1041 smooth_view(C, v3d->camera, NULL, new_ofs, NULL, &new_dist, NULL);
1044 smooth_view(C, NULL, NULL, new_ofs, NULL, &new_dist, NULL);
1047 // XXX BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
1048 if(rv3d->viewlock & RV3D_BOXVIEW)
1049 view3d_boxview_copy(CTX_wm_area(C), ar);
1051 return OPERATOR_FINISHED;
1054 void VIEW3D_OT_view_center(wmOperatorType *ot)
1058 ot->name= "View center";
1059 ot->description = "Move the view to the selection center.";
1060 ot->idname= "VIEW3D_OT_view_center";
1063 ot->exec= viewcenter_exec;
1064 ot->poll= ED_operator_view3d_active;
1067 ot->flag= OPTYPE_REGISTER;
1070 /* ********************* Set render border operator ****************** */
1072 static int render_border_exec(bContext *C, wmOperator *op)
1074 View3D *v3d = CTX_wm_view3d(C);
1075 ARegion *ar= CTX_wm_region(C);
1076 Scene *scene= CTX_data_scene(C);
1081 /* get border select values using rna */
1082 rect.xmin= RNA_int_get(op->ptr, "xmin");
1083 rect.ymin= RNA_int_get(op->ptr, "ymin");
1084 rect.xmax= RNA_int_get(op->ptr, "xmax");
1085 rect.ymax= RNA_int_get(op->ptr, "ymax");
1087 /* calculate range */
1088 calc_viewborder(scene, ar, v3d, &vb);
1090 scene->r.border.xmin= ((float)rect.xmin-vb.xmin)/(vb.xmax-vb.xmin);
1091 scene->r.border.ymin= ((float)rect.ymin-vb.ymin)/(vb.ymax-vb.ymin);
1092 scene->r.border.xmax= ((float)rect.xmax-vb.xmin)/(vb.xmax-vb.xmin);
1093 scene->r.border.ymax= ((float)rect.ymax-vb.ymin)/(vb.ymax-vb.ymin);
1095 /* actually set border */
1096 CLAMP(scene->r.border.xmin, 0.0, 1.0);
1097 CLAMP(scene->r.border.ymin, 0.0, 1.0);
1098 CLAMP(scene->r.border.xmax, 0.0, 1.0);
1099 CLAMP(scene->r.border.ymax, 0.0, 1.0);
1101 /* drawing a border surrounding the entire camera view switches off border rendering
1102 * or the border covers no pixels */
1103 if ((scene->r.border.xmin <= 0.0 && scene->r.border.xmax >= 1.0 &&
1104 scene->r.border.ymin <= 0.0 && scene->r.border.ymax >= 1.0) ||
1105 (scene->r.border.xmin == scene->r.border.xmax ||
1106 scene->r.border.ymin == scene->r.border.ymax ))
1108 scene->r.mode &= ~R_BORDER;
1110 scene->r.mode |= R_BORDER;
1113 return OPERATOR_FINISHED;
1117 static int view3d_render_border_invoke(bContext *C, wmOperator *op, wmEvent *event)
1119 RegionView3D *rv3d= CTX_wm_region_view3d(C);
1121 /* if not in camera view do not exec the operator*/
1122 if (rv3d->persp == V3D_CAMOB) return WM_border_select_invoke(C, op, event);
1123 else return OPERATOR_PASS_THROUGH;
1126 void VIEW3D_OT_render_border(wmOperatorType *ot)
1129 ot->name= "Set Render Border";
1130 ot->description = "Set the boundries of the border render and enables border render .";
1131 ot->idname= "VIEW3D_OT_render_border";
1134 ot->invoke= view3d_render_border_invoke;
1135 ot->exec= render_border_exec;
1136 ot->modal= WM_border_select_modal;
1138 ot->poll= ED_operator_view3d_active;
1141 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1144 RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
1145 RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
1146 RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
1147 RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
1150 /* ********************* Border Zoom operator ****************** */
1152 static int view3d_border_zoom_exec(bContext *C, wmOperator *op)
1154 ARegion *ar= CTX_wm_region(C);
1155 View3D *v3d = CTX_wm_view3d(C);
1156 RegionView3D *rv3d= CTX_wm_region_view3d(C);
1157 Scene *scene= CTX_data_scene(C);
1159 /* Zooms in on a border drawn by the user */
1161 float dvec[3], vb[2], xscale, yscale, scale;
1167 /* ZBuffer depth vars */
1169 float depth, depth_close= MAXFLOAT;
1171 double cent[2], p[3];
1174 /* note; otherwise opengl won't work */
1175 view3d_operator_needs_opengl(C);
1177 /* get border select values using rna */
1178 rect.xmin= RNA_int_get(op->ptr, "xmin");
1179 rect.ymin= RNA_int_get(op->ptr, "ymin");
1180 rect.xmax= RNA_int_get(op->ptr, "xmax");
1181 rect.ymax= RNA_int_get(op->ptr, "ymax");
1183 /* Get Z Depths, needed for perspective, nice for ortho */
1184 bgl_get_mats(&mats);
1185 draw_depth(scene, ar, v3d, NULL);
1187 /* force updating */
1190 rv3d->depths->damaged = 1;
1193 view3d_update_depths(ar, v3d);
1195 /* Constrain rect to depth bounds */
1196 if (rect.xmin < 0) rect.xmin = 0;
1197 if (rect.ymin < 0) rect.ymin = 0;
1198 if (rect.xmax >= rv3d->depths->w) rect.xmax = rv3d->depths->w-1;
1199 if (rect.ymax >= rv3d->depths->h) rect.ymax = rv3d->depths->h-1;
1201 /* Find the closest Z pixel */
1202 for (xs=rect.xmin; xs < rect.xmax; xs++) {
1203 for (ys=rect.ymin; ys < rect.ymax; ys++) {
1204 depth= rv3d->depths->depths[ys*rv3d->depths->w+xs];
1205 if(depth < rv3d->depths->depth_range[1] && depth > rv3d->depths->depth_range[0]) {
1206 if (depth_close > depth) {
1207 depth_close = depth;
1214 MEM_freeN(rv3d->depths->depths);
1215 rv3d->depths->depths = NULL;
1217 rv3d->depths->damaged = 1;
1219 cent[0] = (((double)rect.xmin)+((double)rect.xmax)) / 2;
1220 cent[1] = (((double)rect.ymin)+((double)rect.ymax)) / 2;
1222 if (rv3d->persp==V3D_PERSP) {
1225 /* no depths to use, we cant do anything! */
1226 if (depth_close==MAXFLOAT){
1227 BKE_report(op->reports, RPT_ERROR, "Depth Too Large");
1228 return OPERATOR_CANCELLED;
1230 /* convert border to 3d coordinates */
1231 if (( !gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2])) ||
1232 ( !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])))
1233 return OPERATOR_CANCELLED;
1235 dvec[0] = p[0]-p_corner[0];
1236 dvec[1] = p[1]-p_corner[1];
1237 dvec[2] = p[2]-p_corner[2];
1239 new_dist = VecLength(dvec);
1240 if(new_dist <= v3d->near*1.5) new_dist= v3d->near*1.5;
1246 } else { /* othographic */
1247 /* find the current window width and height */
1251 new_dist = rv3d->dist;
1253 /* convert the drawn rectangle into 3d space */
1254 if (depth_close!=MAXFLOAT && gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2])) {
1259 /* We cant use the depth, fallback to the old way that dosnt set the center depth */
1260 new_ofs[0] = rv3d->ofs[0];
1261 new_ofs[1] = rv3d->ofs[1];
1262 new_ofs[2] = rv3d->ofs[2];
1264 initgrabz(rv3d, -new_ofs[0], -new_ofs[1], -new_ofs[2]);
1266 window_to_3d_delta(ar, dvec, (rect.xmin+rect.xmax-vb[0])/2, (rect.ymin+rect.ymax-vb[1])/2);
1267 /* center the view to the center of the rectangle */
1268 VecSubf(new_ofs, new_ofs, dvec);
1271 /* work out the ratios, so that everything selected fits when we zoom */
1272 xscale = ((rect.xmax-rect.xmin)/vb[0]);
1273 yscale = ((rect.ymax-rect.ymin)/vb[1]);
1274 scale = (xscale >= yscale)?xscale:yscale;
1276 /* zoom in as required, or as far as we can go */
1277 new_dist = ((new_dist*scale) >= 0.001*v3d->grid)? new_dist*scale:0.001*v3d->grid;
1280 smooth_view(C, NULL, NULL, new_ofs, NULL, &new_dist, NULL);
1282 if(rv3d->viewlock & RV3D_BOXVIEW)
1283 view3d_boxview_sync(CTX_wm_area(C), ar);
1285 return OPERATOR_FINISHED;
1288 static int view3d_border_zoom_invoke(bContext *C, wmOperator *op, wmEvent *event)
1290 RegionView3D *rv3d= CTX_wm_region_view3d(C);
1292 /* if in camera view do not exec the operator so we do not conflict with set render border*/
1293 if (rv3d->persp != V3D_CAMOB)
1294 return WM_border_select_invoke(C, op, event);
1296 return OPERATOR_PASS_THROUGH;
1299 void VIEW3D_OT_zoom_border(wmOperatorType *ot)
1303 ot->name= "Border Zoom";
1304 ot->description = "Zoom in the view to the nearest object contained in the border.";
1305 ot->idname= "VIEW3D_OT_zoom_border";
1308 ot->invoke= view3d_border_zoom_invoke;
1309 ot->exec= view3d_border_zoom_exec;
1310 ot->modal= WM_border_select_modal;
1312 ot->poll= ED_operator_view3d_active;
1315 ot->flag= OPTYPE_REGISTER;
1318 RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
1319 RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
1320 RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
1321 RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
1324 /* ********************* Changing view operator ****************** */
1326 static EnumPropertyItem prop_view_items[] = {
1327 {V3D_VIEW_FRONT, "FRONT", 0, "Front", "View From the Front"},
1328 {V3D_VIEW_BACK, "BACK", 0, "Back", "View From the Back"},
1329 {V3D_VIEW_LEFT, "LEFT", 0, "Left", "View From the Left"},
1330 {V3D_VIEW_RIGHT, "RIGHT", 0, "Right", "View From the Right"},
1331 {V3D_VIEW_TOP, "TOP", 0, "Top", "View From the Top"},
1332 {V3D_VIEW_BOTTOM, "BOTTOM", 0, "Bottom", "View From the Bottom"},
1333 {V3D_VIEW_CAMERA, "CAMERA", 0, "Camera", "View From the active amera"},
1334 {0, NULL, 0, NULL, NULL}};
1336 static void axis_set_view(bContext *C, float q1, float q2, float q3, float q4, short view, int perspo)
1338 View3D *v3d = CTX_wm_view3d(C);
1339 RegionView3D *rv3d= CTX_wm_region_view3d(C);
1342 if(rv3d->viewlock) {
1343 /* only pass on if */
1344 if(rv3d->view==V3D_VIEW_FRONT && view==V3D_VIEW_BACK);
1345 else if(rv3d->view==V3D_VIEW_BACK && view==V3D_VIEW_FRONT);
1346 else if(rv3d->view==V3D_VIEW_RIGHT && view==V3D_VIEW_LEFT);
1347 else if(rv3d->view==V3D_VIEW_LEFT && view==V3D_VIEW_RIGHT);
1348 else if(rv3d->view==V3D_VIEW_BOTTOM && view==V3D_VIEW_TOP);
1349 else if(rv3d->view==V3D_VIEW_TOP && view==V3D_VIEW_BOTTOM);
1353 new_quat[0]= q1; new_quat[1]= q2;
1354 new_quat[2]= q3; new_quat[3]= q4;
1358 if(rv3d->viewlock) {
1359 ED_region_tag_redraw(CTX_wm_region(C));
1363 if (rv3d->persp==V3D_CAMOB && v3d->camera) {
1365 if (U.uiflag & USER_AUTOPERSP) rv3d->persp= V3D_ORTHO;
1366 else if(rv3d->persp==V3D_CAMOB) rv3d->persp= perspo;
1368 smooth_view(C, v3d->camera, NULL, rv3d->ofs, new_quat, NULL, NULL);
1372 if (U.uiflag & USER_AUTOPERSP) rv3d->persp= V3D_ORTHO;
1373 else if(rv3d->persp==V3D_CAMOB) rv3d->persp= perspo;
1375 smooth_view(C, NULL, NULL, NULL, new_quat, NULL, NULL);
1380 static int viewnumpad_exec(bContext *C, wmOperator *op)
1382 View3D *v3d = CTX_wm_view3d(C);
1383 RegionView3D *rv3d= CTX_wm_region_view3d(C);
1384 Scene *scene= CTX_data_scene(C);
1385 static int perspo=V3D_PERSP;
1388 viewnum = RNA_enum_get(op->ptr, "type");
1390 /* Use this to test if we started out with a camera */
1393 case V3D_VIEW_BOTTOM :
1394 axis_set_view(C, 0.0, -1.0, 0.0, 0.0, viewnum, perspo);
1398 axis_set_view(C, 0.0, 0.0, (float)-cos(M_PI/4.0), (float)-cos(M_PI/4.0), viewnum, perspo);
1402 axis_set_view(C, 0.5, -0.5, 0.5, 0.5, viewnum, perspo);
1406 axis_set_view(C, 1.0, 0.0, 0.0, 0.0, viewnum, perspo);
1409 case V3D_VIEW_FRONT:
1410 axis_set_view(C, (float)cos(M_PI/4.0), (float)-sin(M_PI/4.0), 0.0, 0.0, viewnum, perspo);
1413 case V3D_VIEW_RIGHT:
1414 axis_set_view(C, 0.5, -0.5, -0.5, -0.5, viewnum, perspo);
1417 case V3D_VIEW_CAMERA:
1418 if(rv3d->viewlock==0) {
1421 if(rv3d->persp != V3D_CAMOB) {
1422 /* store settings of current view before allowing overwriting with camera view */
1423 QUATCOPY(rv3d->lviewquat, rv3d->viewquat);
1424 rv3d->lview= rv3d->view;
1425 rv3d->lpersp= rv3d->persp;
1428 if(G.qual==LR_ALTKEY) {
1429 if(oldcamera && is_an_active_object(oldcamera)) {
1430 v3d->camera= oldcamera;
1432 handle_view3d_lock();
1437 /* check both G.vd as G.scene cameras */
1438 if((v3d->camera==NULL || scene->camera==NULL) && OBACT->type==OB_CAMERA) {
1440 /*handle_view3d_lock();*/
1444 if(v3d->camera==NULL) {
1445 v3d->camera= scene_find_camera(scene);
1446 /*handle_view3d_lock();*/
1448 rv3d->persp= V3D_CAMOB;
1449 smooth_view(C, NULL, v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, &v3d->lens);
1453 /* return to settings of last view */
1454 /* does smooth_view too */
1455 axis_set_view(C, rv3d->lviewquat[0], rv3d->lviewquat[1], rv3d->lviewquat[2], rv3d->lviewquat[3], rv3d->lview, rv3d->lpersp);
1464 if(rv3d->persp != V3D_CAMOB) perspo= rv3d->persp;
1466 return OPERATOR_FINISHED;
1468 void VIEW3D_OT_viewnumpad(wmOperatorType *ot)
1471 ot->name= "View numpad";
1472 ot->description = "Set the view.";
1473 ot->idname= "VIEW3D_OT_viewnumpad";
1476 ot->exec= viewnumpad_exec;
1477 ot->poll= ED_operator_view3d_active;
1480 ot->flag= OPTYPE_REGISTER;
1482 RNA_def_enum(ot->srna, "type", prop_view_items, 0, "View", "The Type of view");
1485 static EnumPropertyItem prop_view_orbit_items[] = {
1486 {V3D_VIEW_STEPLEFT, "ORBITLEFT", 0, "Orbit Left", "Orbit the view around to the Left"},
1487 {V3D_VIEW_STEPRIGHT, "ORBITRIGHT", 0, "Orbit Right", "Orbit the view around to the Right"},
1488 {V3D_VIEW_STEPUP, "ORBITUP", 0, "Orbit Up", "Orbit the view Up"},
1489 {V3D_VIEW_STEPDOWN, "ORBITDOWN", 0, "Orbit Down", "Orbit the view Down"},
1490 {0, NULL, 0, NULL, NULL}};
1492 static int vieworbit_exec(bContext *C, wmOperator *op)
1494 ARegion *ar= CTX_wm_region(C);
1495 RegionView3D *rv3d= CTX_wm_region_view3d(C);
1496 float phi, si, q1[4];
1499 orbitdir = RNA_enum_get(op->ptr, "type");
1501 if(rv3d->viewlock==0) {
1503 if(rv3d->persp != V3D_CAMOB) {
1504 if(orbitdir == V3D_VIEW_STEPLEFT || orbitdir == V3D_VIEW_STEPRIGHT) {
1506 phi= (float)(M_PI/360.0)*U.pad_rot_angle;
1507 if(orbitdir == V3D_VIEW_STEPRIGHT) phi= -phi;
1508 si= (float)sin(phi);
1509 q1[0]= (float)cos(phi);
1512 QuatMul(rv3d->viewquat, rv3d->viewquat, q1);
1515 if(orbitdir == V3D_VIEW_STEPDOWN || orbitdir == V3D_VIEW_STEPUP) {
1516 /* horizontal axis */
1517 VECCOPY(q1+1, rv3d->viewinv[0]);
1520 phi= (float)(M_PI/360.0)*U.pad_rot_angle;
1521 if(orbitdir == V3D_VIEW_STEPDOWN) phi= -phi;
1522 si= (float)sin(phi);
1523 q1[0]= (float)cos(phi);
1527 QuatMul(rv3d->viewquat, rv3d->viewquat, q1);
1530 ED_region_tag_redraw(ar);
1534 return OPERATOR_FINISHED;
1537 void VIEW3D_OT_view_orbit(wmOperatorType *ot)
1540 ot->name= "View Orbit";
1541 ot->description = "Orbit the view.";
1542 ot->idname= "VIEW3D_OT_view_orbit";
1545 ot->exec= vieworbit_exec;
1546 ot->poll= ED_operator_view3d_active;
1549 ot->flag= OPTYPE_REGISTER;
1550 RNA_def_enum(ot->srna, "type", prop_view_orbit_items, 0, "Orbit", "Direction of View Orbit");
1553 static EnumPropertyItem prop_view_pan_items[] = {
1554 {V3D_VIEW_PANLEFT, "PANLEFT", 0, "Pan Left", "Pan the view to the Left"},
1555 {V3D_VIEW_PANRIGHT, "PANRIGHT", 0, "Pan Right", "Pan the view to the Right"},
1556 {V3D_VIEW_PANUP, "PANUP", 0, "Pan Up", "Pan the view Up"},
1557 {V3D_VIEW_PANDOWN, "PANDOWN", 0, "Pan Down", "Pan the view Down"},
1558 {0, NULL, 0, NULL, NULL}};
1560 static int viewpan_exec(bContext *C, wmOperator *op)
1562 ARegion *ar= CTX_wm_region(C);
1563 RegionView3D *rv3d= CTX_wm_region_view3d(C);
1567 pandir = RNA_enum_get(op->ptr, "type");
1569 initgrabz(rv3d, 0.0, 0.0, 0.0);
1571 if(pandir == V3D_VIEW_PANRIGHT) window_to_3d_delta(ar, vec, -32, 0);
1572 else if(pandir == V3D_VIEW_PANLEFT) window_to_3d_delta(ar, vec, 32, 0);
1573 else if(pandir == V3D_VIEW_PANUP) window_to_3d_delta(ar, vec, 0, -25);
1574 else if(pandir == V3D_VIEW_PANDOWN) window_to_3d_delta(ar, vec, 0, 25);
1575 rv3d->ofs[0]+= vec[0];
1576 rv3d->ofs[1]+= vec[1];
1577 rv3d->ofs[2]+= vec[2];
1579 if(rv3d->viewlock & RV3D_BOXVIEW)
1580 view3d_boxview_sync(CTX_wm_area(C), ar);
1582 ED_region_tag_redraw(ar);
1584 return OPERATOR_FINISHED;
1587 void VIEW3D_OT_view_pan(wmOperatorType *ot)
1590 ot->name= "View Pan";
1591 ot->description = "Pan the view.";
1592 ot->idname= "VIEW3D_OT_view_pan";
1595 ot->exec= viewpan_exec;
1596 ot->poll= ED_operator_view3d_active;
1599 ot->flag= OPTYPE_REGISTER;
1600 RNA_def_enum(ot->srna, "type", prop_view_pan_items, 0, "Pan", "Direction of View Pan");
1603 static int viewpersportho_exec(bContext *C, wmOperator *op)
1605 ARegion *ar= CTX_wm_region(C);
1606 RegionView3D *rv3d= CTX_wm_region_view3d(C);
1608 if(rv3d->viewlock==0) {
1609 if(rv3d->persp!=V3D_ORTHO)
1610 rv3d->persp=V3D_ORTHO;
1611 else rv3d->persp=V3D_PERSP;
1612 ED_region_tag_redraw(ar);
1615 return OPERATOR_FINISHED;
1619 void VIEW3D_OT_view_persportho(wmOperatorType *ot)
1622 ot->name= "View persp/ortho";
1623 ot->description = "Switch the current view from perspective/orthographic.";
1624 ot->idname= "VIEW3D_OT_view_persportho";
1627 ot->exec= viewpersportho_exec;
1628 ot->poll= ED_operator_view3d_active;
1631 ot->flag= OPTYPE_REGISTER;
1635 /* ********************* set clipping operator ****************** */
1637 static int view3d_clipping_exec(bContext *C, wmOperator *op)
1639 RegionView3D *rv3d= CTX_wm_region_view3d(C);
1641 double mvmatrix[16];
1642 double projmatrix[16];
1643 double xs, ys, p[3];
1647 rect.xmin= RNA_int_get(op->ptr, "xmin");
1648 rect.ymin= RNA_int_get(op->ptr, "ymin");
1649 rect.xmax= RNA_int_get(op->ptr, "xmax");
1650 rect.ymax= RNA_int_get(op->ptr, "ymax");
1652 rv3d->rflag |= RV3D_CLIPPING;
1653 rv3d->clipbb= MEM_callocN(sizeof(BoundBox), "clipbb");
1655 /* note; otherwise opengl won't work */
1656 view3d_operator_needs_opengl(C);
1658 /* Get the matrices needed for gluUnProject */
1659 glGetIntegerv(GL_VIEWPORT, viewport);
1660 glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
1661 glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
1663 /* near zero floating point values can give issues with gluUnProject
1664 in side view on some implementations */
1665 if(fabs(mvmatrix[0]) < 1e-6) mvmatrix[0]= 0.0;
1666 if(fabs(mvmatrix[5]) < 1e-6) mvmatrix[5]= 0.0;
1668 /* Set up viewport so that gluUnProject will give correct values */
1672 /* four clipping planes and bounding volume */
1673 /* first do the bounding volume */
1674 for(val=0; val<4; val++) {
1676 xs= (val==0||val==3)?rect.xmin:rect.xmax;
1677 ys= (val==0||val==1)?rect.ymin:rect.ymax;
1679 gluUnProject(xs, ys, 0.0, mvmatrix, projmatrix, viewport, &p[0], &p[1], &p[2]);
1680 VECCOPY(rv3d->clipbb->vec[val], p);
1682 gluUnProject(xs, ys, 1.0, mvmatrix, projmatrix, viewport, &p[0], &p[1], &p[2]);
1683 VECCOPY(rv3d->clipbb->vec[4+val], p);
1686 /* then plane equations */
1687 for(val=0; val<4; val++) {
1689 CalcNormFloat(rv3d->clipbb->vec[val], rv3d->clipbb->vec[val==3?0:val+1], rv3d->clipbb->vec[val+4],
1692 rv3d->clip[val][3]= - rv3d->clip[val][0]*rv3d->clipbb->vec[val][0]
1693 - rv3d->clip[val][1]*rv3d->clipbb->vec[val][1]
1694 - rv3d->clip[val][2]*rv3d->clipbb->vec[val][2];
1696 return OPERATOR_FINISHED;
1699 static int view3d_clipping_invoke(bContext *C, wmOperator *op, wmEvent *event)
1701 RegionView3D *rv3d= CTX_wm_region_view3d(C);
1702 ARegion *ar= CTX_wm_region(C);
1704 if(rv3d->rflag & RV3D_CLIPPING) {
1705 rv3d->rflag &= ~RV3D_CLIPPING;
1706 ED_region_tag_redraw(ar);
1707 if(rv3d->clipbb) MEM_freeN(rv3d->clipbb);
1709 return OPERATOR_FINISHED;
1712 return WM_border_select_invoke(C, op, event);
1717 void VIEW3D_OT_clip_border(wmOperatorType *ot)
1721 ot->name= "Clipping Border";
1722 ot->description = "Set the view clipping border.";
1723 ot->idname= "VIEW3D_OT_clip_border";
1726 ot->invoke= view3d_clipping_invoke;
1727 ot->exec= view3d_clipping_exec;
1728 ot->modal= WM_border_select_modal;
1730 ot->poll= ED_operator_view3d_active;
1733 ot->flag= OPTYPE_REGISTER;
1736 RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
1737 RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
1738 RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
1739 RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
1742 /* ********************* draw type operator ****************** */
1744 static int view3d_drawtype_exec(bContext *C, wmOperator *op)
1746 View3D *v3d = CTX_wm_view3d(C);
1749 dt = RNA_int_get(op->ptr, "draw_type");
1750 dt_alt = RNA_int_get(op->ptr, "draw_type_alternate");
1753 if (v3d->drawtype == dt)
1754 v3d->drawtype = dt_alt;
1761 ED_area_tag_redraw(CTX_wm_area(C));
1763 return OPERATOR_FINISHED;
1766 static int view3d_drawtype_invoke(bContext *C, wmOperator *op, wmEvent *event)
1768 return view3d_drawtype_exec(C, op);
1772 void VIEW3D_OT_drawtype(wmOperatorType *ot)
1775 ot->name= "Change draw type";
1776 ot->description = "Change the draw type of the view.";
1777 ot->idname= "VIEW3D_OT_drawtype";
1780 ot->invoke= view3d_drawtype_invoke;
1781 ot->exec= view3d_drawtype_exec;
1783 ot->poll= ED_operator_view3d_active;
1786 ot->flag= OPTYPE_REGISTER;
1788 /* rna XXX should become enum */
1789 RNA_def_int(ot->srna, "draw_type", 0, INT_MIN, INT_MAX, "Draw Type", "", INT_MIN, INT_MAX);
1790 RNA_def_int(ot->srna, "draw_type_alternate", -1, INT_MIN, INT_MAX, "Draw Type Alternate", "", INT_MIN, INT_MAX);
1793 /* ***************** 3d cursor cursor op ******************* */
1795 /* mx my in region coords */
1796 static int set_3dcursor_invoke(bContext *C, wmOperator *op, wmEvent *event)
1798 Scene *scene= CTX_data_scene(C);
1799 ARegion *ar= CTX_wm_region(C);
1800 View3D *v3d = CTX_wm_view3d(C);
1801 RegionView3D *rv3d= CTX_wm_region_view3d(C);
1802 float dx, dy, fz, *fp = NULL, dvec[3], oldcurs[3];
1803 short mx, my, mval[2];
1804 // short ctrl= 0; // XXX
1806 fp= give_cursor(scene, v3d);
1808 // if(obedit && ctrl) lr_click= 1;
1809 VECCOPY(oldcurs, fp);
1811 mx= event->x - ar->winrct.xmin;
1812 my= event->y - ar->winrct.ymin;
1813 project_short_noclip(ar, fp, mval);
1815 initgrabz(rv3d, fp[0], fp[1], fp[2]);
1817 if(mval[0]!=IS_CLIPPED) {
1819 window_to_3d_delta(ar, dvec, mval[0]-mx, mval[1]-my);
1820 VecSubf(fp, fp, dvec);
1824 dx= ((float)(mx-(ar->winx/2)))*rv3d->zfac/(ar->winx/2);
1825 dy= ((float)(my-(ar->winy/2)))*rv3d->zfac/(ar->winy/2);
1827 fz= rv3d->persmat[0][3]*fp[0]+ rv3d->persmat[1][3]*fp[1]+ rv3d->persmat[2][3]*fp[2]+ rv3d->persmat[3][3];
1830 fp[0]= (rv3d->persinv[0][0]*dx + rv3d->persinv[1][0]*dy+ rv3d->persinv[2][0]*fz)-rv3d->ofs[0];
1831 fp[1]= (rv3d->persinv[0][1]*dx + rv3d->persinv[1][1]*dy+ rv3d->persinv[2][1]*fz)-rv3d->ofs[1];
1832 fp[2]= (rv3d->persinv[0][2]*dx + rv3d->persinv[1][2]*dy+ rv3d->persinv[2][2]*fz)-rv3d->ofs[2];
1836 // XXX if(obedit->type==OB_MESH) add_click_mesh();
1837 // else if ELEM(obedit->type, OB_CURVE, OB_SURF) addvert_Nurb(0);
1838 // else if (obedit->type==OB_ARMATURE) addvert_armature();
1839 // VECCOPY(fp, oldcurs);
1841 // XXX notifier for scene */
1842 ED_area_tag_redraw(CTX_wm_area(C));
1844 /* prevent other mouse ops to fail */
1845 return OPERATOR_PASS_THROUGH;
1848 void VIEW3D_OT_cursor3d(wmOperatorType *ot)
1852 ot->name= "Set 3D Cursor";
1853 ot->description = "Set the location of the 3D cursor.";
1854 ot->idname= "VIEW3D_OT_cursor3d";
1857 ot->invoke= set_3dcursor_invoke;
1859 ot->poll= ED_operator_view3d_active;
1865 /* ***************** manipulator op ******************* */
1868 static int manipulator_invoke(bContext *C, wmOperator *op, wmEvent *event)
1870 View3D *v3d = CTX_wm_view3d(C);
1872 if(!(v3d->twflag & V3D_USE_MANIPULATOR)) return OPERATOR_PASS_THROUGH;
1873 if(!(v3d->twflag & V3D_DRAW_MANIPULATOR)) return OPERATOR_PASS_THROUGH;
1875 /* note; otherwise opengl won't work */
1876 view3d_operator_needs_opengl(C);
1878 if(0==BIF_do_manipulator(C, event, op))
1879 return OPERATOR_PASS_THROUGH;
1881 return OPERATOR_FINISHED;
1884 void VIEW3D_OT_manipulator(wmOperatorType *ot)
1888 ot->name= "3D Manipulator";
1889 ot->description = "";
1890 ot->idname= "VIEW3D_OT_manipulator";
1893 ot->invoke= manipulator_invoke;
1895 ot->poll= ED_operator_view3d_active;
1898 RNA_def_boolean_vector(ot->srna, "constraint_axis", 3, NULL, "Constraint Axis", "");
1903 /* ************************* below the line! *********************** */
1906 /* XXX todo Zooms in on a border drawn by the user */
1907 int view_autodist(Scene *scene, ARegion *ar, View3D *v3d, short *mval, float mouse_worldloc[3] ) //, float *autodist )
1909 RegionView3D *rv3d= ar->regiondata;
1910 bglMats mats; /* ZBuffer depth vars */
1912 float depth, depth_close= MAXFLOAT;
1914 double cent[2], p[3];
1917 rect.xmax = mval[0] + 4;
1918 rect.ymax = mval[1] + 4;
1920 rect.xmin = mval[0] - 4;
1921 rect.ymin = mval[1] - 4;
1923 /* Get Z Depths, needed for perspective, nice for ortho */
1924 bgl_get_mats(&mats);
1925 draw_depth(scene, ar, v3d, NULL);
1927 /* force updating */
1930 rv3d->depths->damaged = 1;
1933 view3d_update_depths(ar, v3d);
1935 /* Constrain rect to depth bounds */
1936 if (rect.xmin < 0) rect.xmin = 0;
1937 if (rect.ymin < 0) rect.ymin = 0;
1938 if (rect.xmax >= rv3d->depths->w) rect.xmax = rv3d->depths->w-1;
1939 if (rect.ymax >= rv3d->depths->h) rect.ymax = rv3d->depths->h-1;
1941 /* Find the closest Z pixel */
1942 for (xs=rect.xmin; xs < rect.xmax; xs++) {
1943 for (ys=rect.ymin; ys < rect.ymax; ys++) {
1944 depth= rv3d->depths->depths[ys*rv3d->depths->w+xs];
1945 if(depth < rv3d->depths->depth_range[1] && depth > rv3d->depths->depth_range[0]) {
1946 if (depth_close > depth) {
1947 depth_close = depth;
1953 if (depth_close==MAXFLOAT)
1957 MEM_freeN(rv3d->depths->depths);
1958 rv3d->depths->depths = NULL;
1960 rv3d->depths->damaged = 1;
1962 cent[0] = (double)mval[0];
1963 cent[1] = (double)mval[1];
1965 if (!gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2]))
1968 mouse_worldloc[0] = (float)p[0];
1969 mouse_worldloc[1] = (float)p[1];
1970 mouse_worldloc[2] = (float)p[2];
1976 /* ********************* NDOF ************************ */
1977 /* note: this code is confusing and unclear... (ton) */
1978 /* **************************************************** */
1980 // ndof scaling will be moved to user setting.
1981 // In the mean time this is just a place holder.
1983 // Note: scaling in the plugin and ghostwinlay.c
1984 // should be removed. With driver default setting,
1985 // each axis returns approx. +-200 max deflection.
1987 // The values I selected are based on the older
1988 // polling i/f. With event i/f, the sensistivity
1989 // can be increased for improved response from
1990 // small deflections of the device input.
1993 // lukep notes : i disagree on the range.
1994 // the normal 3Dconnection driver give +/-400
1995 // on defaut range in other applications
1996 // and up to +/- 1000 if set to maximum
1997 // because i remove the scaling by delta,
1998 // which was a bad idea as it depend of the system
1999 // speed and os, i changed the scaling values, but
2000 // those are still not ok
2003 float ndof_axis_scale[6] = {
2012 void filterNDOFvalues(float *sbval)
2018 if (fabs(sbval[i]) > max)
2019 max = fabs(sbval[i]);
2021 if (fabs(sbval[i]) != max )
2025 // statics for controlling rv3d->dist corrections.
2026 // viewmoveNDOF zeros and adjusts rv3d->ofs.
2027 // viewmove restores based on dz_flag state.
2032 void viewmoveNDOFfly(ARegion *ar, View3D *v3d, int mode)
2034 RegionView3D *rv3d= ar->regiondata;
2038 // static fval[6] for low pass filter; device input vector is dval[6]
2039 static float fval[6];
2040 float tvec[3],rvec[3];
2046 /*----------------------------------------------------
2047 * sometimes this routine is called from headerbuttons
2048 * viewmove needs to refresh the screen
2050 // XXX areawinset(ar->win);
2053 // fetch the current state of the ndof device
2054 // XXX getndof(dval);
2056 if (v3d->ndoffilter)
2057 filterNDOFvalues(fval);
2059 // Scale input values
2061 // if(dval[6] == 0) return; // guard against divide by zero
2066 dval[i] = dval[i] * ndof_axis_scale[i];
2070 // low pass filter with zero crossing reset
2073 if((dval[i] * fval[i]) >= 0)
2074 dval[i] = (fval[i] * 15 + dval[i]) / 16;
2080 // force perspective mode. This is a hack and is
2081 // incomplete. It doesn't actually effect the view
2082 // until the first draw and doesn't update the menu
2083 // to reflect persp mode.
2085 rv3d->persp = V3D_PERSP;
2088 // Correct the distance jump if rv3d->dist != 0
2090 // This is due to a side effect of the original
2091 // mouse view rotation code. The rotation point is
2092 // set a distance in front of the viewport to
2093 // make rotating with the mouse look better.
2094 // The distance effect is written at a low level
2095 // in the view management instead of the mouse
2096 // view function. This means that all other view
2097 // movement devices must subtract this from their
2098 // view transformations.
2100 if(rv3d->dist != 0.0) {
2102 m_dist = rv3d->dist;
2103 upvec[0] = upvec[1] = 0;
2104 upvec[2] = rv3d->dist;
2105 Mat3CpyMat4(mat, rv3d->viewinv);
2106 Mat3MulVecfl(mat, upvec);
2107 VecSubf(rv3d->ofs, rv3d->ofs, upvec);
2113 // Rotations feel relatively faster than translations only in fly mode, so
2114 // we have no choice but to fix that here (not in the plugins)
2115 rvec[0] = -0.5 * dval[3];
2116 rvec[1] = -0.5 * dval[4];
2117 rvec[2] = -0.5 * dval[5];
2119 // rotate device x and y by view z
2121 Mat3CpyMat4(mat, rv3d->viewinv);
2123 Mat3MulVecfl(mat, rvec);
2127 phi = Normalize(rvec);
2129 VecRotToQuat(rvec,phi,q1);
2130 QuatMul(rv3d->viewquat, rv3d->viewquat, q1);
2134 // Apply translation
2140 // the next three lines rotate the x and y translation coordinates
2141 // by the current z axis angle
2143 Mat3CpyMat4(mat, rv3d->viewinv);
2145 Mat3MulVecfl(mat, tvec);
2147 // translate the view
2149 VecSubf(rv3d->ofs, rv3d->ofs, tvec);
2152 /*----------------------------------------------------
2153 * refresh the screen XXX
2156 // update render preview window
2158 // XXX BIF_view3d_previewrender_signal(ar, PR_DBASE|PR_DISPRECT);
2161 void viewmoveNDOF(Scene *scene, ARegion *ar, View3D *v3d, int mode)
2163 RegionView3D *rv3d= ar->regiondata;
2166 float sbadjust = 1.0f;
2172 float xvec[3] = {1,0,0};
2173 float yvec[3] = {0,-1,0};
2174 float zvec[3] = {0,0,1};
2180 float d, curareaX, curareaY;
2184 /* Sensitivity will control how fast the view rotates. The value was
2185 * obtained experimentally by tweaking until the author didn't get dizzy watching.
2186 * Perhaps this should be a configurable user parameter.
2188 float psens = 0.005f * (float) U.ndof_pan; /* pan sensitivity */
2189 float rsens = 0.005f * (float) U.ndof_rotate; /* rotate sensitivity */
2190 float zsens = 0.3f; /* zoom sensitivity */
2192 const float minZoom = -30.0f;
2193 const float maxZoom = 300.0f;
2197 //printf("passing here \n");
2199 if (scene->obedit==NULL && ob && !(ob->flag & OB_POSEMODE)) {
2203 if((dz_flag)||rv3d->dist==0) {
2205 rv3d->dist = m_dist;
2206 upvec[0] = upvec[1] = 0;
2207 upvec[2] = rv3d->dist;
2208 Mat3CpyMat4(mat, rv3d->viewinv);
2209 Mat3MulVecfl(mat, upvec);
2210 VecAddf(rv3d->ofs, rv3d->ofs, upvec);
2213 /*----------------------------------------------------
2214 * sometimes this routine is called from headerbuttons
2215 * viewmove needs to refresh the screen
2217 // XXX areawinset(curarea->win);
2219 /*----------------------------------------------------
2220 * record how much time has passed. clamp at 10 Hz
2221 * pretend the previous frame occured at the clamped time
2223 // now = PIL_check_seconds_timer();
2224 // frametime = (now - prevTime);
2225 // if (frametime > 0.1f){ /* if more than 1/10s */
2226 // frametime = 1.0f/60.0; /* clamp at 1/60s so no jumps when starting to move */
2229 // sbadjust *= 60 * frametime; /* normalize ndof device adjustments to 100Hz for framerate independence */
2231 /* fetch the current state of the ndof device & enforce dominant mode if selected */
2232 // XXX getndof(fval);
2233 if (v3d->ndoffilter)
2234 filterNDOFvalues(fval);
2237 // put scaling back here, was previously in ghostwinlay
2238 fval[0] = fval[0] * (1.0f/600.0f);
2239 fval[1] = fval[1] * (1.0f/600.0f);
2240 fval[2] = fval[2] * (1.0f/1100.0f);
2241 fval[3] = fval[3] * 0.00005f;
2242 fval[4] =-fval[4] * 0.00005f;
2243 fval[5] = fval[5] * 0.00005f;
2244 fval[6] = fval[6] / 1000000.0f;
2246 // scale more if not in perspective mode
2247 if (rv3d->persp == V3D_ORTHO) {
2248 fval[0] = fval[0] * 0.05f;
2249 fval[1] = fval[1] * 0.05f;
2250 fval[2] = fval[2] * 0.05f;
2251 fval[3] = fval[3] * 0.9f;
2252 fval[4] = fval[4] * 0.9f;
2253 fval[5] = fval[5] * 0.9f;
2257 /* set object offset */
2259 obofs[0] = -ob->obmat[3][0];
2260 obofs[1] = -ob->obmat[3][1];
2261 obofs[2] = -ob->obmat[3][2];
2264 VECCOPY(obofs, rv3d->ofs);
2267 /* calc an adjustment based on distance from camera
2268 disabled per patch 14402 */
2272 VecSubf(diff, obofs, rv3d->ofs);
2273 d = VecLength(diff);
2277 reverse = (rv3d->persmat[2][1] < 0.0f) ? -1.0f : 1.0f;
2279 /*----------------------------------------------------
2283 curareaX = sbadjust * psens * fval[0];
2284 curareaY = sbadjust * psens * fval[1];
2285 dvec[0] = curareaX * rv3d->persinv[0][0] + curareaY * rv3d->persinv[1][0];
2286 dvec[1] = curareaX * rv3d->persinv[0][1] + curareaY * rv3d->persinv[1][1];
2287 dvec[2] = curareaX * rv3d->persinv[0][2] + curareaY * rv3d->persinv[1][2];
2288 VecAddf(rv3d->ofs, rv3d->ofs, dvec);
2290 /*----------------------------------------------------
2293 len = zsens * sbadjust * fval[2];
2295 if (rv3d->persp==V3D_CAMOB) {
2296 if(rv3d->persp==V3D_CAMOB) { /* This is stupid, please fix - TODO */
2297 rv3d->camzoom+= 10.0f * -len;
2299 if (rv3d->camzoom < minZoom) rv3d->camzoom = minZoom;
2300 else if (rv3d->camzoom > maxZoom) rv3d->camzoom = maxZoom;
2302 else if ((rv3d->dist> 0.001*v3d->grid) && (rv3d->dist<10.0*v3d->far)) {
2303 rv3d->dist*=(1.0 + len);
2307 /*----------------------------------------------------
2308 * ndof device turntable
2309 * derived from the turntable code in viewmove
2312 /* Get the 3x3 matrix and its inverse from the quaternion */
2313 QuatToMat3(rv3d->viewquat, m);
2316 /* Determine the direction of the x vector (for rotating up and down) */
2317 /* This can likely be compuated directly from the quaternion. */
2318 Mat3MulVecfl(m_inv,xvec);
2319 Mat3MulVecfl(m_inv,yvec);
2320 Mat3MulVecfl(m_inv,zvec);
2322 /* Perform the up/down rotation */
2323 phi = sbadjust * rsens * /*0.5f * */ fval[3]; /* spin vertically half as fast as horizontally */
2326 q1[1] = si * xvec[0];
2327 q1[2] = si * xvec[1];
2328 q1[3] = si * xvec[2];
2329 QuatMul(rv3d->viewquat, rv3d->viewquat, q1);
2332 QuatConj(q1); /* conj == inv for unit quat */
2333 VecSubf(v3d->ofs, v3d->ofs, obofs);
2334 QuatMulVecf(q1, rv3d->ofs);
2335 VecAddf(rv3d->ofs, rv3d->ofs, obofs);
2338 /* Perform the orbital rotation */
2339 /* Perform the orbital rotation
2340 If the seen Up axis is parallel to the zoom axis, rotation should be
2341 achieved with a pure Roll motion (no Spin) on the device. When you start
2342 to tilt, moving from Top to Side view, Spinning will increasingly become
2343 more relevant while the Roll component will decrease. When a full
2344 Side view is reached, rotations around the world's Up axis are achieved
2345 with a pure Spin-only motion. In other words the control of the spinning
2346 around the world's Up axis should move from the device's Spin axis to the
2347 device's Roll axis depending on the orientation of the world's Up axis
2348 relative to the screen. */
2349 //phi = sbadjust * rsens * reverse * fval[4]; /* spin the knob, y axis */
2350 phi = sbadjust * rsens * (yvec[2] * fval[4] + zvec[2] * fval[5]);
2352 q1[1] = q1[2] = 0.0;
2354 QuatMul(rv3d->viewquat, rv3d->viewquat, q1);
2358 VecSubf(rv3d->ofs, rv3d->ofs, obofs);
2359 QuatMulVecf(q1, rv3d->ofs);
2360 VecAddf(rv3d->ofs, rv3d->ofs, obofs);
2363 /*----------------------------------------------------
2364 * refresh the screen
2366 // XXX scrarea_do_windraw(curarea);