2.5
[blender-staging.git] / source / blender / editors / space_view3d / view3d_view.c
1 /**
2  * $Id:
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
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. 
10  *
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.
15  *
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.
19  *
20  * The Original Code is Copyright (C) 2008 Blender Foundation.
21  * All rights reserved.
22  *
23  * 
24  * Contributor(s): Blender Foundation
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 #include <string.h>
30 #include <stdio.h>
31 #include <math.h>
32 #include <float.h>
33
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"
45
46 #include "MEM_guardedalloc.h"
47
48 #include "BLI_arithb.h"
49 #include "BLI_blenlib.h"
50 #include "BLI_editVert.h"
51 #include "BLI_rand.h"
52
53 #include "BKE_anim.h"
54 #include "BKE_action.h"
55 #include "BKE_context.h"
56 #include "BKE_object.h"
57 #include "BKE_global.h"
58 #include "BKE_main.h"
59 #include "BKE_scene.h"
60 #include "BKE_screen.h"
61 #include "BKE_utildefines.h"
62
63 #include "RE_pipeline.h"        // make_stars
64
65 #include "BIF_gl.h"
66
67 #include "WM_api.h"
68 #include "WM_types.h"
69
70 #include "ED_mesh.h"
71 #include "ED_screen.h"
72 #include "ED_view3d.h"
73
74 #include "UI_interface.h"
75 #include "UI_resources.h"
76 #include "UI_view2d.h"
77
78 #include "PIL_time.h" /* smoothview */
79
80 #include "view3d_intern.h"      // own include
81
82 #define BL_NEAR_CLIP 0.001
83
84
85
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)
90 {
91         ARegion *ar= CTX_wm_region(C);
92
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");
96         else {
97                 RegionView3D *rv3d= ar->regiondata;
98                 
99                 wmSubWindowSet(CTX_wm_window(C), ar->swinid);
100                 glMatrixMode(GL_PROJECTION);
101                 wmLoadMatrix(rv3d->winmat);
102                 glMatrixMode(GL_MODELVIEW);
103                 wmLoadMatrix(rv3d->viewmat);
104         }
105 }
106
107 float *give_cursor(Scene *scene, View3D *v3d)
108 {
109         if(v3d && v3d->localview) return v3d->cursor;
110         else return scene->cursor;
111 }
112
113
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)
116 {       
117         if (!ob) return;
118         
119         if(ob->type==OB_LAMP ) {
120                 Lamp *la = ob->data;
121                 if (lens) {
122                         float x1, fac;
123                         fac= cos( M_PI*la->spotsize/360.0);
124                         x1= saacos(fac);
125                         *lens= 16.0*fac/sin(x1);
126                 }
127                 if (clipsta)    *clipsta= la->clipsta;
128                 if (clipend)    *clipend= la->clipend;
129         }
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;
135         }
136         else {
137                 if (lens)               *lens= 35.0f;
138         }
139 }
140
141
142 /* Gets the view trasnformation from a camera
143 * currently dosnt take camzoom into account
144
145 * The dist is not modified for this function, if NULL its assimed zero
146 * */
147 static void view_settings_from_ob(Object *ob, float *ofs, float *quat, float *dist, float *lens)
148 {       
149         float bmat[4][4];
150         float imat[4][4];
151         float tmat[3][3];
152         
153         if (!ob) return;
154         
155         /* Offset */
156         if (ofs) {
157                 VECCOPY(ofs, ob->obmat[3]);
158                 VecMulf(ofs, -1.0f); /*flip the vector*/
159         }
160         
161         /* Quat */
162         if (quat) {
163                 Mat4CpyMat4(bmat, ob->obmat);
164                 Mat4Ortho(bmat);
165                 Mat4Invert(imat, bmat);
166                 Mat3CpyMat4(tmat, imat);
167                 Mat3ToQuat(tmat, quat);
168         }
169         
170         if (dist) {
171                 float vec[3];
172                 Mat3CpyMat4(tmat, ob->obmat);
173                 
174                 vec[0]= vec[1] = 0.0;
175                 vec[2]= -(*dist);
176                 Mat3MulVecfl(tmat, vec);
177                 VecSubf(ofs, ofs, vec);
178         }
179         
180         /* Lens */
181         if (lens)
182                 object_lens_clip_settings(ob, lens, NULL, NULL);
183 }
184
185
186 /* ****************** smooth view operator ****************** */
187
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];
193         
194         int to_camera, orig_view;
195         
196         double time_allowed;
197 };
198
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)
202 {
203         View3D *v3d = CTX_wm_view3d(C);
204         RegionView3D *rv3d= CTX_wm_region_view3d(C);
205         struct SmoothViewStore sms;
206         
207         /* initialize 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;
212         sms.to_camera= 0;
213         
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;
219         
220         if (camera) {
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 */
223         }
224         
225         if (C && U.smooth_viewtx) {
226                 int changed = 0; /* zero means no difference */
227                 
228                 if (sms.new_dist != rv3d->dist)
229                         changed = 1;
230                 if (sms.new_lens != v3d->lens)
231                         changed = 1;
232                 
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]) )
236                         changed = 1;
237                 
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]) )
242                         changed = 1;
243                 
244                 /* The new view is different from the old one
245                         * so animate the view */
246                 if (changed) {
247                         
248                         sms.time_allowed= (double)U.smooth_viewtx / 1000.0;
249                         
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];
256                                 
257                                 VECCOPY(vec1, sms.new_quat);
258                                 VECCOPY(vec2, sms.orig_quat);
259                                 Normalize(vec1);
260                                 Normalize(vec2);
261                                 /* scale the time allowed by the rotation */
262                                 sms.time_allowed *= NormalizedVecAngle2(vec1, vec2)/(M_PI/2); 
263                         }
264                         
265                         /* original values */
266                         if (oldcamera) {
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);
269                         }
270                         else {
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;
275                         }
276                         /* grid draw as floor */
277                         sms.orig_view= rv3d->view;
278                         rv3d->view= 0;
279                         
280                         /* ensure it shows correct */
281                         if(sms.to_camera) rv3d->persp= V3D_PERSP;
282                         
283                         /* keep track of running timer! */
284                         if(rv3d->sms==NULL)
285                                 rv3d->sms= MEM_mallocN(sizeof(struct SmoothViewStore), "smoothview v3d");
286                         *rv3d->sms= sms;
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 */
291                         
292                         return;
293                 }
294         }
295         
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;
302         }
303         ED_region_tag_redraw(CTX_wm_region(C));
304 }
305
306 /* only meant for timer usage */
307 static int view3d_smoothview_invoke(bContext *C, wmOperator *op, wmEvent *event)
308 {
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;
313         
314         /* escape if not our timer */
315         if(rv3d->smooth_timer==NULL || rv3d->smooth_timer!=event->customdata)
316                 return OPERATOR_PASS_THROUGH;
317         
318         step =  (rv3d->smooth_timer->duration)/sms->time_allowed;
319         
320         /* end timer */
321         if(step >= 1.0f) {
322                 
323                 /* if we went to camera, store the original */
324                 if(sms->to_camera) {
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;
330                 }
331                 else {
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;
336                 }
337                 rv3d->view= sms->orig_view;
338                 
339                 MEM_freeN(rv3d->sms);
340                 rv3d->sms= NULL;
341                 
342                 WM_event_remove_window_timer(CTX_wm_window(C), rv3d->smooth_timer);
343                 rv3d->smooth_timer= NULL;
344         }
345         else {
346                 int i;
347                 
348                 /* ease in/out */
349                 if (step < 0.5) step = (float)pow(step*2, 2)/2;
350                 else                    step = (float)1-(pow(2*(1-step),2)/2);
351
352                 step_inv = 1.0-step;
353
354                 for (i=0; i<3; i++)
355                         rv3d->ofs[i] = sms->new_ofs[i]*step + sms->orig_ofs[i]*step_inv;
356
357                 QuatInterpol(rv3d->viewquat, sms->orig_quat, sms->new_quat, step);
358                 
359                 rv3d->dist = sms->new_dist*step + sms->orig_dist*step_inv;
360                 v3d->lens = sms->new_lens*step + sms->orig_lens*step_inv;
361         }
362         
363         ED_region_tag_redraw(CTX_wm_region(C));
364         
365         return OPERATOR_FINISHED;
366 }
367
368 void VIEW3D_OT_smoothview(wmOperatorType *ot)
369 {
370         
371         /* identifiers */
372         ot->name= "Smooth View";
373         ot->idname= "VIEW3D_OT_smoothview";
374         
375         /* api callbacks */
376         ot->invoke= view3d_smoothview_invoke;
377         
378         ot->poll= ED_operator_view3d_active;
379 }
380
381 static int view3d_setcameratoview_exec(bContext *C, wmOperator *op)
382 {
383         View3D *v3d = CTX_wm_view3d(C);
384         RegionView3D *rv3d= CTX_wm_region_view3d(C);
385         Object *ob;
386         float dvec[3];
387         
388         ob= v3d->camera;
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];
392         
393         VECCOPY(ob->loc, dvec);
394         VecSubf(ob->loc, ob->loc, v3d->ofs);
395         rv3d->viewquat[0]= -rv3d->viewquat[0];
396
397         QuatToEul(rv3d->viewquat, ob->rot);
398         rv3d->viewquat[0]= -rv3d->viewquat[0];
399         
400         ob->recalc= OB_RECALC_OB;
401         
402         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, CTX_data_scene(C));
403         
404         return OPERATOR_FINISHED;
405
406 }
407
408 void VIEW3D_OT_setcameratoview(wmOperatorType *ot)
409 {
410         
411         /* identifiers */
412         ot->name= "Align Camera To View";
413         ot->idname= "VIEW3D_OT_set_camera_to_view";
414         
415         /* api callbacks */
416         ot->exec= view3d_setcameratoview_exec;  
417         ot->poll= ED_operator_view3d_active;
418 }
419
420 /* ********************************** */
421
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])
424 {
425         RegionView3D *rv3d= ar->regiondata;
426         float vec[4];
427         
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;
431                 vec[2]= -1.0f;
432                 vec[3]= 1.0f;
433                 
434                 Mat4MulVec4fl(rv3d->persinv, vec);
435                 VecMulf(vec, 1.0f / vec[3]);
436                 
437                 VECCOPY(ray_start, rv3d->viewinv[3]);
438                 VECSUB(vec, vec, ray_start);
439                 Normalize(vec);
440                 
441                 VECADDFAC(ray_start, rv3d->viewinv[3], vec, v3d->near);
442                 VECADDFAC(ray_end, rv3d->viewinv[3], vec, v3d->far);
443         }
444         else {
445                 vec[0] = 2.0f * mval[0] / ar->winx - 1;
446                 vec[1] = 2.0f * mval[1] / ar->winy - 1;
447                 vec[2] = 0.0f;
448                 vec[3] = 1.0f;
449                 
450                 Mat4MulVec4fl(rv3d->persinv, vec);
451                 
452                 VECADDFAC(ray_start, vec, rv3d->viewinv[2],  1000.0f);
453                 VECADDFAC(ray_end, vec, rv3d->viewinv[2], -1000.0f);
454         }
455 }
456
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])
459 {
460         float ray_end[3];
461         
462         viewline(ar, v3d, mval, ray_start, ray_end);
463         VecSubf(ray_normal, ray_end, ray_start);
464         Normalize(ray_normal);
465 }
466
467
468 void initgrabz(RegionView3D *rv3d, float x, float y, float z)
469 {
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];
472         
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)
475                 * */
476         if (rv3d->zfac < 1.e-6f && rv3d->zfac > -1.e-6f) rv3d->zfac = 1.0f;
477         
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.
480         */
481         if (rv3d->zfac < 0.0f) rv3d->zfac = 1.0f;
482 }
483
484 void window_to_3d(ARegion *ar, float *vec, short mx, short my)
485 {
486         RegionView3D *rv3d= ar->regiondata;
487         
488         /* always call initgrabz */
489         float dx, dy;
490         
491         dx= 2.0f*mx*rv3d->zfac/ar->winx;
492         dy= 2.0f*my*rv3d->zfac/ar->winy;
493         
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);
497 }
498
499 float read_cached_depth(ViewContext *vc, int x, int y)
500 {
501         ViewDepths *vd = vc->rv3d->depths;
502                 
503         y -= vc->ar->winrct.ymin;
504
505         if(vd && vd->depths && x > 0 && y > 0 && x < vd->w && y < vd->h)
506                 return vd->depths[y * vd->w + x];
507         else
508                 return 1;
509 }
510
511 void request_depth_update(ViewContext *vc)
512 {
513         if(vc->rv3d->depths)
514                 vc->rv3d->depths->damaged= 1;
515 }
516
517 void view3d_get_object_project_mat(RegionView3D *rv3d, Object *ob, float pmat[4][4], float vmat[4][4])
518 {
519         Mat4MulMat4(vmat, ob->obmat, rv3d->viewmat);
520         Mat4MulMat4(pmat, vmat, rv3d->winmat);
521         Mat4CpyMat4(vmat, ob->obmat);
522 }
523
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])
526 {
527         RegionView3D *rv3d= ar->regiondata;
528         float fx, fy, vec4[4];
529         
530         adr[0]= IS_CLIPPED;
531         
532         /* clipplanes in eye space */
533         if(rv3d->rflag & RV3D_CLIPPING) {
534                 VECCOPY(vec4, vec);
535                 Mat4MulVecfl(wmat, vec4);
536                 if(view3d_test_clipping(rv3d, vec4))
537                         return;
538         }
539         
540         VECCOPY(vec4, vec);
541         vec4[3]= 1.0;
542         
543         Mat4MulVec4fl(projmat, vec4);
544         
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]);
548                 
549                 if( fx>0 && fx<ar->winx) {
550                         
551                         fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]);
552                         
553                         if(fy>0.0 && fy< (float)ar->winy) {
554                                 adr[0]= (short)floor(fx); 
555                                 adr[1]= (short)floor(fy);
556                         }
557                 }
558         }
559 }
560
561 void view3d_project_short_noclip(ARegion *ar, float *vec, short *adr, float mat[4][4])
562 {
563         float fx, fy, vec4[4];
564         
565         adr[0]= IS_CLIPPED;
566         
567         VECCOPY(vec4, vec);
568         vec4[3]= 1.0;
569         
570         Mat4MulVec4fl(mat, vec4);
571         
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]);
574                 
575                 if( fx>-32700 && fx<32700) {
576                         
577                         fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]);
578                         
579                         if(fy>-32700.0 && fy<32700.0) {
580                                 adr[0]= (short)floor(fx); 
581                                 adr[1]= (short)floor(fy);
582                         }
583                 }
584         }
585 }
586
587 void view3d_project_float(ARegion *ar, float *vec, float *adr, float mat[4][4])
588 {
589         float vec4[4];
590         
591         adr[0]= IS_CLIPPED;
592         VECCOPY(vec4, vec);
593         vec4[3]= 1.0;
594         
595         Mat4MulVec4fl(mat, vec4);
596         
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];
600         } else {
601                 adr[0] = adr[1] = 0.0f;
602         }
603 }
604
605 int boundbox_clip(RegionView3D *rv3d, float obmat[][4], BoundBox *bb)
606 {
607         /* return 1: draw */
608         
609         float mat[4][4];
610         float vec[4], min, max;
611         int a, flag= -1, fl;
612         
613         if(bb==NULL) return 1;
614         if(bb->flag & OB_BB_DISABLED) return 1;
615         
616         Mat4MulMat4(mat, obmat, rv3d->persmat);
617         
618         for(a=0; a<8; a++) {
619                 VECCOPY(vec, bb->vec[a]);
620                 vec[3]= 1.0;
621                 Mat4MulVec4fl(mat, vec);
622                 max= vec[3];
623                 min= -vec[3];
624                 
625                 fl= 0;
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;
632                 
633                 flag &= fl;
634                 if(flag==0) return 1;
635         }
636         
637         return 0;
638 }
639
640 void project_short(ARegion *ar, float *vec, short *adr) /* clips */
641 {
642         RegionView3D *rv3d= ar->regiondata;
643         float fx, fy, vec4[4];
644         
645         adr[0]= IS_CLIPPED;
646         
647         if(rv3d->rflag & RV3D_CLIPPING) {
648                 if(view3d_test_clipping(rv3d, vec))
649                         return;
650         }
651         
652         VECCOPY(vec4, vec);
653         vec4[3]= 1.0;
654         Mat4MulVec4fl(rv3d->persmat, vec4);
655         
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]);
658                 
659                 if( fx>0 && fx<ar->winx) {
660                         
661                         fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]);
662                         
663                         if(fy>0.0 && fy< (float)ar->winy) {
664                                 adr[0]= (short)floor(fx); 
665                                 adr[1]= (short)floor(fy);
666                         }
667                 }
668         }
669 }
670
671 void project_int(ARegion *ar, float *vec, int *adr)
672 {
673         RegionView3D *rv3d= ar->regiondata;
674         float fx, fy, vec4[4];
675         
676         adr[0]= (int)2140000000.0f;
677         VECCOPY(vec4, vec);
678         vec4[3]= 1.0;
679         
680         Mat4MulVec4fl(rv3d->persmat, vec4);
681         
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]);
684                 
685                 if( fx>-2140000000.0f && fx<2140000000.0f) {
686                         fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]);
687                         
688                         if(fy>-2140000000.0f && fy<2140000000.0f) {
689                                 adr[0]= (int)floor(fx); 
690                                 adr[1]= (int)floor(fy);
691                         }
692                 }
693         }
694 }
695
696 void project_int_noclip(ARegion *ar, float *vec, int *adr)
697 {
698         RegionView3D *rv3d= ar->regiondata;
699         float fx, fy, vec4[4];
700         
701         VECCOPY(vec4, vec);
702         vec4[3]= 1.0;
703         
704         Mat4MulVec4fl(rv3d->persmat, vec4);
705         
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]);
709                 
710                 adr[0] = (int)floor(fx); 
711                 adr[1] = (int)floor(fy);
712         }
713         else
714         {
715                 adr[0] = ar->winx / 2;
716                 adr[1] = ar->winy / 2;
717         }
718 }
719
720 void project_short_noclip(ARegion *ar, float *vec, short *adr)
721 {
722         RegionView3D *rv3d= ar->regiondata;
723         float fx, fy, vec4[4];
724         
725         adr[0]= IS_CLIPPED;
726         VECCOPY(vec4, vec);
727         vec4[3]= 1.0;
728         
729         Mat4MulVec4fl(rv3d->persmat, vec4);
730         
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]);
733                 
734                 if( fx>-32700 && fx<32700) {
735                         
736                         fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]);
737                         
738                         if(fy>-32700.0 && fy<32700.0) {
739                                 adr[0]= (short)floor(fx); 
740                                 adr[1]= (short)floor(fy);
741                         }
742                 }
743         }
744 }
745
746 void project_float(ARegion *ar, float *vec, float *adr)
747 {
748         RegionView3D *rv3d= ar->regiondata;
749         float vec4[4];
750         
751         adr[0]= IS_CLIPPED;
752         VECCOPY(vec4, vec);
753         vec4[3]= 1.0;
754         
755         Mat4MulVec4fl(rv3d->persmat, vec4);
756         
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];
760         }
761 }
762
763 void project_float_noclip(ARegion *ar, float *vec, float *adr)
764 {
765         RegionView3D *rv3d= ar->regiondata;
766         float vec4[4];
767         
768         VECCOPY(vec4, vec);
769         vec4[3]= 1.0;
770         
771         Mat4MulVec4fl(rv3d->persmat, vec4);
772         
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];
776         }
777         else
778         {
779                 adr[0] = ar->winx / 2.0f;
780                 adr[1] = ar->winy / 2.0f;
781         }
782 }
783
784
785
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)
788 {
789         Camera *cam=NULL;
790         float lens, fac, x1, y1, x2, y2;
791         float winx= (float)winxi, winy= (float)winyi;
792         int orth= 0;
793         
794         lens= v3d->lens;        
795         
796         *clipsta= v3d->near;
797         *clipend= v3d->far;
798         
799         if(rv3d->persp==V3D_CAMOB) {
800                 if(v3d->camera) {
801                         if(v3d->camera->type==OB_LAMP ) {
802                                 Lamp *la;
803                                 
804                                 la= v3d->camera->data;
805                                 fac= cos( M_PI*la->spotsize/360.0);
806                                 
807                                 x1= saacos(fac);
808                                 lens= 16.0*fac/sin(x1);
809                                 
810                                 *clipsta= la->clipsta;
811                                 *clipend= la->clipend;
812                         }
813                         else if(v3d->camera->type==OB_CAMERA) {
814                                 cam= v3d->camera->data;
815                                 lens= cam->lens;
816                                 *clipsta= cam->clipsta;
817                                 *clipend= cam->clipend;
818                         }
819                 }
820         }
821         
822         if(rv3d->persp==V3D_ORTHO) {
823                 if(winx>winy) x1= -rv3d->dist;
824                 else x1= -winx*rv3d->dist/winy;
825                 x2= -x1;
826                 
827                 if(winx>winy) y1= -winy*rv3d->dist/winx;
828                 else y1= -rv3d->dist;
829                 y2= -y1;
830                 
831                 *clipend *= 0.5;        // otherwise too extreme low zbuffer quality
832                 *clipsta= - *clipend;
833                 orth= 1;
834         }
835         else {
836                 /* fac for zoom, also used for camdx */
837                 if(rv3d->persp==V3D_CAMOB) {
838                         fac= (1.41421+( (float)rv3d->camzoom )/50.0);
839                         fac*= fac;
840                 }
841                 else fac= 2.0;
842                 
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;
847                         
848                         if(winx>winy) x1= -dfac;
849                         else x1= -winx*dfac/winy;
850                         x2= -x1;
851                         
852                         if(winx>winy) y1= -winy*dfac/winx;
853                         else y1= -dfac;
854                         y2= -y1;
855                         orth= 1;
856                 }
857                 else {
858                         float dfac;
859                         
860                         if(winx>winy) dfac= 64.0/(fac*winx*lens);
861                         else dfac= 64.0/(fac*winy*lens);
862                         
863                         x1= - *clipsta * winx*dfac;
864                         x2= -x1;
865                         y1= - *clipsta * winy*dfac;
866                         y2= -y1;
867                         orth= 0;
868                 }
869                 /* cam view offset */
870                 if(cam) {
871                         float dx= 0.5*fac*rv3d->camdx*(x2-x1);
872                         float dy= 0.5*fac*rv3d->camdy*(y2-y1);
873                         x1+= dx;
874                         x2+= dx;
875                         y1+= dy;
876                         y2+= dy;
877                 }
878         }
879         
880         if(pixsize) {
881                 float viewfac;
882                 
883                 if(orth) {
884                         viewfac= (winx >= winy)? winx: winy;
885                         *pixsize= 1.0f/viewfac;
886                 }
887                 else {
888                         viewfac= (((winx >= winy)? winx: winy)*lens)/32.0;
889                         *pixsize= *clipsta/viewfac;
890                 }
891         }
892         
893         viewplane->xmin= x1;
894         viewplane->ymin= y1;
895         viewplane->xmax= x2;
896         viewplane->ymax= y2;
897         
898         return orth;
899 }
900
901
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 */
904 {
905         RegionView3D *rv3d= ar->regiondata;
906         rctf viewplane;
907         float clipsta, clipend, x1, y1, x2, y2;
908         int orth;
909         
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);
912         x1= viewplane.xmin;
913         y1= viewplane.ymin;
914         x2= viewplane.xmax;
915         y2= viewplane.ymax;
916         
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);
926                 
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);
929                 
930         }
931         else {
932                 if(orth) wmOrtho(x1, x2, y1, y2, clipsta, clipend);
933                 else wmFrustum(x1, x2, y1, y2, clipsta, clipend);
934         }
935
936         /* not sure what this was for? (ton) */
937         glMatrixMode(GL_PROJECTION);
938         wmGetMatrix(rv3d->winmat);
939         glMatrixMode(GL_MODELVIEW);
940 }
941
942
943 static void obmat_to_viewmat(View3D *v3d, RegionView3D *rv3d, Object *ob, short smooth)
944 {
945         float bmat[4][4];
946         float tmat[3][3];
947         
948         rv3d->view= 0; /* dont show the grid */
949         
950         Mat4CpyMat4(bmat, ob->obmat);
951         Mat4Ortho(bmat);
952         Mat4Invert(rv3d->viewmat, bmat);
953         
954         /* view quat calculation, needed for add object */
955         Mat3CpyMat4(tmat, rv3d->viewmat);
956         if (smooth) {
957                 float new_quat[4];
958                 if (rv3d->persp==V3D_CAMOB && v3d->camera) {
959                         /* were from a camera view */
960                         
961                         float orig_ofs[3];
962                         float orig_dist= rv3d->dist;
963                         float orig_lens= v3d->lens;
964                         VECCOPY(orig_ofs, rv3d->ofs);
965                         
966                         /* Switch from camera view */
967                         Mat3ToQuat(tmat, new_quat);
968                         
969                         rv3d->persp=V3D_PERSP;
970                         rv3d->dist= 0.0;
971                         
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
974                         
975                         rv3d->persp=V3D_CAMOB; /* just to be polite, not needed */
976                         
977                 } else {
978                         Mat3ToQuat(tmat, new_quat);
979                         smooth_view(NULL, NULL, NULL, NULL, new_quat, NULL, NULL); // XXX
980                 }
981         } else {
982                 Mat3ToQuat(tmat, rv3d->viewquat);
983         }
984 }
985
986 /* dont set windows active in in here, is used by renderwin too */
987 void setviewmatrixview3d(Scene *scene, View3D *v3d, RegionView3D *rv3d)
988 {
989         if(rv3d->persp==V3D_CAMOB) {        /* obs/camera */
990                 if(v3d->camera) {
991                         where_is_object(scene, v3d->camera);    
992                         obmat_to_viewmat(v3d, rv3d, v3d->camera, 0);
993                 }
994                 else {
995                         QuatToMat4(rv3d->viewquat, rv3d->viewmat);
996                         rv3d->viewmat[3][2]-= rv3d->dist;
997                 }
998         }
999         else {
1000                 
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;
1005                         float vec[3];
1006                         
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);
1010                                 if(pchan) {
1011                                         VECCOPY(vec, pchan->pose_mat[3]);
1012                                         Mat4MulVecfl(ob->obmat, vec);
1013                                 }
1014                         }
1015                         i_translate(-vec[0], -vec[1], -vec[2], rv3d->viewmat);
1016                 }
1017                 else i_translate(rv3d->ofs[0], rv3d->ofs[1], rv3d->ofs[2], rv3d->viewmat);
1018         }
1019 }
1020
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
1025 */
1026 short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int bufsize, rcti *input)
1027 {
1028         Scene *scene= vc->scene;
1029         View3D *v3d= vc->v3d;
1030         ARegion *ar= vc->ar;
1031         rctf rect;
1032         short code, hits;
1033         
1034         G.f |= G_PICKSEL;
1035         
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;
1042         }
1043         else {
1044                 rect.xmin= input->xmin;
1045                 rect.xmax= input->xmax;
1046                 rect.ymin= input->ymin;
1047                 rect.ymax= input->ymax;
1048         }
1049         
1050         setwinmatrixview3d(ar, v3d, &rect);
1051         Mat4MulMat4(vc->rv3d->persmat, vc->rv3d->viewmat, vc->rv3d->winmat);
1052         
1053         if(v3d->drawtype > OB_WIRE) {
1054                 v3d->zbuf= TRUE;
1055                 glEnable(GL_DEPTH_TEST);
1056         }
1057         
1058         if(vc->rv3d->rflag & RV3D_CLIPPING)
1059                 view3d_set_clipping(vc->rv3d);
1060         
1061         glSelectBuffer( bufsize, (GLuint *)buffer);
1062         glRenderMode(GL_SELECT);
1063         glInitNames();  /* these two calls whatfor? It doesnt work otherwise */
1064         glPushName(-1);
1065         code= 1;
1066         
1067         if(vc->obedit && vc->obedit->type==OB_MBALL) {
1068                 draw_object(scene, ar, v3d, BASACT, DRAW_PICKING|DRAW_CONSTCOLOR);
1069         }
1070         else if ((vc->obedit && vc->obedit->type==OB_ARMATURE)) {
1071                 draw_object(scene, ar, v3d, BASACT, DRAW_PICKING|DRAW_CONSTCOLOR);
1072         }
1073         else {
1074                 Base *base;
1075                 
1076                 v3d->xray= TRUE;        // otherwise it postpones drawing
1077                 for(base= scene->base.first; base; base= base->next) {
1078                         if(base->lay & v3d->lay) {
1079                                 
1080                                 if (base->object->restrictflag & OB_RESTRICT_SELECT)
1081                                         base->selcol= 0;
1082                                 else {
1083                                         base->selcol= code;
1084                                         glLoadName(code);
1085                                         draw_object(scene, ar, v3d, base, DRAW_PICKING|DRAW_CONSTCOLOR);
1086                                         
1087                                         /* we draw group-duplicators for selection too */
1088                                         if((base->object->transflag & OB_DUPLI) && base->object->dup_group) {
1089                                                 ListBase *lb;
1090                                                 DupliObject *dob;
1091                                                 Base tbase;
1092                                                 
1093                                                 tbase.flag= OB_FROMDUPLI;
1094                                                 lb= object_duplilist(scene, base->object);
1095                                                 
1096                                                 for(dob= lb->first; dob; dob= dob->next) {
1097                                                         tbase.object= dob->ob;
1098                                                         Mat4CpyMat4(dob->ob->obmat, dob->mat);
1099                                                         
1100                                                         draw_object(scene, ar, v3d, &tbase, DRAW_PICKING|DRAW_CONSTCOLOR);
1101                                                         
1102                                                         Mat4CpyMat4(dob->ob->obmat, dob->omat);
1103                                                 }
1104                                                 free_object_duplilist(lb);
1105                                         }
1106                                         code++;
1107                                 }                               
1108                         }
1109                 }
1110                 v3d->xray= FALSE;       // restore
1111         }
1112         
1113         glPopName();    /* see above (pushname) */
1114         hits= glRenderMode(GL_RENDER);
1115         
1116         G.f &= ~G_PICKSEL;
1117         setwinmatrixview3d(ar, v3d, NULL);
1118         Mat4MulMat4(vc->rv3d->persmat, vc->rv3d->viewmat, vc->rv3d->winmat);
1119         
1120         if(v3d->drawtype > OB_WIRE) {
1121                 v3d->zbuf= 0;
1122                 glDisable(GL_DEPTH_TEST);
1123         }
1124 // XXX  persp(PERSP_WIN);
1125         
1126         if(vc->rv3d->rflag & RV3D_CLIPPING)
1127                 view3d_clr_clipping();
1128         
1129         if(hits<0) printf("Too many objects in select buffer\n");       // XXX make error message
1130         
1131         return hits;
1132 }
1133
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)
1136 {
1137         unsigned int lay;
1138         ScrArea *sa;
1139         bScreen *sc;
1140         
1141         lay= 0;
1142         
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;
1151                                         lay |= v3d->lay;
1152                                 }
1153                         }
1154                 }
1155         }
1156         
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;
1165         
1166         return 0;
1167 }
1168
1169
1170 void initlocalview(Scene *scene, ARegion *ar, View3D *v3d)
1171 {
1172         RegionView3D *rv3d= ar->regiondata;
1173         Base *base;
1174         float size = 0.0, min[3], max[3], afm[3];
1175         unsigned int locallay;
1176         int ok=0;
1177
1178         if(v3d->localvd) return;
1179
1180         INIT_MINMAX(min, max);
1181
1182         locallay= free_localbit();
1183
1184         if(locallay==0) {
1185                 printf("Sorry,  no more than 8 localviews\n");  // XXX error 
1186                 ok= 0;
1187         }
1188         else {
1189                 if(scene->obedit) {
1190                         minmax_object(scene->obedit, min, max);
1191                         
1192                         ok= 1;
1193                 
1194                         BASACT->lay |= locallay;
1195                         scene->obedit->lay= BASACT->lay;
1196                 }
1197                 else {
1198                         base= FIRSTBASE;
1199                         while(base) {
1200                                 if(TESTBASE(v3d, base))  {
1201                                         minmax_object(base->object, min, max);
1202                                         base->lay |= locallay;
1203                                         base->object->lay= base->lay;
1204                                         ok= 1;
1205                                 }
1206                                 base= base->next;
1207                         }
1208                 }
1209                 
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;
1215         }
1216         
1217         if(ok) {
1218                 v3d->localvd= MEM_mallocN(sizeof(View3D), "localview");
1219                 memcpy(v3d->localvd, v3d, sizeof(View3D));
1220
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;
1224
1225                 rv3d->dist= size;
1226
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;
1231                         rv3d->dist*= size;
1232                 }
1233                 
1234                 if (rv3d->persp==V3D_CAMOB) rv3d->persp= V3D_PERSP;
1235                 if (v3d->near> 0.1) v3d->near= 0.1;
1236                 
1237                 v3d->cursor[0]= -rv3d->ofs[0];
1238                 v3d->cursor[1]= -rv3d->ofs[1];
1239                 v3d->cursor[2]= -rv3d->ofs[2];
1240
1241                 v3d->lay= locallay;
1242                 
1243 // XXX          countall();
1244 // XXX          scrarea_queue_winredraw(curarea);
1245         }
1246         else {
1247                 /* clear flags */ 
1248                 base= FIRSTBASE;
1249                 while(base) {
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;
1255                         }
1256                         base= base->next;
1257                 }
1258 // XXX          scrarea_queue_headredraw(curarea);
1259                 
1260                 v3d->localview= 0;
1261         }
1262 // XXX  BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
1263 }
1264
1265 void restore_localviewdata(View3D *vd)
1266 {
1267         if(vd->localvd==0) return;
1268         
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;
1276         
1277 }
1278
1279 void endlocalview(Scene *scene, ScrArea *sa)
1280 {
1281         View3D *v3d;
1282         struct Base *base;
1283         unsigned int locallay;
1284         
1285         if(sa->spacetype!=SPACE_VIEW3D) return;
1286         v3d= sa->spacedata.first;
1287         
1288         if(v3d->localvd) {
1289                 
1290                 locallay= v3d->lay & 0xFF000000;
1291                 
1292                 restore_localviewdata(v3d);
1293                 
1294                 MEM_freeN(v3d->localvd);
1295                 v3d->localvd= 0;
1296                 v3d->localview= 0;
1297
1298                 /* for when in other window the layers have changed */
1299                 if(v3d->scenelock) v3d->lay= scene->lay;
1300                 
1301                 base= FIRSTBASE;
1302                 while(base) {
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;
1309                                 }
1310                                 base->object->lay= base->lay;
1311                         }
1312                         base= base->next;
1313                 }
1314
1315 // XXX          countall();
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);
1319         } 
1320 }
1321
1322 void view3d_align_axis_to_vector(View3D *v3d, RegionView3D *rv3d, int axisidx, float vec[3])
1323 {
1324         float alignaxis[3] = {0.0, 0.0, 0.0};
1325         float norm[3], axis[3], angle, new_quat[4];
1326         
1327         if(axisidx > 0) alignaxis[axisidx-1]= 1.0;
1328         else alignaxis[-axisidx-1]= -1.0;
1329         
1330         VECCOPY(norm, vec);
1331         Normalize(norm);
1332         
1333         angle= (float)acos(Inpf(alignaxis, norm));
1334         Crossf(axis, alignaxis, norm);
1335         VecRotToQuat(axis, -angle, new_quat);
1336         
1337         rv3d->view= 0;
1338         
1339         if (rv3d->persp==V3D_CAMOB && v3d->camera) {
1340                 /* switch out of camera view */
1341                 float orig_ofs[3];
1342                 float orig_dist= rv3d->dist;
1343                 float orig_lens= v3d->lens;
1344                 
1345                 VECCOPY(orig_ofs, rv3d->ofs);
1346                 rv3d->persp= V3D_PERSP;
1347                 rv3d->dist= 0.0;
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
1350         } else {
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
1353         }
1354 }
1355