Merge from 2.5 r21037 through r21112
[blender.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 #include "ED_armature.h"
74
75 #include "UI_interface.h"
76 #include "UI_resources.h"
77 #include "UI_view2d.h"
78
79 #include "GPU_draw.h"
80
81 #include "PIL_time.h" /* smoothview */
82
83 #include "view3d_intern.h"      // own include
84
85 /* use this call when executing an operator,
86    event system doesn't set for each event the
87    opengl drawing context */
88 void view3d_operator_needs_opengl(const bContext *C)
89 {
90         ARegion *ar= CTX_wm_region(C);
91
92         /* for debugging purpose, context should always be OK */
93         if(ar->regiontype!=RGN_TYPE_WINDOW)
94                 printf("view3d_operator_needs_opengl error, wrong region\n");
95         else {
96                 RegionView3D *rv3d= ar->regiondata;
97                 
98                 wmSubWindowSet(CTX_wm_window(C), ar->swinid);
99                 glMatrixMode(GL_PROJECTION);
100                 wmLoadMatrix(rv3d->winmat);
101                 glMatrixMode(GL_MODELVIEW);
102                 wmLoadMatrix(rv3d->viewmat);
103         }
104 }
105
106 float *give_cursor(Scene *scene, View3D *v3d)
107 {
108         if(v3d && v3d->localview) return v3d->cursor;
109         else return scene->cursor;
110 }
111
112
113 /* Gets the lens and clipping values from a camera of lamp type object */
114 static void object_lens_clip_settings(Object *ob, float *lens, float *clipsta, float *clipend)
115 {       
116         if (!ob) return;
117         
118         if(ob->type==OB_LAMP ) {
119                 Lamp *la = ob->data;
120                 if (lens) {
121                         float x1, fac;
122                         fac= cos( M_PI*la->spotsize/360.0);
123                         x1= saacos(fac);
124                         *lens= 16.0*fac/sin(x1);
125                 }
126                 if (clipsta)    *clipsta= la->clipsta;
127                 if (clipend)    *clipend= la->clipend;
128         }
129         else if(ob->type==OB_CAMERA) {
130                 Camera *cam= ob->data;
131                 if (lens)               *lens= cam->lens;
132                 if (clipsta)    *clipsta= cam->clipsta;
133                 if (clipend)    *clipend= cam->clipend;
134         }
135         else {
136                 if (lens)               *lens= 35.0f;
137         }
138 }
139
140
141 /* Gets the view trasnformation from a camera
142 * currently dosnt take camzoom into account
143
144 * The dist is not modified for this function, if NULL its assimed zero
145 * */
146 static void view_settings_from_ob(Object *ob, float *ofs, float *quat, float *dist, float *lens)
147 {       
148         float bmat[4][4];
149         float imat[4][4];
150         float tmat[3][3];
151         
152         if (!ob) return;
153         
154         /* Offset */
155         if (ofs) {
156                 VECCOPY(ofs, ob->obmat[3]);
157                 VecMulf(ofs, -1.0f); /*flip the vector*/
158         }
159         
160         /* Quat */
161         if (quat) {
162                 Mat4CpyMat4(bmat, ob->obmat);
163                 Mat4Ortho(bmat);
164                 Mat4Invert(imat, bmat);
165                 Mat3CpyMat4(tmat, imat);
166                 Mat3ToQuat(tmat, quat);
167         }
168         
169         if (dist) {
170                 float vec[3];
171                 Mat3CpyMat4(tmat, ob->obmat);
172                 
173                 vec[0]= vec[1] = 0.0;
174                 vec[2]= -(*dist);
175                 Mat3MulVecfl(tmat, vec);
176                 VecSubf(ofs, ofs, vec);
177         }
178         
179         /* Lens */
180         if (lens)
181                 object_lens_clip_settings(ob, lens, NULL, NULL);
182 }
183
184
185 /* ****************** smooth view operator ****************** */
186
187 struct SmoothViewStore {
188         float orig_dist, new_dist;
189         float orig_lens, new_lens;
190         float orig_quat[4], new_quat[4];
191         float orig_ofs[3], new_ofs[3];
192         
193         int to_camera, orig_view;
194         
195         double time_allowed;
196 };
197
198 /* will start timer if appropriate */
199 /* the arguments are the desired situation */
200 void smooth_view(bContext *C, Object *oldcamera, Object *camera, float *ofs, float *quat, float *dist, float *lens)
201 {
202         View3D *v3d = CTX_wm_view3d(C);
203         RegionView3D *rv3d= CTX_wm_region_view3d(C);
204         struct SmoothViewStore sms;
205         
206         /* initialize sms */
207         memset(&sms,0,sizeof(struct SmoothViewStore));
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_camera_to_view";
414         
415         /* api callbacks */
416         ot->exec= view3d_setcameratoview_exec;  
417         ot->poll= ED_operator_view3d_active;
418         
419         /* flags */
420         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
421 }
422
423 /* ********************************** */
424
425 /* create intersection coordinates in view Z direction at mouse coordinates */
426 void viewline(ARegion *ar, View3D *v3d, short mval[2], float ray_start[3], float ray_end[3])
427 {
428         RegionView3D *rv3d= ar->regiondata;
429         float vec[4];
430         
431         if(rv3d->persp != V3D_ORTHO){
432                 vec[0]= 2.0f * mval[0] / ar->winx - 1;
433                 vec[1]= 2.0f * mval[1] / ar->winy - 1;
434                 vec[2]= -1.0f;
435                 vec[3]= 1.0f;
436                 
437                 Mat4MulVec4fl(rv3d->persinv, vec);
438                 VecMulf(vec, 1.0f / vec[3]);
439                 
440                 VECCOPY(ray_start, rv3d->viewinv[3]);
441                 VECSUB(vec, vec, ray_start);
442                 Normalize(vec);
443                 
444                 VECADDFAC(ray_start, rv3d->viewinv[3], vec, v3d->near);
445                 VECADDFAC(ray_end, rv3d->viewinv[3], vec, v3d->far);
446         }
447         else {
448                 vec[0] = 2.0f * mval[0] / ar->winx - 1;
449                 vec[1] = 2.0f * mval[1] / ar->winy - 1;
450                 vec[2] = 0.0f;
451                 vec[3] = 1.0f;
452                 
453                 Mat4MulVec4fl(rv3d->persinv, vec);
454                 
455                 VECADDFAC(ray_start, vec, rv3d->viewinv[2],  1000.0f);
456                 VECADDFAC(ray_end, vec, rv3d->viewinv[2], -1000.0f);
457         }
458 }
459
460 /* create intersection ray in view Z direction at mouse coordinates */
461 void viewray(ARegion *ar, View3D *v3d, short mval[2], float ray_start[3], float ray_normal[3])
462 {
463         float ray_end[3];
464         
465         viewline(ar, v3d, mval, ray_start, ray_end);
466         VecSubf(ray_normal, ray_end, ray_start);
467         Normalize(ray_normal);
468 }
469
470
471 void initgrabz(RegionView3D *rv3d, float x, float y, float z)
472 {
473         if(rv3d==NULL) return;
474         rv3d->zfac= rv3d->persmat[0][3]*x+ rv3d->persmat[1][3]*y+ rv3d->persmat[2][3]*z+ rv3d->persmat[3][3];
475         
476         /* if x,y,z is exactly the viewport offset, zfac is 0 and we don't want that 
477                 * (accounting for near zero values)
478                 * */
479         if (rv3d->zfac < 1.e-6f && rv3d->zfac > -1.e-6f) rv3d->zfac = 1.0f;
480         
481         /* Negative zfac means x, y, z was behind the camera (in perspective).
482                 * This gives flipped directions, so revert back to ok default case.
483         */
484         if (rv3d->zfac < 0.0f) rv3d->zfac = 1.0f;
485 }
486
487 /* always call initgrabz */
488 void window_to_3d(ARegion *ar, float *vec, short mx, short my)
489 {
490         RegionView3D *rv3d= ar->regiondata;
491         
492         float dx= ((float)(mx-(ar->winx/2)))*rv3d->zfac/(ar->winx/2);
493         float dy= ((float)(my-(ar->winy/2)))*rv3d->zfac/(ar->winy/2);
494         
495         float fz= rv3d->persmat[0][3]*vec[0]+ rv3d->persmat[1][3]*vec[1]+ rv3d->persmat[2][3]*vec[2]+ rv3d->persmat[3][3];
496         fz= fz/rv3d->zfac;
497         
498         vec[0]= (rv3d->persinv[0][0]*dx + rv3d->persinv[1][0]*dy+ rv3d->persinv[2][0]*fz)-rv3d->ofs[0];
499         vec[1]= (rv3d->persinv[0][1]*dx + rv3d->persinv[1][1]*dy+ rv3d->persinv[2][1]*fz)-rv3d->ofs[1];
500         vec[2]= (rv3d->persinv[0][2]*dx + rv3d->persinv[1][2]*dy+ rv3d->persinv[2][2]*fz)-rv3d->ofs[2];
501         
502 }
503
504 /* always call initgrabz */
505 /* only to detect delta motion */
506 void window_to_3d_delta(ARegion *ar, float *vec, short mx, short my)
507 {
508         RegionView3D *rv3d= ar->regiondata;
509         float dx, dy;
510         
511         dx= 2.0f*mx*rv3d->zfac/ar->winx;
512         dy= 2.0f*my*rv3d->zfac/ar->winy;
513         
514         vec[0]= (rv3d->persinv[0][0]*dx + rv3d->persinv[1][0]*dy);
515         vec[1]= (rv3d->persinv[0][1]*dx + rv3d->persinv[1][1]*dy);
516         vec[2]= (rv3d->persinv[0][2]*dx + rv3d->persinv[1][2]*dy);
517 }
518
519 float read_cached_depth(ViewContext *vc, int x, int y)
520 {
521         ViewDepths *vd = vc->rv3d->depths;
522                 
523         x -= vc->ar->winrct.xmin;
524         y -= vc->ar->winrct.ymin;
525
526         if(vd && vd->depths && x > 0 && y > 0 && x < vd->w && y < vd->h)
527                 return vd->depths[y * vd->w + x];
528         else
529                 return 1;
530 }
531
532 void request_depth_update(RegionView3D *rv3d)
533 {
534         if(rv3d->depths)
535                 rv3d->depths->damaged= 1;
536 }
537
538 void view3d_get_object_project_mat(RegionView3D *rv3d, Object *ob, float pmat[4][4])
539 {
540         float vmat[4][4];
541         
542         Mat4MulMat4(vmat, ob->obmat, rv3d->viewmat);
543         Mat4MulMat4(pmat, vmat, rv3d->winmat);
544 }
545
546
547 /* use above call to get projecting mat */
548 void view3d_project_float(ARegion *ar, float *vec, float *adr, float mat[4][4])
549 {
550         float vec4[4];
551         
552         adr[0]= IS_CLIPPED;
553         VECCOPY(vec4, vec);
554         vec4[3]= 1.0;
555         
556         Mat4MulVec4fl(mat, vec4);
557         
558         if( vec4[3]>FLT_EPSILON ) {
559                 adr[0] = (float)(ar->winx/2.0f)+(ar->winx/2.0f)*vec4[0]/vec4[3];        
560                 adr[1] = (float)(ar->winy/2.0f)+(ar->winy/2.0f)*vec4[1]/vec4[3];
561         } else {
562                 adr[0] = adr[1] = 0.0f;
563         }
564 }
565
566 int boundbox_clip(RegionView3D *rv3d, float obmat[][4], BoundBox *bb)
567 {
568         /* return 1: draw */
569         
570         float mat[4][4];
571         float vec[4], min, max;
572         int a, flag= -1, fl;
573         
574         if(bb==NULL) return 1;
575         if(bb->flag & OB_BB_DISABLED) return 1;
576         
577         Mat4MulMat4(mat, obmat, rv3d->persmat);
578         
579         for(a=0; a<8; a++) {
580                 VECCOPY(vec, bb->vec[a]);
581                 vec[3]= 1.0;
582                 Mat4MulVec4fl(mat, vec);
583                 max= vec[3];
584                 min= -vec[3];
585                 
586                 fl= 0;
587                 if(vec[0] < min) fl+= 1;
588                 if(vec[0] > max) fl+= 2;
589                 if(vec[1] < min) fl+= 4;
590                 if(vec[1] > max) fl+= 8;
591                 if(vec[2] < min) fl+= 16;
592                 if(vec[2] > max) fl+= 32;
593                 
594                 flag &= fl;
595                 if(flag==0) return 1;
596         }
597         
598         return 0;
599 }
600
601 void project_short(ARegion *ar, float *vec, short *adr) /* clips */
602 {
603         RegionView3D *rv3d= ar->regiondata;
604         float fx, fy, vec4[4];
605         
606         adr[0]= IS_CLIPPED;
607         
608         if(rv3d->rflag & RV3D_CLIPPING) {
609                 if(view3d_test_clipping(rv3d, vec))
610                         return;
611         }
612         
613         VECCOPY(vec4, vec);
614         vec4[3]= 1.0;
615         Mat4MulVec4fl(rv3d->persmat, vec4);
616         
617         if( vec4[3]>BL_NEAR_CLIP ) {    /* 0.001 is the NEAR clipping cutoff for picking */
618                 fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]);
619                 
620                 if( fx>0 && fx<ar->winx) {
621                         
622                         fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]);
623                         
624                         if(fy>0.0 && fy< (float)ar->winy) {
625                                 adr[0]= (short)floor(fx); 
626                                 adr[1]= (short)floor(fy);
627                         }
628                 }
629         }
630 }
631
632 void project_int(ARegion *ar, float *vec, int *adr)
633 {
634         RegionView3D *rv3d= ar->regiondata;
635         float fx, fy, vec4[4];
636         
637         adr[0]= (int)2140000000.0f;
638         VECCOPY(vec4, vec);
639         vec4[3]= 1.0;
640         
641         Mat4MulVec4fl(rv3d->persmat, vec4);
642         
643         if( vec4[3]>BL_NEAR_CLIP ) {    /* 0.001 is the NEAR clipping cutoff for picking */
644                 fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]);
645                 
646                 if( fx>-2140000000.0f && fx<2140000000.0f) {
647                         fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]);
648                         
649                         if(fy>-2140000000.0f && fy<2140000000.0f) {
650                                 adr[0]= (int)floor(fx); 
651                                 adr[1]= (int)floor(fy);
652                         }
653                 }
654         }
655 }
656
657 void project_int_noclip(ARegion *ar, float *vec, int *adr)
658 {
659         RegionView3D *rv3d= ar->regiondata;
660         float fx, fy, vec4[4];
661         
662         VECCOPY(vec4, vec);
663         vec4[3]= 1.0;
664         
665         Mat4MulVec4fl(rv3d->persmat, vec4);
666         
667         if( fabs(vec4[3]) > BL_NEAR_CLIP ) {
668                 fx = (ar->winx/2)*(1 + vec4[0]/vec4[3]);
669                 fy = (ar->winy/2)*(1 + vec4[1]/vec4[3]);
670                 
671                 adr[0] = (int)floor(fx); 
672                 adr[1] = (int)floor(fy);
673         }
674         else
675         {
676                 adr[0] = ar->winx / 2;
677                 adr[1] = ar->winy / 2;
678         }
679 }
680
681 void project_short_noclip(ARegion *ar, float *vec, short *adr)
682 {
683         RegionView3D *rv3d= ar->regiondata;
684         float fx, fy, vec4[4];
685         
686         adr[0]= IS_CLIPPED;
687         VECCOPY(vec4, vec);
688         vec4[3]= 1.0;
689         
690         Mat4MulVec4fl(rv3d->persmat, vec4);
691         
692         if( vec4[3]>BL_NEAR_CLIP ) {    /* 0.001 is the NEAR clipping cutoff for picking */
693                 fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]);
694                 
695                 if( fx>-32700 && fx<32700) {
696                         
697                         fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]);
698                         
699                         if(fy>-32700.0 && fy<32700.0) {
700                                 adr[0]= (short)floor(fx); 
701                                 adr[1]= (short)floor(fy);
702                         }
703                 }
704         }
705 }
706
707 void project_float(ARegion *ar, float *vec, float *adr)
708 {
709         RegionView3D *rv3d= ar->regiondata;
710         float vec4[4];
711         
712         adr[0]= IS_CLIPPED;
713         VECCOPY(vec4, vec);
714         vec4[3]= 1.0;
715         
716         Mat4MulVec4fl(rv3d->persmat, vec4);
717         
718         if( vec4[3]>BL_NEAR_CLIP ) {
719                 adr[0] = (float)(ar->winx/2.0)+(ar->winx/2.0)*vec4[0]/vec4[3];  
720                 adr[1] = (float)(ar->winy/2.0)+(ar->winy/2.0)*vec4[1]/vec4[3];
721         }
722 }
723
724 void project_float_noclip(ARegion *ar, float *vec, float *adr)
725 {
726         RegionView3D *rv3d= ar->regiondata;
727         float vec4[4];
728         
729         VECCOPY(vec4, vec);
730         vec4[3]= 1.0;
731         
732         Mat4MulVec4fl(rv3d->persmat, vec4);
733         
734         if( fabs(vec4[3]) > BL_NEAR_CLIP ) {
735                 adr[0] = (float)(ar->winx/2.0)+(ar->winx/2.0)*vec4[0]/vec4[3];  
736                 adr[1] = (float)(ar->winy/2.0)+(ar->winy/2.0)*vec4[1]/vec4[3];
737         }
738         else
739         {
740                 adr[0] = ar->winx / 2.0f;
741                 adr[1] = ar->winy / 2.0f;
742         }
743 }
744
745 int get_view3d_ortho(View3D *v3d, RegionView3D *rv3d)
746 {
747   Camera *cam;
748   
749   if(rv3d->persp==V3D_CAMOB) {
750       if(v3d->camera && v3d->camera->type==OB_CAMERA) {
751           cam= v3d->camera->data;
752
753           if(cam && cam->type==CAM_ORTHO)
754               return 1;
755           else
756               return 0;
757       }
758       else
759           return 0;
760   }
761   
762   if(rv3d->persp==V3D_ORTHO)
763       return 1;
764
765   return 0;
766 }
767
768 /* also exposed in previewrender.c */
769 int get_view3d_viewplane(View3D *v3d, RegionView3D *rv3d, int winxi, int winyi, rctf *viewplane, float *clipsta, float *clipend, float *pixsize)
770 {
771         Camera *cam=NULL;
772         float lens, fac, x1, y1, x2, y2;
773         float winx= (float)winxi, winy= (float)winyi;
774         int orth= 0;
775         
776         lens= v3d->lens;        
777         
778         *clipsta= v3d->near;
779         *clipend= v3d->far;
780         
781         if(rv3d->persp==V3D_CAMOB) {
782                 if(v3d->camera) {
783                         if(v3d->camera->type==OB_LAMP ) {
784                                 Lamp *la;
785                                 
786                                 la= v3d->camera->data;
787                                 fac= cos( M_PI*la->spotsize/360.0);
788                                 
789                                 x1= saacos(fac);
790                                 lens= 16.0*fac/sin(x1);
791                                 
792                                 *clipsta= la->clipsta;
793                                 *clipend= la->clipend;
794                         }
795                         else if(v3d->camera->type==OB_CAMERA) {
796                                 cam= v3d->camera->data;
797                                 lens= cam->lens;
798                                 *clipsta= cam->clipsta;
799                                 *clipend= cam->clipend;
800                         }
801                 }
802         }
803         
804         if(rv3d->persp==V3D_ORTHO) {
805                 if(winx>winy) x1= -rv3d->dist;
806                 else x1= -winx*rv3d->dist/winy;
807                 x2= -x1;
808                 
809                 if(winx>winy) y1= -winy*rv3d->dist/winx;
810                 else y1= -rv3d->dist;
811                 y2= -y1;
812                 
813                 *clipend *= 0.5;        // otherwise too extreme low zbuffer quality
814                 *clipsta= - *clipend;
815                 orth= 1;
816         }
817         else {
818                 /* fac for zoom, also used for camdx */
819                 if(rv3d->persp==V3D_CAMOB) {
820                         fac= (1.41421+( (float)rv3d->camzoom )/50.0);
821                         fac*= fac;
822                 }
823                 else fac= 2.0;
824                 
825                 /* viewplane size depends... */
826                 if(cam && cam->type==CAM_ORTHO) {
827                         /* ortho_scale == 1 means exact 1 to 1 mapping */
828                         float dfac= 2.0*cam->ortho_scale/fac;
829                         
830                         if(winx>winy) x1= -dfac;
831                         else x1= -winx*dfac/winy;
832                         x2= -x1;
833                         
834                         if(winx>winy) y1= -winy*dfac/winx;
835                         else y1= -dfac;
836                         y2= -y1;
837                         orth= 1;
838                 }
839                 else {
840                         float dfac;
841                         
842                         if(winx>winy) dfac= 64.0/(fac*winx*lens);
843                         else dfac= 64.0/(fac*winy*lens);
844                         
845                         x1= - *clipsta * winx*dfac;
846                         x2= -x1;
847                         y1= - *clipsta * winy*dfac;
848                         y2= -y1;
849                         orth= 0;
850                 }
851                 /* cam view offset */
852                 if(cam) {
853                         float dx= 0.5*fac*rv3d->camdx*(x2-x1);
854                         float dy= 0.5*fac*rv3d->camdy*(y2-y1);
855                         x1+= dx;
856                         x2+= dx;
857                         y1+= dy;
858                         y2+= dy;
859                 }
860         }
861         
862         if(pixsize) {
863                 float viewfac;
864                 
865                 if(orth) {
866                         viewfac= (winx >= winy)? winx: winy;
867                         *pixsize= 1.0f/viewfac;
868                 }
869                 else {
870                         viewfac= (((winx >= winy)? winx: winy)*lens)/32.0;
871                         *pixsize= *clipsta/viewfac;
872                 }
873         }
874         
875         viewplane->xmin= x1;
876         viewplane->ymin= y1;
877         viewplane->xmax= x2;
878         viewplane->ymax= y2;
879         
880         return orth;
881 }
882
883 void setwinmatrixview3d(ARegion *ar, View3D *v3d, rctf *rect)           /* rect: for picking */
884 {
885         RegionView3D *rv3d= ar->regiondata;
886         rctf viewplane;
887         float clipsta, clipend, x1, y1, x2, y2;
888         int orth;
889         
890         orth= get_view3d_viewplane(v3d, rv3d, ar->winx, ar->winy, &viewplane, &clipsta, &clipend, NULL);
891         //      printf("%d %d %f %f %f %f %f %f\n", winx, winy, viewplane.xmin, viewplane.ymin, viewplane.xmax, viewplane.ymax, clipsta, clipend);
892         x1= viewplane.xmin;
893         y1= viewplane.ymin;
894         x2= viewplane.xmax;
895         y2= viewplane.ymax;
896         
897         if(rect) {              /* picking */
898                 rect->xmin/= (float)ar->winx;
899                 rect->xmin= x1+rect->xmin*(x2-x1);
900                 rect->ymin/= (float)ar->winy;
901                 rect->ymin= y1+rect->ymin*(y2-y1);
902                 rect->xmax/= (float)ar->winx;
903                 rect->xmax= x1+rect->xmax*(x2-x1);
904                 rect->ymax/= (float)ar->winy;
905                 rect->ymax= y1+rect->ymax*(y2-y1);
906                 
907                 if(orth) wmOrtho(rect->xmin, rect->xmax, rect->ymin, rect->ymax, -clipend, clipend);
908                 else wmFrustum(rect->xmin, rect->xmax, rect->ymin, rect->ymax, clipsta, clipend);
909                 
910         }
911         else {
912                 if(orth) wmOrtho(x1, x2, y1, y2, clipsta, clipend);
913                 else wmFrustum(x1, x2, y1, y2, clipsta, clipend);
914         }
915
916         /* not sure what this was for? (ton) */
917         glMatrixMode(GL_PROJECTION);
918         wmGetMatrix(rv3d->winmat);
919         glMatrixMode(GL_MODELVIEW);
920 }
921
922
923 static void obmat_to_viewmat(View3D *v3d, RegionView3D *rv3d, Object *ob, short smooth)
924 {
925         float bmat[4][4];
926         float tmat[3][3];
927         
928         rv3d->view= 0; /* dont show the grid */
929         
930         Mat4CpyMat4(bmat, ob->obmat);
931         Mat4Ortho(bmat);
932         Mat4Invert(rv3d->viewmat, bmat);
933         
934         /* view quat calculation, needed for add object */
935         Mat3CpyMat4(tmat, rv3d->viewmat);
936         if (smooth) {
937                 float new_quat[4];
938                 if (rv3d->persp==V3D_CAMOB && v3d->camera) {
939                         /* were from a camera view */
940                         
941                         float orig_ofs[3];
942                         float orig_dist= rv3d->dist;
943                         float orig_lens= v3d->lens;
944                         VECCOPY(orig_ofs, rv3d->ofs);
945                         
946                         /* Switch from camera view */
947                         Mat3ToQuat(tmat, new_quat);
948                         
949                         rv3d->persp=V3D_PERSP;
950                         rv3d->dist= 0.0;
951                         
952                         view_settings_from_ob(v3d->camera, rv3d->ofs, NULL, NULL, &v3d->lens);
953                         smooth_view(NULL, NULL, NULL, orig_ofs, new_quat, &orig_dist, &orig_lens); // XXX
954                         
955                         rv3d->persp=V3D_CAMOB; /* just to be polite, not needed */
956                         
957                 } else {
958                         Mat3ToQuat(tmat, new_quat);
959                         smooth_view(NULL, NULL, NULL, NULL, new_quat, NULL, NULL); // XXX
960                 }
961         } else {
962                 Mat3ToQuat(tmat, rv3d->viewquat);
963         }
964 }
965
966 #define QUATSET(a, b, c, d, e)  a[0]=b; a[1]=c; a[2]=d; a[3]=e; 
967
968 static void view3d_viewlock(RegionView3D *rv3d)
969 {
970         switch(rv3d->view) {
971         case V3D_VIEW_BOTTOM :
972                 QUATSET(rv3d->viewquat,0.0, -1.0, 0.0, 0.0);
973                 break;
974                 
975         case V3D_VIEW_BACK:
976                 QUATSET(rv3d->viewquat,0.0, 0.0, (float)-cos(M_PI/4.0), (float)-cos(M_PI/4.0));
977                 break;
978                 
979         case V3D_VIEW_LEFT:
980                 QUATSET(rv3d->viewquat,0.5, -0.5, 0.5, 0.5);
981                 break;
982                 
983         case V3D_VIEW_TOP:
984                 QUATSET(rv3d->viewquat,1.0, 0.0, 0.0, 0.0);
985                 break;
986                 
987         case V3D_VIEW_FRONT:
988                 QUATSET(rv3d->viewquat,(float)cos(M_PI/4.0), (float)-sin(M_PI/4.0), 0.0, 0.0);
989                 break;
990                 
991         case V3D_VIEW_RIGHT:
992                 QUATSET(rv3d->viewquat, 0.5, -0.5, -0.5, -0.5);
993                 break;
994         }
995 }
996
997 /* dont set windows active in in here, is used by renderwin too */
998 void setviewmatrixview3d(Scene *scene, View3D *v3d, RegionView3D *rv3d)
999 {
1000         if(rv3d->persp==V3D_CAMOB) {        /* obs/camera */
1001                 if(v3d->camera) {
1002                         where_is_object(scene, v3d->camera);    
1003                         obmat_to_viewmat(v3d, rv3d, v3d->camera, 0);
1004                 }
1005                 else {
1006                         QuatToMat4(rv3d->viewquat, rv3d->viewmat);
1007                         rv3d->viewmat[3][2]-= rv3d->dist;
1008                 }
1009         }
1010         else {
1011                 /* should be moved to better initialize later on XXX */
1012                 if(rv3d->viewlock)
1013                         view3d_viewlock(rv3d);
1014                 
1015                 QuatToMat4(rv3d->viewquat, rv3d->viewmat);
1016                 if(rv3d->persp==V3D_PERSP) rv3d->viewmat[3][2]-= rv3d->dist;
1017                 if(v3d->ob_centre) {
1018                         Object *ob= v3d->ob_centre;
1019                         float vec[3];
1020                         
1021                         VECCOPY(vec, ob->obmat[3]);
1022                         if(ob->type==OB_ARMATURE && v3d->ob_centre_bone[0]) {
1023                                 bPoseChannel *pchan= get_pose_channel(ob->pose, v3d->ob_centre_bone);
1024                                 if(pchan) {
1025                                         VECCOPY(vec, pchan->pose_mat[3]);
1026                                         Mat4MulVecfl(ob->obmat, vec);
1027                                 }
1028                         }
1029                         i_translate(-vec[0], -vec[1], -vec[2], rv3d->viewmat);
1030                 }
1031                 else i_translate(rv3d->ofs[0], rv3d->ofs[1], rv3d->ofs[2], rv3d->viewmat);
1032         }
1033 }
1034
1035 /* IGLuint-> GLuint*/
1036 /* Warning: be sure to account for a negative return value
1037 *   This is an error, "Too many objects in select buffer"
1038 *   and no action should be taken (can crash blender) if this happens
1039 */
1040 short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int bufsize, rcti *input)
1041 {
1042         Scene *scene= vc->scene;
1043         View3D *v3d= vc->v3d;
1044         ARegion *ar= vc->ar;
1045         rctf rect;
1046         short code, hits;
1047         
1048         G.f |= G_PICKSEL;
1049         
1050         /* case not a border select */
1051         if(input->xmin==input->xmax) {
1052                 rect.xmin= input->xmin-12;      // seems to be default value for bones only now
1053                 rect.xmax= input->xmin+12;
1054                 rect.ymin= input->ymin-12;
1055                 rect.ymax= input->ymin+12;
1056         }
1057         else {
1058                 rect.xmin= input->xmin;
1059                 rect.xmax= input->xmax;
1060                 rect.ymin= input->ymin;
1061                 rect.ymax= input->ymax;
1062         }
1063         
1064         setwinmatrixview3d(ar, v3d, &rect);
1065         Mat4MulMat4(vc->rv3d->persmat, vc->rv3d->viewmat, vc->rv3d->winmat);
1066         
1067         if(v3d->drawtype > OB_WIRE) {
1068                 v3d->zbuf= TRUE;
1069                 glEnable(GL_DEPTH_TEST);
1070         }
1071         
1072         if(vc->rv3d->rflag & RV3D_CLIPPING)
1073                 view3d_set_clipping(vc->rv3d);
1074         
1075         glSelectBuffer( bufsize, (GLuint *)buffer);
1076         glRenderMode(GL_SELECT);
1077         glInitNames();  /* these two calls whatfor? It doesnt work otherwise */
1078         glPushName(-1);
1079         code= 1;
1080         
1081         if(vc->obedit && vc->obedit->type==OB_MBALL) {
1082                 draw_object(scene, ar, v3d, BASACT, DRAW_PICKING|DRAW_CONSTCOLOR);
1083         }
1084         else if((vc->obedit && vc->obedit->type==OB_ARMATURE)) {
1085                 /* if not drawing sketch, draw bones */
1086                 if(!BDR_drawSketchNames(vc)) {
1087                         draw_object(scene, ar, v3d, BASACT, DRAW_PICKING|DRAW_CONSTCOLOR);
1088                 }
1089         }
1090         else {
1091                 Base *base;
1092                 
1093                 v3d->xray= TRUE;        // otherwise it postpones drawing
1094                 for(base= scene->base.first; base; base= base->next) {
1095                         if(base->lay & v3d->lay) {
1096                                 
1097                                 if (base->object->restrictflag & OB_RESTRICT_SELECT)
1098                                         base->selcol= 0;
1099                                 else {
1100                                         base->selcol= code;
1101                                         glLoadName(code);
1102                                         draw_object(scene, ar, v3d, base, DRAW_PICKING|DRAW_CONSTCOLOR);
1103                                         
1104                                         /* we draw group-duplicators for selection too */
1105                                         if((base->object->transflag & OB_DUPLI) && base->object->dup_group) {
1106                                                 ListBase *lb;
1107                                                 DupliObject *dob;
1108                                                 Base tbase;
1109                                                 
1110                                                 tbase.flag= OB_FROMDUPLI;
1111                                                 lb= object_duplilist(scene, base->object);
1112                                                 
1113                                                 for(dob= lb->first; dob; dob= dob->next) {
1114                                                         tbase.object= dob->ob;
1115                                                         Mat4CpyMat4(dob->ob->obmat, dob->mat);
1116                                                         
1117                                                         draw_object(scene, ar, v3d, &tbase, DRAW_PICKING|DRAW_CONSTCOLOR);
1118                                                         
1119                                                         Mat4CpyMat4(dob->ob->obmat, dob->omat);
1120                                                 }
1121                                                 free_object_duplilist(lb);
1122                                         }
1123                                         code++;
1124                                 }                               
1125                         }
1126                 }
1127                 v3d->xray= FALSE;       // restore
1128         }
1129         
1130         glPopName();    /* see above (pushname) */
1131         hits= glRenderMode(GL_RENDER);
1132         
1133         G.f &= ~G_PICKSEL;
1134         setwinmatrixview3d(ar, v3d, NULL);
1135         Mat4MulMat4(vc->rv3d->persmat, vc->rv3d->viewmat, vc->rv3d->winmat);
1136         
1137         if(v3d->drawtype > OB_WIRE) {
1138                 v3d->zbuf= 0;
1139                 glDisable(GL_DEPTH_TEST);
1140         }
1141 // XXX  persp(PERSP_WIN);
1142         
1143         if(vc->rv3d->rflag & RV3D_CLIPPING)
1144                 view3d_clr_clipping();
1145         
1146         if(hits<0) printf("Too many objects in select buffer\n");       // XXX make error message
1147         
1148         return hits;
1149 }
1150
1151 /* ********************** local view operator ******************** */
1152
1153 static unsigned int free_localbit(void)
1154 {
1155         unsigned int lay;
1156         ScrArea *sa;
1157         bScreen *sc;
1158         
1159         lay= 0;
1160         
1161         /* sometimes we loose a localview: when an area is closed */
1162         /* check all areas: which localviews are in use? */
1163         for(sc= G.main->screen.first; sc; sc= sc->id.next) {
1164                 for(sa= sc->areabase.first; sa; sa= sa->next) {
1165                         SpaceLink *sl= sa->spacedata.first;
1166                         for(; sl; sl= sl->next) {
1167                                 if(sl->spacetype==SPACE_VIEW3D) {
1168                                         View3D *v3d= (View3D*) sl;
1169                                         lay |= v3d->lay;
1170                                 }
1171                         }
1172                 }
1173         }
1174         
1175         if( (lay & 0x01000000)==0) return 0x01000000;
1176         if( (lay & 0x02000000)==0) return 0x02000000;
1177         if( (lay & 0x04000000)==0) return 0x04000000;
1178         if( (lay & 0x08000000)==0) return 0x08000000;
1179         if( (lay & 0x10000000)==0) return 0x10000000;
1180         if( (lay & 0x20000000)==0) return 0x20000000;
1181         if( (lay & 0x40000000)==0) return 0x40000000;
1182         if( (lay & 0x80000000)==0) return 0x80000000;
1183         
1184         return 0;
1185 }
1186
1187
1188 static void initlocalview(Scene *scene, ScrArea *sa)
1189 {
1190         View3D *v3d= sa->spacedata.first;
1191         Base *base;
1192         float size = 0.0, min[3], max[3], box[3];
1193         unsigned int locallay;
1194         int ok=0;
1195
1196         if(v3d->localvd) return;
1197
1198         INIT_MINMAX(min, max);
1199
1200         locallay= free_localbit();
1201
1202         if(locallay==0) {
1203                 printf("Sorry, no more than 8 localviews\n");   // XXX error 
1204                 ok= 0;
1205         }
1206         else {
1207                 if(scene->obedit) {
1208                         minmax_object(scene->obedit, min, max);
1209                         
1210                         ok= 1;
1211                 
1212                         BASACT->lay |= locallay;
1213                         scene->obedit->lay= BASACT->lay;
1214                 }
1215                 else {
1216                         for(base= FIRSTBASE; base; base= base->next) {
1217                                 if(TESTBASE(v3d, base))  {
1218                                         minmax_object(base->object, min, max);
1219                                         base->lay |= locallay;
1220                                         base->object->lay= base->lay;
1221                                         ok= 1;
1222                                 }
1223                         }
1224                 }
1225                 
1226                 box[0]= (max[0]-min[0]);
1227                 box[1]= (max[1]-min[1]);
1228                 box[2]= (max[2]-min[2]);
1229                 size= MAX3(box[0], box[1], box[2]);
1230                 if(size<=0.01) size= 0.01;
1231         }
1232         
1233         if(ok) {
1234                 ARegion *ar;
1235                 
1236                 v3d->localvd= MEM_mallocN(sizeof(View3D), "localview");
1237                 
1238                 memcpy(v3d->localvd, v3d, sizeof(View3D));
1239
1240                 for(ar= sa->regionbase.first; ar; ar= ar->next) {
1241                         if(ar->regiontype == RGN_TYPE_WINDOW) {
1242                                 RegionView3D *rv3d= ar->regiondata;
1243
1244                                 rv3d->localvd= MEM_mallocN(sizeof(RegionView3D), "localview region");
1245                                 memcpy(rv3d->localvd, rv3d, sizeof(RegionView3D));
1246                                 
1247                                 rv3d->ofs[0]= -(min[0]+max[0])/2.0;
1248                                 rv3d->ofs[1]= -(min[1]+max[1])/2.0;
1249                                 rv3d->ofs[2]= -(min[2]+max[2])/2.0;
1250
1251                                 rv3d->dist= size;
1252                                 /* perspective should be a bit farther away to look nice */
1253                                 if(rv3d->persp==V3D_ORTHO)
1254                                         rv3d->dist*= 0.7;
1255
1256                                 // correction for window aspect ratio
1257                                 if(ar->winy>2 && ar->winx>2) {
1258                                         float asp= (float)ar->winx/(float)ar->winy;
1259                                         if(asp<1.0) asp= 1.0/asp;
1260                                         rv3d->dist*= asp;
1261                                 }
1262                                 
1263                                 if (rv3d->persp==V3D_CAMOB) rv3d->persp= V3D_PERSP;
1264                                 
1265                                 v3d->cursor[0]= -rv3d->ofs[0];
1266                                 v3d->cursor[1]= -rv3d->ofs[1];
1267                                 v3d->cursor[2]= -rv3d->ofs[2];
1268                         }
1269                 }
1270                 if (v3d->near> 0.1) v3d->near= 0.1;
1271                 
1272                 v3d->lay= locallay;
1273         }
1274         else {
1275                 /* clear flags */ 
1276                 for(base= FIRSTBASE; base; base= base->next) {
1277                         if( base->lay & locallay ) {
1278                                 base->lay-= locallay;
1279                                 if(base->lay==0) base->lay= v3d->layact;
1280                                 if(base->object != scene->obedit) base->flag |= SELECT;
1281                                 base->object->lay= base->lay;
1282                         }
1283                 }               
1284                 v3d->localview= 0;
1285         }
1286
1287 }
1288
1289 static void restore_localviewdata(ScrArea *sa, int free)
1290 {
1291         ARegion *ar;
1292         View3D *v3d= sa->spacedata.first;
1293         
1294         if(v3d->localvd==NULL) return;
1295         
1296         v3d->near= v3d->localvd->near;
1297         v3d->far= v3d->localvd->far;
1298         v3d->lay= v3d->localvd->lay;
1299         v3d->layact= v3d->localvd->layact;
1300         v3d->drawtype= v3d->localvd->drawtype;
1301         v3d->camera= v3d->localvd->camera;
1302         
1303         if(free) {
1304                 MEM_freeN(v3d->localvd);
1305                 v3d->localvd= NULL;
1306                 v3d->localview= 0;
1307         }
1308         
1309         for(ar= sa->regionbase.first; ar; ar= ar->next) {
1310                 if(ar->regiontype == RGN_TYPE_WINDOW) {
1311                         RegionView3D *rv3d= ar->regiondata;
1312                         
1313                         if(rv3d->localvd) {
1314                                 rv3d->dist= rv3d->localvd->dist;
1315                                 VECCOPY(rv3d->ofs, rv3d->localvd->ofs);
1316                                 QUATCOPY(rv3d->viewquat, rv3d->localvd->viewquat);
1317                                 rv3d->view= rv3d->localvd->view;
1318                                 rv3d->persp= rv3d->localvd->persp;
1319                                 rv3d->camzoom= rv3d->localvd->camzoom;
1320
1321                                 if(free) {
1322                                         MEM_freeN(rv3d->localvd);
1323                                         rv3d->localvd= NULL;
1324                                 }
1325                         }
1326                 }
1327         }
1328 }
1329
1330 static void endlocalview(Scene *scene, ScrArea *sa)
1331 {
1332         View3D *v3d= sa->spacedata.first;
1333         struct Base *base;
1334         unsigned int locallay;
1335         
1336         if(v3d->localvd) {
1337                 
1338                 locallay= v3d->lay & 0xFF000000;
1339                 
1340                 restore_localviewdata(sa, 1); // 1 = free
1341
1342                 /* for when in other window the layers have changed */
1343                 if(v3d->scenelock) v3d->lay= scene->lay;
1344                 
1345                 for(base= FIRSTBASE; base; base= base->next) {
1346                         if( base->lay & locallay ) {
1347                                 base->lay-= locallay;
1348                                 if(base->lay==0) base->lay= v3d->layact;
1349                                 if(base->object != scene->obedit) {
1350                                         base->flag |= SELECT;
1351                                         base->object->flag |= SELECT;
1352                                 }
1353                                 base->object->lay= base->lay;
1354                         }
1355                 }
1356         } 
1357 }
1358
1359 static int localview_exec(bContext *C, wmOperator *unused)
1360 {
1361         View3D *v3d= CTX_wm_view3d(C);
1362         
1363         if(v3d->localvd)
1364                 endlocalview(CTX_data_scene(C), CTX_wm_area(C));
1365         else
1366                 initlocalview(CTX_data_scene(C), CTX_wm_area(C));
1367         
1368         ED_area_tag_redraw(CTX_wm_area(C));
1369         
1370         return OPERATOR_FINISHED;
1371 }
1372
1373 void VIEW3D_OT_localview(wmOperatorType *ot)
1374 {
1375         
1376         /* identifiers */
1377         ot->name= "Local View";
1378         ot->idname= "VIEW3D_OT_localview";
1379         
1380         /* api callbacks */
1381         ot->exec= localview_exec;
1382         
1383         ot->poll= ED_operator_view3d_active;
1384 }
1385
1386 static ListBase queue_back;
1387 static void SaveState(bContext *C)
1388 {
1389         wmWindow *win= CTX_wm_window(C);
1390         
1391         glPushAttrib(GL_ALL_ATTRIB_BITS);
1392
1393         GPU_state_init();
1394
1395         if(G.f & G_TEXTUREPAINT)
1396                 GPU_paint_set_mipmap(1);
1397         
1398         queue_back= win->queue;
1399         
1400         win->queue.first= win->queue.last= NULL;
1401         
1402         //XXX waitcursor(1);
1403 }
1404
1405 static void RestoreState(bContext *C)
1406 {
1407         wmWindow *win= CTX_wm_window(C);
1408         
1409         if(G.f & G_TEXTUREPAINT)
1410                 GPU_paint_set_mipmap(0);
1411
1412         //XXX curarea->win_swap = 0;
1413         //XXX curarea->head_swap=0;
1414         //XXX allqueue(REDRAWVIEW3D, 1);
1415         //XXX allqueue(REDRAWBUTSALL, 0);
1416         //XXX reset_slowparents();
1417         //XXX waitcursor(0);
1418         //XXX G.qual= 0;
1419         
1420         win->queue= queue_back;
1421         
1422         glPopAttrib();
1423 }
1424
1425 /* maybe we need this defined somewhere else */
1426 extern void StartKetsjiShell(struct bContext *C,int always_use_expand_framing);
1427
1428
1429 static int game_engine_exec(bContext *C, wmOperator *unused)
1430 {
1431         Scene *startscene = CTX_data_scene(C);
1432         
1433 #if GAMEBLENDER == 1
1434         SaveState(C);
1435         StartKetsjiShell(C, 1);
1436         RestoreState(C);
1437         
1438         //XXX restore_all_scene_cfra(scene_cfra_store);
1439         set_scene_bg(startscene);
1440         //XXX scene_update_for_newframe(G.scene, G.scene->lay);
1441         
1442 #else
1443         printf("GameEngine Disabled\n");
1444 #endif
1445         ED_area_tag_redraw(CTX_wm_area(C));
1446         return OPERATOR_FINISHED;
1447 }
1448
1449 void VIEW3D_OT_game_start(wmOperatorType *ot)
1450 {
1451         
1452         /* identifiers */
1453         ot->name= "Start Game Engine";
1454         ot->idname= "VIEW3D_OT_game_start";
1455         
1456         /* api callbacks */
1457         ot->exec= game_engine_exec;
1458         
1459         ot->poll= ED_operator_view3d_active;
1460 }
1461
1462 /* ************************************** */
1463
1464 void view3d_align_axis_to_vector(View3D *v3d, RegionView3D *rv3d, int axisidx, float vec[3])
1465 {
1466         float alignaxis[3] = {0.0, 0.0, 0.0};
1467         float norm[3], axis[3], angle, new_quat[4];
1468         
1469         if(axisidx > 0) alignaxis[axisidx-1]= 1.0;
1470         else alignaxis[-axisidx-1]= -1.0;
1471         
1472         VECCOPY(norm, vec);
1473         Normalize(norm);
1474         
1475         angle= (float)acos(Inpf(alignaxis, norm));
1476         Crossf(axis, alignaxis, norm);
1477         VecRotToQuat(axis, -angle, new_quat);
1478         
1479         rv3d->view= 0;
1480         
1481         if (rv3d->persp==V3D_CAMOB && v3d->camera) {
1482                 /* switch out of camera view */
1483                 float orig_ofs[3];
1484                 float orig_dist= rv3d->dist;
1485                 float orig_lens= v3d->lens;
1486                 
1487                 VECCOPY(orig_ofs, rv3d->ofs);
1488                 rv3d->persp= V3D_PERSP;
1489                 rv3d->dist= 0.0;
1490                 view_settings_from_ob(v3d->camera, rv3d->ofs, NULL, NULL, &v3d->lens);
1491                 smooth_view(NULL, NULL, NULL, orig_ofs, new_quat, &orig_dist, &orig_lens); // XXX
1492         } else {
1493                 if (rv3d->persp==V3D_CAMOB) rv3d->persp= V3D_PERSP; /* switch out of camera mode */
1494                 smooth_view(NULL, NULL, NULL, NULL, new_quat, NULL, NULL); // XXX
1495         }
1496 }
1497