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_arithb.h"
49 #include "BLI_blenlib.h"
50 #include "BLI_editVert.h"
54 #include "BKE_action.h"
55 #include "BKE_context.h"
56 #include "BKE_object.h"
57 #include "BKE_global.h"
59 #include "BKE_scene.h"
60 #include "BKE_screen.h"
61 #include "BKE_utildefines.h"
63 #include "RE_pipeline.h" // make_stars
71 #include "ED_screen.h"
72 #include "ED_view3d.h"
74 #include "UI_interface.h"
75 #include "UI_resources.h"
76 #include "UI_view2d.h"
78 #include "PIL_time.h" /* smoothview */
80 #include "view3d_intern.h" // own include
82 #define BL_NEAR_CLIP 0.001
86 /* use this call when executing an operator,
87 event system doesn't set for each event the
88 opengl drawing context */
89 void view3d_operator_needs_opengl(const bContext *C)
91 ARegion *ar= CTX_wm_region(C);
93 /* for debugging purpose, context should always be OK */
94 if(ar->regiontype!=RGN_TYPE_WINDOW)
95 printf("view3d_operator_needs_opengl error, wrong region\n");
97 RegionView3D *rv3d= ar->regiondata;
99 wmSubWindowSet(CTX_wm_window(C), ar->swinid);
100 glMatrixMode(GL_PROJECTION);
101 wmLoadMatrix(rv3d->winmat);
102 glMatrixMode(GL_MODELVIEW);
103 wmLoadMatrix(rv3d->viewmat);
107 float *give_cursor(Scene *scene, View3D *v3d)
109 if(v3d && v3d->localview) return v3d->cursor;
110 else return scene->cursor;
114 /* Gets the lens and clipping values from a camera of lamp type object */
115 static void object_lens_clip_settings(Object *ob, float *lens, float *clipsta, float *clipend)
119 if(ob->type==OB_LAMP ) {
123 fac= cos( M_PI*la->spotsize/360.0);
125 *lens= 16.0*fac/sin(x1);
127 if (clipsta) *clipsta= la->clipsta;
128 if (clipend) *clipend= la->clipend;
130 else if(ob->type==OB_CAMERA) {
131 Camera *cam= ob->data;
132 if (lens) *lens= cam->lens;
133 if (clipsta) *clipsta= cam->clipsta;
134 if (clipend) *clipend= cam->clipend;
137 if (lens) *lens= 35.0f;
142 /* Gets the view trasnformation from a camera
143 * currently dosnt take camzoom into account
145 * The dist is not modified for this function, if NULL its assimed zero
147 static void view_settings_from_ob(Object *ob, float *ofs, float *quat, float *dist, float *lens)
157 VECCOPY(ofs, ob->obmat[3]);
158 VecMulf(ofs, -1.0f); /*flip the vector*/
163 Mat4CpyMat4(bmat, ob->obmat);
165 Mat4Invert(imat, bmat);
166 Mat3CpyMat4(tmat, imat);
167 Mat3ToQuat(tmat, quat);
172 Mat3CpyMat4(tmat, ob->obmat);
174 vec[0]= vec[1] = 0.0;
176 Mat3MulVecfl(tmat, vec);
177 VecSubf(ofs, ofs, vec);
182 object_lens_clip_settings(ob, lens, NULL, NULL);
186 /* ****************** smooth view operator ****************** */
188 struct SmoothViewStore {
189 float orig_dist, new_dist;
190 float orig_lens, new_lens;
191 float orig_quat[4], new_quat[4];
192 float orig_ofs[3], new_ofs[3];
194 int to_camera, orig_view;
199 /* will start timer if appropriate */
200 /* the arguments are the desired situation */
201 void smooth_view(bContext *C, Object *oldcamera, Object *camera, float *ofs, float *quat, float *dist, float *lens)
203 View3D *v3d = CTX_wm_view3d(C);
204 RegionView3D *rv3d= CTX_wm_region_view3d(C);
205 struct SmoothViewStore sms;
208 VECCOPY(sms.new_ofs, rv3d->ofs);
209 QUATCOPY(sms.new_quat, rv3d->viewquat);
210 sms.new_dist= rv3d->dist;
211 sms.new_lens= v3d->lens;
214 /* store the options we want to end with */
215 if(ofs) VECCOPY(sms.new_ofs, ofs);
216 if(quat) QUATCOPY(sms.new_quat, quat);
217 if(dist) sms.new_dist= *dist;
218 if(lens) sms.new_lens= *lens;
221 view_settings_from_ob(camera, sms.new_ofs, sms.new_quat, &sms.new_dist, &sms.new_lens);
222 sms.to_camera= 1; /* restore view3d values in end */
225 if (C && U.smooth_viewtx) {
226 int changed = 0; /* zero means no difference */
228 if (sms.new_dist != rv3d->dist)
230 if (sms.new_lens != v3d->lens)
233 if ((sms.new_ofs[0]!=rv3d->ofs[0]) ||
234 (sms.new_ofs[1]!=rv3d->ofs[1]) ||
235 (sms.new_ofs[2]!=rv3d->ofs[2]) )
238 if ((sms.new_quat[0]!=rv3d->viewquat[0]) ||
239 (sms.new_quat[1]!=rv3d->viewquat[1]) ||
240 (sms.new_quat[2]!=rv3d->viewquat[2]) ||
241 (sms.new_quat[3]!=rv3d->viewquat[3]) )
244 /* The new view is different from the old one
245 * so animate the view */
248 sms.time_allowed= (double)U.smooth_viewtx / 1000.0;
250 /* if this is view rotation only
251 * we can decrease the time allowed by
252 * the angle between quats
253 * this means small rotations wont lag */
254 if (quat && !ofs && !dist) {
255 float vec1[3], vec2[3];
257 VECCOPY(vec1, sms.new_quat);
258 VECCOPY(vec2, sms.orig_quat);
261 /* scale the time allowed by the rotation */
262 sms.time_allowed *= NormalizedVecAngle2(vec1, vec2)/(M_PI/2);
265 /* original values */
267 sms.orig_dist= rv3d->dist; // below function does weird stuff with it...
268 view_settings_from_ob(oldcamera, sms.orig_ofs, sms.orig_quat, &sms.orig_dist, &sms.orig_lens);
271 VECCOPY(sms.orig_ofs, rv3d->ofs);
272 QUATCOPY(sms.orig_quat, rv3d->viewquat);
273 sms.orig_dist= rv3d->dist;
274 sms.orig_lens= v3d->lens;
276 /* grid draw as floor */
277 sms.orig_view= rv3d->view;
280 /* ensure it shows correct */
281 if(sms.to_camera) rv3d->persp= V3D_PERSP;
283 /* keep track of running timer! */
285 rv3d->sms= MEM_mallocN(sizeof(struct SmoothViewStore), "smoothview v3d");
287 if(rv3d->smooth_timer)
288 WM_event_remove_window_timer(CTX_wm_window(C), rv3d->smooth_timer);
289 /* TIMER1 is hardcoded in keymap */
290 rv3d->smooth_timer= WM_event_add_window_timer(CTX_wm_window(C), TIMER1, 1.0/30.0); /* max 30 frs/sec */
296 /* if we get here nothing happens */
297 if(sms.to_camera==0) {
298 VECCOPY(rv3d->ofs, sms.new_ofs);
299 QUATCOPY(rv3d->viewquat, sms.new_quat);
300 rv3d->dist = sms.new_dist;
301 v3d->lens = sms.new_lens;
303 ED_region_tag_redraw(CTX_wm_region(C));
306 /* only meant for timer usage */
307 static int view3d_smoothview_invoke(bContext *C, wmOperator *op, wmEvent *event)
309 View3D *v3d = CTX_wm_view3d(C);
310 RegionView3D *rv3d= CTX_wm_region_view3d(C);
311 struct SmoothViewStore *sms= rv3d->sms;
312 double step, step_inv;
314 /* escape if not our timer */
315 if(rv3d->smooth_timer==NULL || rv3d->smooth_timer!=event->customdata)
316 return OPERATOR_PASS_THROUGH;
318 step = (rv3d->smooth_timer->duration)/sms->time_allowed;
323 /* if we went to camera, store the original */
325 rv3d->persp= V3D_CAMOB;
326 VECCOPY(rv3d->ofs, sms->orig_ofs);
327 QUATCOPY(rv3d->viewquat, sms->orig_quat);
328 rv3d->dist = sms->orig_dist;
329 v3d->lens = sms->orig_lens;
332 VECCOPY(rv3d->ofs, sms->new_ofs);
333 QUATCOPY(rv3d->viewquat, sms->new_quat);
334 rv3d->dist = sms->new_dist;
335 v3d->lens = sms->new_lens;
337 rv3d->view= sms->orig_view;
339 MEM_freeN(rv3d->sms);
342 WM_event_remove_window_timer(CTX_wm_window(C), rv3d->smooth_timer);
343 rv3d->smooth_timer= NULL;
349 if (step < 0.5) step = (float)pow(step*2, 2)/2;
350 else step = (float)1-(pow(2*(1-step),2)/2);
355 rv3d->ofs[i] = sms->new_ofs[i]*step + sms->orig_ofs[i]*step_inv;
357 QuatInterpol(rv3d->viewquat, sms->orig_quat, sms->new_quat, step);
359 rv3d->dist = sms->new_dist*step + sms->orig_dist*step_inv;
360 v3d->lens = sms->new_lens*step + sms->orig_lens*step_inv;
363 ED_region_tag_redraw(CTX_wm_region(C));
365 return OPERATOR_FINISHED;
368 void VIEW3D_OT_smoothview(wmOperatorType *ot)
372 ot->name= "Smooth View";
373 ot->idname= "VIEW3D_OT_smoothview";
376 ot->invoke= view3d_smoothview_invoke;
378 ot->poll= ED_operator_view3d_active;
381 static int view3d_setcameratoview_exec(bContext *C, wmOperator *op)
383 View3D *v3d = CTX_wm_view3d(C);
384 RegionView3D *rv3d= CTX_wm_region_view3d(C);
389 dvec[0]= rv3d->dist*rv3d->viewinv[2][0];
390 dvec[1]= rv3d->dist*rv3d->viewinv[2][1];
391 dvec[2]= rv3d->dist*rv3d->viewinv[2][2];
393 VECCOPY(ob->loc, dvec);
394 VecSubf(ob->loc, ob->loc, v3d->ofs);
395 rv3d->viewquat[0]= -rv3d->viewquat[0];
397 QuatToEul(rv3d->viewquat, ob->rot);
398 rv3d->viewquat[0]= -rv3d->viewquat[0];
400 ob->recalc= OB_RECALC_OB;
402 WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, CTX_data_scene(C));
404 return OPERATOR_FINISHED;
408 void VIEW3D_OT_setcameratoview(wmOperatorType *ot)
412 ot->name= "Align Camera To View";
413 ot->idname= "VIEW3D_OT_set_camera_to_view";
416 ot->exec= view3d_setcameratoview_exec;
417 ot->poll= ED_operator_view3d_active;
420 /* ********************************** */
422 /* create intersection coordinates in view Z direction at mouse coordinates */
423 void viewline(ARegion *ar, View3D *v3d, short mval[2], float ray_start[3], float ray_end[3])
425 RegionView3D *rv3d= ar->regiondata;
428 if(rv3d->persp != V3D_ORTHO){
429 vec[0]= 2.0f * mval[0] / ar->winx - 1;
430 vec[1]= 2.0f * mval[1] / ar->winy - 1;
434 Mat4MulVec4fl(rv3d->persinv, vec);
435 VecMulf(vec, 1.0f / vec[3]);
437 VECCOPY(ray_start, rv3d->viewinv[3]);
438 VECSUB(vec, vec, ray_start);
441 VECADDFAC(ray_start, rv3d->viewinv[3], vec, v3d->near);
442 VECADDFAC(ray_end, rv3d->viewinv[3], vec, v3d->far);
445 vec[0] = 2.0f * mval[0] / ar->winx - 1;
446 vec[1] = 2.0f * mval[1] / ar->winy - 1;
450 Mat4MulVec4fl(rv3d->persinv, vec);
452 VECADDFAC(ray_start, vec, rv3d->viewinv[2], 1000.0f);
453 VECADDFAC(ray_end, vec, rv3d->viewinv[2], -1000.0f);
457 /* create intersection ray in view Z direction at mouse coordinates */
458 void viewray(ARegion *ar, View3D *v3d, short mval[2], float ray_start[3], float ray_normal[3])
462 viewline(ar, v3d, mval, ray_start, ray_end);
463 VecSubf(ray_normal, ray_end, ray_start);
464 Normalize(ray_normal);
468 void initgrabz(RegionView3D *rv3d, float x, float y, float z)
470 if(rv3d==NULL) return;
471 rv3d->zfac= rv3d->persmat[0][3]*x+ rv3d->persmat[1][3]*y+ rv3d->persmat[2][3]*z+ rv3d->persmat[3][3];
473 /* if x,y,z is exactly the viewport offset, zfac is 0 and we don't want that
474 * (accounting for near zero values)
476 if (rv3d->zfac < 1.e-6f && rv3d->zfac > -1.e-6f) rv3d->zfac = 1.0f;
478 /* Negative zfac means x, y, z was behind the camera (in perspective).
479 * This gives flipped directions, so revert back to ok default case.
481 if (rv3d->zfac < 0.0f) rv3d->zfac = 1.0f;
484 void window_to_3d(ARegion *ar, float *vec, short mx, short my)
486 RegionView3D *rv3d= ar->regiondata;
488 /* always call initgrabz */
491 dx= 2.0f*mx*rv3d->zfac/ar->winx;
492 dy= 2.0f*my*rv3d->zfac/ar->winy;
494 vec[0]= (rv3d->persinv[0][0]*dx + rv3d->persinv[1][0]*dy);
495 vec[1]= (rv3d->persinv[0][1]*dx + rv3d->persinv[1][1]*dy);
496 vec[2]= (rv3d->persinv[0][2]*dx + rv3d->persinv[1][2]*dy);
499 float read_cached_depth(ViewContext *vc, int x, int y)
501 ViewDepths *vd = vc->rv3d->depths;
503 y -= vc->ar->winrct.ymin;
505 if(vd && vd->depths && x > 0 && y > 0 && x < vd->w && y < vd->h)
506 return vd->depths[y * vd->w + x];
511 void request_depth_update(ViewContext *vc)
514 vc->rv3d->depths->damaged= 1;
517 void view3d_get_object_project_mat(RegionView3D *rv3d, Object *ob, float pmat[4][4], float vmat[4][4])
519 Mat4MulMat4(vmat, ob->obmat, rv3d->viewmat);
520 Mat4MulMat4(pmat, vmat, rv3d->winmat);
521 Mat4CpyMat4(vmat, ob->obmat);
524 /* projectmat brings it to window coords, wmat to rotated world space */
525 void view3d_project_short_clip(ARegion *ar, float *vec, short *adr, float projmat[4][4], float wmat[4][4])
527 RegionView3D *rv3d= ar->regiondata;
528 float fx, fy, vec4[4];
532 /* clipplanes in eye space */
533 if(rv3d->rflag & RV3D_CLIPPING) {
535 Mat4MulVecfl(wmat, vec4);
536 if(view3d_test_clipping(rv3d, vec4))
543 Mat4MulVec4fl(projmat, vec4);
545 /* clipplanes in window space */
546 if( vec4[3]>BL_NEAR_CLIP ) { /* 0.001 is the NEAR clipping cutoff for picking */
547 fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]);
549 if( fx>0 && fx<ar->winx) {
551 fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]);
553 if(fy>0.0 && fy< (float)ar->winy) {
554 adr[0]= (short)floor(fx);
555 adr[1]= (short)floor(fy);
561 void view3d_project_short_noclip(ARegion *ar, float *vec, short *adr, float mat[4][4])
563 float fx, fy, vec4[4];
570 Mat4MulVec4fl(mat, vec4);
572 if( vec4[3]>BL_NEAR_CLIP ) { /* 0.001 is the NEAR clipping cutoff for picking */
573 fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]);
575 if( fx>-32700 && fx<32700) {
577 fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]);
579 if(fy>-32700.0 && fy<32700.0) {
580 adr[0]= (short)floor(fx);
581 adr[1]= (short)floor(fy);
587 void view3d_project_float(ARegion *ar, float *vec, float *adr, float mat[4][4])
595 Mat4MulVec4fl(mat, vec4);
597 if( vec4[3]>FLT_EPSILON ) {
598 adr[0] = (float)(ar->winx/2.0f)+(ar->winx/2.0f)*vec4[0]/vec4[3];
599 adr[1] = (float)(ar->winy/2.0f)+(ar->winy/2.0f)*vec4[1]/vec4[3];
601 adr[0] = adr[1] = 0.0f;
605 int boundbox_clip(RegionView3D *rv3d, float obmat[][4], BoundBox *bb)
610 float vec[4], min, max;
613 if(bb==NULL) return 1;
614 if(bb->flag & OB_BB_DISABLED) return 1;
616 Mat4MulMat4(mat, obmat, rv3d->persmat);
619 VECCOPY(vec, bb->vec[a]);
621 Mat4MulVec4fl(mat, vec);
626 if(vec[0] < min) fl+= 1;
627 if(vec[0] > max) fl+= 2;
628 if(vec[1] < min) fl+= 4;
629 if(vec[1] > max) fl+= 8;
630 if(vec[2] < min) fl+= 16;
631 if(vec[2] > max) fl+= 32;
634 if(flag==0) return 1;
640 void project_short(ARegion *ar, float *vec, short *adr) /* clips */
642 RegionView3D *rv3d= ar->regiondata;
643 float fx, fy, vec4[4];
647 if(rv3d->rflag & RV3D_CLIPPING) {
648 if(view3d_test_clipping(rv3d, vec))
654 Mat4MulVec4fl(rv3d->persmat, vec4);
656 if( vec4[3]>BL_NEAR_CLIP ) { /* 0.001 is the NEAR clipping cutoff for picking */
657 fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]);
659 if( fx>0 && fx<ar->winx) {
661 fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]);
663 if(fy>0.0 && fy< (float)ar->winy) {
664 adr[0]= (short)floor(fx);
665 adr[1]= (short)floor(fy);
671 void project_int(ARegion *ar, float *vec, int *adr)
673 RegionView3D *rv3d= ar->regiondata;
674 float fx, fy, vec4[4];
676 adr[0]= (int)2140000000.0f;
680 Mat4MulVec4fl(rv3d->persmat, vec4);
682 if( vec4[3]>BL_NEAR_CLIP ) { /* 0.001 is the NEAR clipping cutoff for picking */
683 fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]);
685 if( fx>-2140000000.0f && fx<2140000000.0f) {
686 fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]);
688 if(fy>-2140000000.0f && fy<2140000000.0f) {
689 adr[0]= (int)floor(fx);
690 adr[1]= (int)floor(fy);
696 void project_int_noclip(ARegion *ar, float *vec, int *adr)
698 RegionView3D *rv3d= ar->regiondata;
699 float fx, fy, vec4[4];
704 Mat4MulVec4fl(rv3d->persmat, vec4);
706 if( fabs(vec4[3]) > BL_NEAR_CLIP ) {
707 fx = (ar->winx/2)*(1 + vec4[0]/vec4[3]);
708 fy = (ar->winy/2)*(1 + vec4[1]/vec4[3]);
710 adr[0] = (int)floor(fx);
711 adr[1] = (int)floor(fy);
715 adr[0] = ar->winx / 2;
716 adr[1] = ar->winy / 2;
720 void project_short_noclip(ARegion *ar, float *vec, short *adr)
722 RegionView3D *rv3d= ar->regiondata;
723 float fx, fy, vec4[4];
729 Mat4MulVec4fl(rv3d->persmat, vec4);
731 if( vec4[3]>BL_NEAR_CLIP ) { /* 0.001 is the NEAR clipping cutoff for picking */
732 fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]);
734 if( fx>-32700 && fx<32700) {
736 fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]);
738 if(fy>-32700.0 && fy<32700.0) {
739 adr[0]= (short)floor(fx);
740 adr[1]= (short)floor(fy);
746 void project_float(ARegion *ar, float *vec, float *adr)
748 RegionView3D *rv3d= ar->regiondata;
755 Mat4MulVec4fl(rv3d->persmat, vec4);
757 if( vec4[3]>BL_NEAR_CLIP ) {
758 adr[0] = (float)(ar->winx/2.0)+(ar->winx/2.0)*vec4[0]/vec4[3];
759 adr[1] = (float)(ar->winy/2.0)+(ar->winy/2.0)*vec4[1]/vec4[3];
763 void project_float_noclip(ARegion *ar, float *vec, float *adr)
765 RegionView3D *rv3d= ar->regiondata;
771 Mat4MulVec4fl(rv3d->persmat, vec4);
773 if( fabs(vec4[3]) > BL_NEAR_CLIP ) {
774 adr[0] = (float)(ar->winx/2.0)+(ar->winx/2.0)*vec4[0]/vec4[3];
775 adr[1] = (float)(ar->winy/2.0)+(ar->winy/2.0)*vec4[1]/vec4[3];
779 adr[0] = ar->winx / 2.0f;
780 adr[1] = ar->winy / 2.0f;
786 /* also exposed in previewrender.c */
787 int get_view3d_viewplane(View3D *v3d, RegionView3D *rv3d, int winxi, int winyi, rctf *viewplane, float *clipsta, float *clipend, float *pixsize)
790 float lens, fac, x1, y1, x2, y2;
791 float winx= (float)winxi, winy= (float)winyi;
799 if(rv3d->persp==V3D_CAMOB) {
801 if(v3d->camera->type==OB_LAMP ) {
804 la= v3d->camera->data;
805 fac= cos( M_PI*la->spotsize/360.0);
808 lens= 16.0*fac/sin(x1);
810 *clipsta= la->clipsta;
811 *clipend= la->clipend;
813 else if(v3d->camera->type==OB_CAMERA) {
814 cam= v3d->camera->data;
816 *clipsta= cam->clipsta;
817 *clipend= cam->clipend;
822 if(rv3d->persp==V3D_ORTHO) {
823 if(winx>winy) x1= -rv3d->dist;
824 else x1= -winx*rv3d->dist/winy;
827 if(winx>winy) y1= -winy*rv3d->dist/winx;
828 else y1= -rv3d->dist;
831 *clipend *= 0.5; // otherwise too extreme low zbuffer quality
832 *clipsta= - *clipend;
836 /* fac for zoom, also used for camdx */
837 if(rv3d->persp==V3D_CAMOB) {
838 fac= (1.41421+( (float)rv3d->camzoom )/50.0);
843 /* viewplane size depends... */
844 if(cam && cam->type==CAM_ORTHO) {
845 /* ortho_scale == 1 means exact 1 to 1 mapping */
846 float dfac= 2.0*cam->ortho_scale/fac;
848 if(winx>winy) x1= -dfac;
849 else x1= -winx*dfac/winy;
852 if(winx>winy) y1= -winy*dfac/winx;
860 if(winx>winy) dfac= 64.0/(fac*winx*lens);
861 else dfac= 64.0/(fac*winy*lens);
863 x1= - *clipsta * winx*dfac;
865 y1= - *clipsta * winy*dfac;
869 /* cam view offset */
871 float dx= 0.5*fac*rv3d->camdx*(x2-x1);
872 float dy= 0.5*fac*rv3d->camdy*(y2-y1);
884 viewfac= (winx >= winy)? winx: winy;
885 *pixsize= 1.0f/viewfac;
888 viewfac= (((winx >= winy)? winx: winy)*lens)/32.0;
889 *pixsize= *clipsta/viewfac;
902 /* important to not set windows active in here, can be renderwin for example */
903 void setwinmatrixview3d(ARegion *ar, View3D *v3d, rctf *rect) /* rect: for picking */
905 RegionView3D *rv3d= ar->regiondata;
907 float clipsta, clipend, x1, y1, x2, y2;
910 orth= get_view3d_viewplane(v3d, rv3d, ar->winx, ar->winy, &viewplane, &clipsta, &clipend, NULL);
911 // printf("%d %d %f %f %f %f %f %f\n", winx, winy, viewplane.xmin, viewplane.ymin, viewplane.xmax, viewplane.ymax, clipsta, clipend);
917 if(rect) { /* picking */
918 rect->xmin/= (float)ar->winx;
919 rect->xmin= x1+rect->xmin*(x2-x1);
920 rect->ymin/= (float)ar->winy;
921 rect->ymin= y1+rect->ymin*(y2-y1);
922 rect->xmax/= (float)ar->winx;
923 rect->xmax= x1+rect->xmax*(x2-x1);
924 rect->ymax/= (float)ar->winy;
925 rect->ymax= y1+rect->ymax*(y2-y1);
927 if(orth) wmOrtho(rect->xmin, rect->xmax, rect->ymin, rect->ymax, -clipend, clipend);
928 else wmFrustum(rect->xmin, rect->xmax, rect->ymin, rect->ymax, clipsta, clipend);
932 if(orth) wmOrtho(x1, x2, y1, y2, clipsta, clipend);
933 else wmFrustum(x1, x2, y1, y2, clipsta, clipend);
936 /* not sure what this was for? (ton) */
937 glMatrixMode(GL_PROJECTION);
938 wmGetMatrix(rv3d->winmat);
939 glMatrixMode(GL_MODELVIEW);
943 static void obmat_to_viewmat(View3D *v3d, RegionView3D *rv3d, Object *ob, short smooth)
948 rv3d->view= 0; /* dont show the grid */
950 Mat4CpyMat4(bmat, ob->obmat);
952 Mat4Invert(rv3d->viewmat, bmat);
954 /* view quat calculation, needed for add object */
955 Mat3CpyMat4(tmat, rv3d->viewmat);
958 if (rv3d->persp==V3D_CAMOB && v3d->camera) {
959 /* were from a camera view */
962 float orig_dist= rv3d->dist;
963 float orig_lens= v3d->lens;
964 VECCOPY(orig_ofs, rv3d->ofs);
966 /* Switch from camera view */
967 Mat3ToQuat(tmat, new_quat);
969 rv3d->persp=V3D_PERSP;
972 view_settings_from_ob(v3d->camera, rv3d->ofs, NULL, NULL, &v3d->lens);
973 smooth_view(NULL, NULL, NULL, orig_ofs, new_quat, &orig_dist, &orig_lens); // XXX
975 rv3d->persp=V3D_CAMOB; /* just to be polite, not needed */
978 Mat3ToQuat(tmat, new_quat);
979 smooth_view(NULL, NULL, NULL, NULL, new_quat, NULL, NULL); // XXX
982 Mat3ToQuat(tmat, rv3d->viewquat);
986 /* dont set windows active in in here, is used by renderwin too */
987 void setviewmatrixview3d(Scene *scene, View3D *v3d, RegionView3D *rv3d)
989 if(rv3d->persp==V3D_CAMOB) { /* obs/camera */
991 where_is_object(scene, v3d->camera);
992 obmat_to_viewmat(v3d, rv3d, v3d->camera, 0);
995 QuatToMat4(rv3d->viewquat, rv3d->viewmat);
996 rv3d->viewmat[3][2]-= rv3d->dist;
1001 QuatToMat4(rv3d->viewquat, rv3d->viewmat);
1002 if(rv3d->persp==V3D_PERSP) rv3d->viewmat[3][2]-= rv3d->dist;
1003 if(v3d->ob_centre) {
1004 Object *ob= v3d->ob_centre;
1007 VECCOPY(vec, ob->obmat[3]);
1008 if(ob->type==OB_ARMATURE && v3d->ob_centre_bone[0]) {
1009 bPoseChannel *pchan= get_pose_channel(ob->pose, v3d->ob_centre_bone);
1011 VECCOPY(vec, pchan->pose_mat[3]);
1012 Mat4MulVecfl(ob->obmat, vec);
1015 i_translate(-vec[0], -vec[1], -vec[2], rv3d->viewmat);
1017 else i_translate(rv3d->ofs[0], rv3d->ofs[1], rv3d->ofs[2], rv3d->viewmat);
1021 /* IGLuint-> GLuint*/
1022 /* Warning: be sure to account for a negative return value
1023 * This is an error, "Too many objects in select buffer"
1024 * and no action should be taken (can crash blender) if this happens
1026 short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int bufsize, rcti *input)
1028 Scene *scene= vc->scene;
1029 View3D *v3d= vc->v3d;
1030 ARegion *ar= vc->ar;
1036 /* case not a border select */
1037 if(input->xmin==input->xmax) {
1038 rect.xmin= input->xmin-12; // seems to be default value for bones only now
1039 rect.xmax= input->xmin+12;
1040 rect.ymin= input->ymin-12;
1041 rect.ymax= input->xmin+12;
1044 rect.xmin= input->xmin;
1045 rect.xmax= input->xmax;
1046 rect.ymin= input->ymin;
1047 rect.ymax= input->ymax;
1050 setwinmatrixview3d(ar, v3d, &rect);
1051 Mat4MulMat4(vc->rv3d->persmat, vc->rv3d->viewmat, vc->rv3d->winmat);
1053 if(v3d->drawtype > OB_WIRE) {
1055 glEnable(GL_DEPTH_TEST);
1058 if(vc->rv3d->rflag & RV3D_CLIPPING)
1059 view3d_set_clipping(vc->rv3d);
1061 glSelectBuffer( bufsize, (GLuint *)buffer);
1062 glRenderMode(GL_SELECT);
1063 glInitNames(); /* these two calls whatfor? It doesnt work otherwise */
1067 if(vc->obedit && vc->obedit->type==OB_MBALL) {
1068 draw_object(scene, ar, v3d, BASACT, DRAW_PICKING|DRAW_CONSTCOLOR);
1070 else if ((vc->obedit && vc->obedit->type==OB_ARMATURE)) {
1071 draw_object(scene, ar, v3d, BASACT, DRAW_PICKING|DRAW_CONSTCOLOR);
1076 v3d->xray= TRUE; // otherwise it postpones drawing
1077 for(base= scene->base.first; base; base= base->next) {
1078 if(base->lay & v3d->lay) {
1080 if (base->object->restrictflag & OB_RESTRICT_SELECT)
1085 draw_object(scene, ar, v3d, base, DRAW_PICKING|DRAW_CONSTCOLOR);
1087 /* we draw group-duplicators for selection too */
1088 if((base->object->transflag & OB_DUPLI) && base->object->dup_group) {
1093 tbase.flag= OB_FROMDUPLI;
1094 lb= object_duplilist(scene, base->object);
1096 for(dob= lb->first; dob; dob= dob->next) {
1097 tbase.object= dob->ob;
1098 Mat4CpyMat4(dob->ob->obmat, dob->mat);
1100 draw_object(scene, ar, v3d, &tbase, DRAW_PICKING|DRAW_CONSTCOLOR);
1102 Mat4CpyMat4(dob->ob->obmat, dob->omat);
1104 free_object_duplilist(lb);
1110 v3d->xray= FALSE; // restore
1113 glPopName(); /* see above (pushname) */
1114 hits= glRenderMode(GL_RENDER);
1117 setwinmatrixview3d(ar, v3d, NULL);
1118 Mat4MulMat4(vc->rv3d->persmat, vc->rv3d->viewmat, vc->rv3d->winmat);
1120 if(v3d->drawtype > OB_WIRE) {
1122 glDisable(GL_DEPTH_TEST);
1124 // XXX persp(PERSP_WIN);
1126 if(vc->rv3d->rflag & RV3D_CLIPPING)
1127 view3d_clr_clipping();
1129 if(hits<0) printf("Too many objects in select buffer\n"); // XXX make error message
1134 // XXX solve: localview on region level? no.... layers are area, so all regions in area have to be set
1135 static unsigned int free_localbit(void)
1143 /* sometimes we loose a localview: when an area is closed */
1144 /* check all areas: which localviews are in use? */
1145 for(sc= G.main->screen.first; sc; sc= sc->id.next) {
1146 for(sa= sc->areabase.first; sa; sa= sa->next) {
1147 SpaceLink *sl= sa->spacedata.first;
1148 for(; sl; sl= sl->next) {
1149 if(sl->spacetype==SPACE_VIEW3D) {
1150 View3D *v3d= (View3D*) sl;
1157 if( (lay & 0x01000000)==0) return 0x01000000;
1158 if( (lay & 0x02000000)==0) return 0x02000000;
1159 if( (lay & 0x04000000)==0) return 0x04000000;
1160 if( (lay & 0x08000000)==0) return 0x08000000;
1161 if( (lay & 0x10000000)==0) return 0x10000000;
1162 if( (lay & 0x20000000)==0) return 0x20000000;
1163 if( (lay & 0x40000000)==0) return 0x40000000;
1164 if( (lay & 0x80000000)==0) return 0x80000000;
1170 void initlocalview(Scene *scene, ARegion *ar, View3D *v3d)
1172 RegionView3D *rv3d= ar->regiondata;
1174 float size = 0.0, min[3], max[3], afm[3];
1175 unsigned int locallay;
1178 if(v3d->localvd) return;
1180 INIT_MINMAX(min, max);
1182 locallay= free_localbit();
1185 printf("Sorry, no more than 8 localviews\n"); // XXX error
1190 minmax_object(scene->obedit, min, max);
1194 BASACT->lay |= locallay;
1195 scene->obedit->lay= BASACT->lay;
1200 if(TESTBASE(v3d, base)) {
1201 minmax_object(base->object, min, max);
1202 base->lay |= locallay;
1203 base->object->lay= base->lay;
1210 afm[0]= (max[0]-min[0]);
1211 afm[1]= (max[1]-min[1]);
1212 afm[2]= (max[2]-min[2]);
1213 size= 0.7*MAX3(afm[0], afm[1], afm[2]);
1214 if(size<=0.01) size= 0.01;
1218 v3d->localvd= MEM_mallocN(sizeof(View3D), "localview");
1219 memcpy(v3d->localvd, v3d, sizeof(View3D));
1221 rv3d->ofs[0]= -(min[0]+max[0])/2.0;
1222 rv3d->ofs[1]= -(min[1]+max[1])/2.0;
1223 rv3d->ofs[2]= -(min[2]+max[2])/2.0;
1227 // correction for window aspect ratio
1228 if(ar->winy>2 && ar->winx>2) {
1229 size= (float)ar->winx/(float)ar->winy;
1230 if(size<1.0) size= 1.0/size;
1234 if (rv3d->persp==V3D_CAMOB) rv3d->persp= V3D_PERSP;
1235 if (v3d->near> 0.1) v3d->near= 0.1;
1237 v3d->cursor[0]= -rv3d->ofs[0];
1238 v3d->cursor[1]= -rv3d->ofs[1];
1239 v3d->cursor[2]= -rv3d->ofs[2];
1244 // XXX scrarea_queue_winredraw(curarea);
1250 if( base->lay & locallay ) {
1251 base->lay-= locallay;
1252 if(base->lay==0) base->lay= v3d->layact;
1253 if(base->object != scene->obedit) base->flag |= SELECT;
1254 base->object->lay= base->lay;
1258 // XXX scrarea_queue_headredraw(curarea);
1262 // XXX BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
1265 void restore_localviewdata(View3D *vd)
1267 if(vd->localvd==0) return;
1269 VECCOPY(vd->ofs, vd->localvd->ofs);
1270 vd->near= vd->localvd->near;
1271 vd->far= vd->localvd->far;
1272 vd->lay= vd->localvd->lay;
1273 vd->layact= vd->localvd->layact;
1274 vd->drawtype= vd->localvd->drawtype;
1275 vd->camera= vd->localvd->camera;
1279 void endlocalview(Scene *scene, ScrArea *sa)
1283 unsigned int locallay;
1285 if(sa->spacetype!=SPACE_VIEW3D) return;
1286 v3d= sa->spacedata.first;
1290 locallay= v3d->lay & 0xFF000000;
1292 restore_localviewdata(v3d);
1294 MEM_freeN(v3d->localvd);
1298 /* for when in other window the layers have changed */
1299 if(v3d->scenelock) v3d->lay= scene->lay;
1303 if( base->lay & locallay ) {
1304 base->lay-= locallay;
1305 if(base->lay==0) base->lay= v3d->layact;
1306 if(base->object != scene->obedit) {
1307 base->flag |= SELECT;
1308 base->object->flag |= SELECT;
1310 base->object->lay= base->lay;
1316 // XXX allqueue(REDRAWVIEW3D, 0); /* because of select */
1317 // XXX allqueue(REDRAWOOPS, 0); /* because of select */
1318 // XXX BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
1322 void view3d_align_axis_to_vector(View3D *v3d, RegionView3D *rv3d, int axisidx, float vec[3])
1324 float alignaxis[3] = {0.0, 0.0, 0.0};
1325 float norm[3], axis[3], angle, new_quat[4];
1327 if(axisidx > 0) alignaxis[axisidx-1]= 1.0;
1328 else alignaxis[-axisidx-1]= -1.0;
1333 angle= (float)acos(Inpf(alignaxis, norm));
1334 Crossf(axis, alignaxis, norm);
1335 VecRotToQuat(axis, -angle, new_quat);
1339 if (rv3d->persp==V3D_CAMOB && v3d->camera) {
1340 /* switch out of camera view */
1342 float orig_dist= rv3d->dist;
1343 float orig_lens= v3d->lens;
1345 VECCOPY(orig_ofs, rv3d->ofs);
1346 rv3d->persp= V3D_PERSP;
1348 view_settings_from_ob(v3d->camera, rv3d->ofs, NULL, NULL, &v3d->lens);
1349 smooth_view(NULL, NULL, NULL, orig_ofs, new_quat, &orig_dist, &orig_lens); // XXX
1351 if (rv3d->persp==V3D_CAMOB) rv3d->persp= V3D_PERSP; /* switch out of camera mode */
1352 smooth_view(NULL, NULL, NULL, NULL, new_quat, NULL, NULL); // XXX