Grease Pencil: Cleanup Work + Bugfixes
[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 #include "BIF_glutil.h"
67
68 #include "WM_api.h"
69 #include "WM_types.h"
70
71 #include "ED_mesh.h"
72 #include "ED_screen.h"
73 #include "ED_view3d.h"
74 #include "ED_armature.h"
75
76 #include "UI_interface.h"
77 #include "UI_resources.h"
78 #include "UI_view2d.h"
79
80 #include "GPU_draw.h"
81
82 #include "PIL_time.h" /* smoothview */
83
84 #include "view3d_intern.h"      // own include
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         memset(&sms,0,sizeof(struct SmoothViewStore));
209         VECCOPY(sms.new_ofs, rv3d->ofs);
210         QUATCOPY(sms.new_quat, rv3d->viewquat);
211         sms.new_dist= rv3d->dist;
212         sms.new_lens= v3d->lens;
213         sms.to_camera= 0;
214         
215         /* store the options we want to end with */
216         if(ofs) VECCOPY(sms.new_ofs, ofs);
217         if(quat) QUATCOPY(sms.new_quat, quat);
218         if(dist) sms.new_dist= *dist;
219         if(lens) sms.new_lens= *lens;
220         
221         if (camera) {
222                 view_settings_from_ob(camera, sms.new_ofs, sms.new_quat, &sms.new_dist, &sms.new_lens);
223                 sms.to_camera= 1; /* restore view3d values in end */
224         }
225         
226         if (C && U.smooth_viewtx) {
227                 int changed = 0; /* zero means no difference */
228                 
229                 if (sms.new_dist != rv3d->dist)
230                         changed = 1;
231                 if (sms.new_lens != v3d->lens)
232                         changed = 1;
233                 
234                 if ((sms.new_ofs[0]!=rv3d->ofs[0]) ||
235                         (sms.new_ofs[1]!=rv3d->ofs[1]) ||
236                         (sms.new_ofs[2]!=rv3d->ofs[2]) )
237                         changed = 1;
238                 
239                 if ((sms.new_quat[0]!=rv3d->viewquat[0]) ||
240                         (sms.new_quat[1]!=rv3d->viewquat[1]) ||
241                         (sms.new_quat[2]!=rv3d->viewquat[2]) ||
242                         (sms.new_quat[3]!=rv3d->viewquat[3]) )
243                         changed = 1;
244                 
245                 /* The new view is different from the old one
246                         * so animate the view */
247                 if (changed) {
248                         
249                         sms.time_allowed= (double)U.smooth_viewtx / 1000.0;
250                         
251                         /* if this is view rotation only
252                                 * we can decrease the time allowed by
253                                 * the angle between quats 
254                                 * this means small rotations wont lag */
255                         if (quat && !ofs && !dist) {
256                                 float vec1[3], vec2[3];
257                                 
258                                 VECCOPY(vec1, sms.new_quat);
259                                 VECCOPY(vec2, sms.orig_quat);
260                                 Normalize(vec1);
261                                 Normalize(vec2);
262                                 /* scale the time allowed by the rotation */
263                                 sms.time_allowed *= NormalizedVecAngle2(vec1, vec2)/(M_PI/2); 
264                         }
265                         
266                         /* original values */
267                         if (oldcamera) {
268                                 sms.orig_dist= rv3d->dist; // below function does weird stuff with it...
269                                 view_settings_from_ob(oldcamera, sms.orig_ofs, sms.orig_quat, &sms.orig_dist, &sms.orig_lens);
270                         }
271                         else {
272                                 VECCOPY(sms.orig_ofs, rv3d->ofs);
273                                 QUATCOPY(sms.orig_quat, rv3d->viewquat);
274                                 sms.orig_dist= rv3d->dist;
275                                 sms.orig_lens= v3d->lens;
276                         }
277                         /* grid draw as floor */
278                         sms.orig_view= rv3d->view;
279                         rv3d->view= 0;
280                         
281                         /* ensure it shows correct */
282                         if(sms.to_camera) rv3d->persp= V3D_PERSP;
283                         
284                         /* keep track of running timer! */
285                         if(rv3d->sms==NULL)
286                                 rv3d->sms= MEM_mallocN(sizeof(struct SmoothViewStore), "smoothview v3d");
287                         *rv3d->sms= sms;
288                         if(rv3d->smooth_timer)
289                                 WM_event_remove_window_timer(CTX_wm_window(C), rv3d->smooth_timer);
290                         /* TIMER1 is hardcoded in keymap */
291                         rv3d->smooth_timer= WM_event_add_window_timer(CTX_wm_window(C), TIMER1, 1.0/30.0);      /* max 30 frs/sec */
292                         
293                         return;
294                 }
295         }
296         
297         /* if we get here nothing happens */
298         if(sms.to_camera==0) {
299                 VECCOPY(rv3d->ofs, sms.new_ofs);
300                 QUATCOPY(rv3d->viewquat, sms.new_quat);
301                 rv3d->dist = sms.new_dist;
302                 v3d->lens = sms.new_lens;
303         }
304         ED_region_tag_redraw(CTX_wm_region(C));
305 }
306
307 /* only meant for timer usage */
308 static int view3d_smoothview_invoke(bContext *C, wmOperator *op, wmEvent *event)
309 {
310         View3D *v3d = CTX_wm_view3d(C);
311         RegionView3D *rv3d= CTX_wm_region_view3d(C);
312         struct SmoothViewStore *sms= rv3d->sms;
313         double step, step_inv;
314         
315         /* escape if not our timer */
316         if(rv3d->smooth_timer==NULL || rv3d->smooth_timer!=event->customdata)
317                 return OPERATOR_PASS_THROUGH;
318         
319         step =  (rv3d->smooth_timer->duration)/sms->time_allowed;
320         
321         /* end timer */
322         if(step >= 1.0f) {
323                 
324                 /* if we went to camera, store the original */
325                 if(sms->to_camera) {
326                         rv3d->persp= V3D_CAMOB;
327                         VECCOPY(rv3d->ofs, sms->orig_ofs);
328                         QUATCOPY(rv3d->viewquat, sms->orig_quat);
329                         rv3d->dist = sms->orig_dist;
330                         v3d->lens = sms->orig_lens;
331                 }
332                 else {
333                         VECCOPY(rv3d->ofs, sms->new_ofs);
334                         QUATCOPY(rv3d->viewquat, sms->new_quat);
335                         rv3d->dist = sms->new_dist;
336                         v3d->lens = sms->new_lens;
337                 }
338                 rv3d->view= sms->orig_view;
339                 
340                 MEM_freeN(rv3d->sms);
341                 rv3d->sms= NULL;
342                 
343                 WM_event_remove_window_timer(CTX_wm_window(C), rv3d->smooth_timer);
344                 rv3d->smooth_timer= NULL;
345         }
346         else {
347                 int i;
348                 
349                 /* ease in/out */
350                 if (step < 0.5) step = (float)pow(step*2, 2)/2;
351                 else                    step = (float)1-(pow(2*(1-step),2)/2);
352
353                 step_inv = 1.0-step;
354
355                 for (i=0; i<3; i++)
356                         rv3d->ofs[i] = sms->new_ofs[i]*step + sms->orig_ofs[i]*step_inv;
357
358                 QuatInterpol(rv3d->viewquat, sms->orig_quat, sms->new_quat, step);
359                 
360                 rv3d->dist = sms->new_dist*step + sms->orig_dist*step_inv;
361                 v3d->lens = sms->new_lens*step + sms->orig_lens*step_inv;
362         }
363         
364         ED_region_tag_redraw(CTX_wm_region(C));
365         
366         return OPERATOR_FINISHED;
367 }
368
369 void VIEW3D_OT_smoothview(wmOperatorType *ot)
370 {
371         
372         /* identifiers */
373         ot->name= "Smooth View";
374         ot->idname= "VIEW3D_OT_smoothview";
375         
376         /* api callbacks */
377         ot->invoke= view3d_smoothview_invoke;
378         
379         ot->poll= ED_operator_view3d_active;
380 }
381
382 static int view3d_setcameratoview_exec(bContext *C, wmOperator *op)
383 {
384         View3D *v3d = CTX_wm_view3d(C);
385         RegionView3D *rv3d= CTX_wm_region_view3d(C);
386         Object *ob;
387         float dvec[3];
388         
389         ob= v3d->camera;
390         dvec[0]= rv3d->dist*rv3d->viewinv[2][0];
391         dvec[1]= rv3d->dist*rv3d->viewinv[2][1];
392         dvec[2]= rv3d->dist*rv3d->viewinv[2][2];
393         
394         VECCOPY(ob->loc, dvec);
395         VecSubf(ob->loc, ob->loc, v3d->ofs);
396         rv3d->viewquat[0]= -rv3d->viewquat[0];
397
398         QuatToEul(rv3d->viewquat, ob->rot);
399         rv3d->viewquat[0]= -rv3d->viewquat[0];
400         
401         ob->recalc= OB_RECALC_OB;
402         
403         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, CTX_data_scene(C));
404         
405         return OPERATOR_FINISHED;
406
407 }
408
409 void VIEW3D_OT_setcameratoview(wmOperatorType *ot)
410 {
411         
412         /* identifiers */
413         ot->name= "Align Camera To View";
414         ot->idname= "VIEW3D_OT_camera_to_view";
415         
416         /* api callbacks */
417         ot->exec= view3d_setcameratoview_exec;  
418         ot->poll= ED_operator_view3d_active;
419         
420         /* flags */
421         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
422 }
423
424 /* ********************************** */
425
426 /* create intersection coordinates in view Z direction at mouse coordinates */
427 void viewline(ARegion *ar, View3D *v3d, short mval[2], float ray_start[3], float ray_end[3])
428 {
429         RegionView3D *rv3d= ar->regiondata;
430         float vec[4];
431         
432         if(rv3d->persp != V3D_ORTHO){
433                 vec[0]= 2.0f * mval[0] / ar->winx - 1;
434                 vec[1]= 2.0f * mval[1] / ar->winy - 1;
435                 vec[2]= -1.0f;
436                 vec[3]= 1.0f;
437                 
438                 Mat4MulVec4fl(rv3d->persinv, vec);
439                 VecMulf(vec, 1.0f / vec[3]);
440                 
441                 VECCOPY(ray_start, rv3d->viewinv[3]);
442                 VECSUB(vec, vec, ray_start);
443                 Normalize(vec);
444                 
445                 VECADDFAC(ray_start, rv3d->viewinv[3], vec, v3d->near);
446                 VECADDFAC(ray_end, rv3d->viewinv[3], vec, v3d->far);
447         }
448         else {
449                 vec[0] = 2.0f * mval[0] / ar->winx - 1;
450                 vec[1] = 2.0f * mval[1] / ar->winy - 1;
451                 vec[2] = 0.0f;
452                 vec[3] = 1.0f;
453                 
454                 Mat4MulVec4fl(rv3d->persinv, vec);
455                 
456                 VECADDFAC(ray_start, vec, rv3d->viewinv[2],  1000.0f);
457                 VECADDFAC(ray_end, vec, rv3d->viewinv[2], -1000.0f);
458         }
459 }
460
461 /* create intersection ray in view Z direction at mouse coordinates */
462 void viewray(ARegion *ar, View3D *v3d, short mval[2], float ray_start[3], float ray_normal[3])
463 {
464         float ray_end[3];
465         
466         viewline(ar, v3d, mval, ray_start, ray_end);
467         VecSubf(ray_normal, ray_end, ray_start);
468         Normalize(ray_normal);
469 }
470
471
472 void initgrabz(RegionView3D *rv3d, float x, float y, float z)
473 {
474         if(rv3d==NULL) return;
475         rv3d->zfac= rv3d->persmat[0][3]*x+ rv3d->persmat[1][3]*y+ rv3d->persmat[2][3]*z+ rv3d->persmat[3][3];
476         
477         /* if x,y,z is exactly the viewport offset, zfac is 0 and we don't want that 
478                 * (accounting for near zero values)
479                 * */
480         if (rv3d->zfac < 1.e-6f && rv3d->zfac > -1.e-6f) rv3d->zfac = 1.0f;
481         
482         /* Negative zfac means x, y, z was behind the camera (in perspective).
483                 * This gives flipped directions, so revert back to ok default case.
484         */
485         // NOTE: I've changed this to flip zfac to be positive again for now so that GPencil draws ok
486         //      -- Aligorith, 2009Aug31
487         //if (rv3d->zfac < 0.0f) rv3d->zfac = 1.0f;
488         if (rv3d->zfac < 0.0f) rv3d->zfac= -rv3d->zfac;
489 }
490
491 /* always call initgrabz */
492 void window_to_3d(ARegion *ar, float *vec, short mx, short my)
493 {
494         RegionView3D *rv3d= ar->regiondata;
495         
496         float dx= ((float)(mx-(ar->winx/2)))*rv3d->zfac/(ar->winx/2);
497         float dy= ((float)(my-(ar->winy/2)))*rv3d->zfac/(ar->winy/2);
498         
499         float fz= rv3d->persmat[0][3]*vec[0]+ rv3d->persmat[1][3]*vec[1]+ rv3d->persmat[2][3]*vec[2]+ rv3d->persmat[3][3];
500         fz= fz/rv3d->zfac;
501         
502         vec[0]= (rv3d->persinv[0][0]*dx + rv3d->persinv[1][0]*dy+ rv3d->persinv[2][0]*fz)-rv3d->ofs[0];
503         vec[1]= (rv3d->persinv[0][1]*dx + rv3d->persinv[1][1]*dy+ rv3d->persinv[2][1]*fz)-rv3d->ofs[1];
504         vec[2]= (rv3d->persinv[0][2]*dx + rv3d->persinv[1][2]*dy+ rv3d->persinv[2][2]*fz)-rv3d->ofs[2];
505         
506 }
507
508 /* always call initgrabz */
509 /* only to detect delta motion */
510 void window_to_3d_delta(ARegion *ar, float *vec, short mx, short my)
511 {
512         RegionView3D *rv3d= ar->regiondata;
513         float dx, dy;
514         
515         dx= 2.0f*mx*rv3d->zfac/ar->winx;
516         dy= 2.0f*my*rv3d->zfac/ar->winy;
517         
518         vec[0]= (rv3d->persinv[0][0]*dx + rv3d->persinv[1][0]*dy);
519         vec[1]= (rv3d->persinv[0][1]*dx + rv3d->persinv[1][1]*dy);
520         vec[2]= (rv3d->persinv[0][2]*dx + rv3d->persinv[1][2]*dy);
521 }
522
523 float read_cached_depth(ViewContext *vc, int x, int y)
524 {
525         ViewDepths *vd = vc->rv3d->depths;
526                 
527         x -= vc->ar->winrct.xmin;
528         y -= vc->ar->winrct.ymin;
529
530         if(vd && vd->depths && x > 0 && y > 0 && x < vd->w && y < vd->h)
531                 return vd->depths[y * vd->w + x];
532         else
533                 return 1;
534 }
535
536 void request_depth_update(RegionView3D *rv3d)
537 {
538         if(rv3d->depths)
539                 rv3d->depths->damaged= 1;
540 }
541
542 void view3d_get_object_project_mat(RegionView3D *rv3d, Object *ob, float pmat[4][4])
543 {
544         float vmat[4][4];
545         
546         Mat4MulMat4(vmat, ob->obmat, rv3d->viewmat);
547         Mat4MulMat4(pmat, vmat, rv3d->winmat);
548 }
549
550 /* Uses window coordinates (x,y) and depth component z to find a point in
551    modelspace */
552 void view3d_unproject(bglMats *mats, float out[3], const short x, const short y, const float z)
553 {
554         double ux, uy, uz;
555
556         gluUnProject(x,y,z, mats->modelview, mats->projection,
557                      (GLint *)mats->viewport, &ux, &uy, &uz );
558         out[0] = ux;
559         out[1] = uy;
560         out[2] = uz;
561 }
562
563 /* use above call to get projecting mat */
564 void view3d_project_float(ARegion *ar, float *vec, float *adr, float mat[4][4])
565 {
566         float vec4[4];
567         
568         adr[0]= IS_CLIPPED;
569         VECCOPY(vec4, vec);
570         vec4[3]= 1.0;
571         
572         Mat4MulVec4fl(mat, vec4);
573         
574         if( vec4[3]>FLT_EPSILON ) {
575                 adr[0] = (float)(ar->winx/2.0f)+(ar->winx/2.0f)*vec4[0]/vec4[3];        
576                 adr[1] = (float)(ar->winy/2.0f)+(ar->winy/2.0f)*vec4[1]/vec4[3];
577         } else {
578                 adr[0] = adr[1] = 0.0f;
579         }
580 }
581
582 int boundbox_clip(RegionView3D *rv3d, float obmat[][4], BoundBox *bb)
583 {
584         /* return 1: draw */
585         
586         float mat[4][4];
587         float vec[4], min, max;
588         int a, flag= -1, fl;
589         
590         if(bb==NULL) return 1;
591         if(bb->flag & OB_BB_DISABLED) return 1;
592         
593         Mat4MulMat4(mat, obmat, rv3d->persmat);
594         
595         for(a=0; a<8; a++) {
596                 VECCOPY(vec, bb->vec[a]);
597                 vec[3]= 1.0;
598                 Mat4MulVec4fl(mat, vec);
599                 max= vec[3];
600                 min= -vec[3];
601                 
602                 fl= 0;
603                 if(vec[0] < min) fl+= 1;
604                 if(vec[0] > max) fl+= 2;
605                 if(vec[1] < min) fl+= 4;
606                 if(vec[1] > max) fl+= 8;
607                 if(vec[2] < min) fl+= 16;
608                 if(vec[2] > max) fl+= 32;
609                 
610                 flag &= fl;
611                 if(flag==0) return 1;
612         }
613         
614         return 0;
615 }
616
617 void project_short(ARegion *ar, float *vec, short *adr) /* clips */
618 {
619         RegionView3D *rv3d= ar->regiondata;
620         float fx, fy, vec4[4];
621         
622         adr[0]= IS_CLIPPED;
623         
624         if(rv3d->rflag & RV3D_CLIPPING) {
625                 if(view3d_test_clipping(rv3d, vec))
626                         return;
627         }
628         
629         VECCOPY(vec4, vec);
630         vec4[3]= 1.0;
631         Mat4MulVec4fl(rv3d->persmat, vec4);
632         
633         if( vec4[3]>BL_NEAR_CLIP ) {    /* 0.001 is the NEAR clipping cutoff for picking */
634                 fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]);
635                 
636                 if( fx>0 && fx<ar->winx) {
637                         
638                         fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]);
639                         
640                         if(fy>0.0 && fy< (float)ar->winy) {
641                                 adr[0]= (short)floor(fx); 
642                                 adr[1]= (short)floor(fy);
643                         }
644                 }
645         }
646 }
647
648 void project_int(ARegion *ar, float *vec, int *adr)
649 {
650         RegionView3D *rv3d= ar->regiondata;
651         float fx, fy, vec4[4];
652         
653         adr[0]= (int)2140000000.0f;
654         VECCOPY(vec4, vec);
655         vec4[3]= 1.0;
656         
657         Mat4MulVec4fl(rv3d->persmat, vec4);
658         
659         if( vec4[3]>BL_NEAR_CLIP ) {    /* 0.001 is the NEAR clipping cutoff for picking */
660                 fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]);
661                 
662                 if( fx>-2140000000.0f && fx<2140000000.0f) {
663                         fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]);
664                         
665                         if(fy>-2140000000.0f && fy<2140000000.0f) {
666                                 adr[0]= (int)floor(fx); 
667                                 adr[1]= (int)floor(fy);
668                         }
669                 }
670         }
671 }
672
673 void project_int_noclip(ARegion *ar, float *vec, int *adr)
674 {
675         RegionView3D *rv3d= ar->regiondata;
676         float fx, fy, vec4[4];
677         
678         VECCOPY(vec4, vec);
679         vec4[3]= 1.0;
680         
681         Mat4MulVec4fl(rv3d->persmat, vec4);
682         
683         if( fabs(vec4[3]) > BL_NEAR_CLIP ) {
684                 fx = (ar->winx/2)*(1 + vec4[0]/vec4[3]);
685                 fy = (ar->winy/2)*(1 + vec4[1]/vec4[3]);
686                 
687                 adr[0] = (int)floor(fx); 
688                 adr[1] = (int)floor(fy);
689         }
690         else
691         {
692                 adr[0] = ar->winx / 2;
693                 adr[1] = ar->winy / 2;
694         }
695 }
696
697 void project_short_noclip(ARegion *ar, float *vec, short *adr)
698 {
699         RegionView3D *rv3d= ar->regiondata;
700         float fx, fy, vec4[4];
701         
702         adr[0]= IS_CLIPPED;
703         VECCOPY(vec4, vec);
704         vec4[3]= 1.0;
705         
706         Mat4MulVec4fl(rv3d->persmat, vec4);
707         
708         if( vec4[3]>BL_NEAR_CLIP ) {    /* 0.001 is the NEAR clipping cutoff for picking */
709                 fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]);
710                 
711                 if( fx>-32700 && fx<32700) {
712                         
713                         fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]);
714                         
715                         if(fy>-32700.0 && fy<32700.0) {
716                                 adr[0]= (short)floor(fx); 
717                                 adr[1]= (short)floor(fy);
718                         }
719                 }
720         }
721 }
722
723 void project_float(ARegion *ar, float *vec, float *adr)
724 {
725         RegionView3D *rv3d= ar->regiondata;
726         float vec4[4];
727         
728         adr[0]= IS_CLIPPED;
729         VECCOPY(vec4, vec);
730         vec4[3]= 1.0;
731         
732         Mat4MulVec4fl(rv3d->persmat, vec4);
733         
734         if( 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 }
739
740 void project_float_noclip(ARegion *ar, float *vec, float *adr)
741 {
742         RegionView3D *rv3d= ar->regiondata;
743         float vec4[4];
744         
745         VECCOPY(vec4, vec);
746         vec4[3]= 1.0;
747         
748         Mat4MulVec4fl(rv3d->persmat, vec4);
749         
750         if( fabs(vec4[3]) > BL_NEAR_CLIP ) {
751                 adr[0] = (float)(ar->winx/2.0)+(ar->winx/2.0)*vec4[0]/vec4[3];  
752                 adr[1] = (float)(ar->winy/2.0)+(ar->winy/2.0)*vec4[1]/vec4[3];
753         }
754         else
755         {
756                 adr[0] = ar->winx / 2.0f;
757                 adr[1] = ar->winy / 2.0f;
758         }
759 }
760
761 int get_view3d_ortho(View3D *v3d, RegionView3D *rv3d)
762 {
763   Camera *cam;
764   
765   if(rv3d->persp==V3D_CAMOB) {
766       if(v3d->camera && v3d->camera->type==OB_CAMERA) {
767           cam= v3d->camera->data;
768
769           if(cam && cam->type==CAM_ORTHO)
770               return 1;
771           else
772               return 0;
773       }
774       else
775           return 0;
776   }
777   
778   if(rv3d->persp==V3D_ORTHO)
779       return 1;
780
781   return 0;
782 }
783
784 /* also exposed in previewrender.c */
785 int get_view3d_viewplane(View3D *v3d, RegionView3D *rv3d, int winxi, int winyi, rctf *viewplane, float *clipsta, float *clipend, float *pixsize)
786 {
787         Camera *cam=NULL;
788         float lens, fac, x1, y1, x2, y2;
789         float winx= (float)winxi, winy= (float)winyi;
790         int orth= 0;
791         
792         lens= v3d->lens;        
793         
794         *clipsta= v3d->near;
795         *clipend= v3d->far;
796         
797         if(rv3d->persp==V3D_CAMOB) {
798                 if(v3d->camera) {
799                         if(v3d->camera->type==OB_LAMP ) {
800                                 Lamp *la;
801                                 
802                                 la= v3d->camera->data;
803                                 fac= cos( M_PI*la->spotsize/360.0);
804                                 
805                                 x1= saacos(fac);
806                                 lens= 16.0*fac/sin(x1);
807                                 
808                                 *clipsta= la->clipsta;
809                                 *clipend= la->clipend;
810                         }
811                         else if(v3d->camera->type==OB_CAMERA) {
812                                 cam= v3d->camera->data;
813                                 lens= cam->lens;
814                                 *clipsta= cam->clipsta;
815                                 *clipend= cam->clipend;
816                         }
817                 }
818         }
819         
820         if(rv3d->persp==V3D_ORTHO) {
821                 if(winx>winy) x1= -rv3d->dist;
822                 else x1= -winx*rv3d->dist/winy;
823                 x2= -x1;
824                 
825                 if(winx>winy) y1= -winy*rv3d->dist/winx;
826                 else y1= -rv3d->dist;
827                 y2= -y1;
828                 
829                 *clipend *= 0.5;        // otherwise too extreme low zbuffer quality
830                 *clipsta= - *clipend;
831                 orth= 1;
832         }
833         else {
834                 /* fac for zoom, also used for camdx */
835                 if(rv3d->persp==V3D_CAMOB) {
836                         fac= (1.41421+( (float)rv3d->camzoom )/50.0);
837                         fac*= fac;
838                 }
839                 else fac= 2.0;
840                 
841                 /* viewplane size depends... */
842                 if(cam && cam->type==CAM_ORTHO) {
843                         /* ortho_scale == 1 means exact 1 to 1 mapping */
844                         float dfac= 2.0*cam->ortho_scale/fac;
845                         
846                         if(winx>winy) x1= -dfac;
847                         else x1= -winx*dfac/winy;
848                         x2= -x1;
849                         
850                         if(winx>winy) y1= -winy*dfac/winx;
851                         else y1= -dfac;
852                         y2= -y1;
853                         orth= 1;
854                 }
855                 else {
856                         float dfac;
857                         
858                         if(winx>winy) dfac= 64.0/(fac*winx*lens);
859                         else dfac= 64.0/(fac*winy*lens);
860                         
861                         x1= - *clipsta * winx*dfac;
862                         x2= -x1;
863                         y1= - *clipsta * winy*dfac;
864                         y2= -y1;
865                         orth= 0;
866                 }
867                 /* cam view offset */
868                 if(cam) {
869                         float dx= 0.5*fac*rv3d->camdx*(x2-x1);
870                         float dy= 0.5*fac*rv3d->camdy*(y2-y1);
871                         x1+= dx;
872                         x2+= dx;
873                         y1+= dy;
874                         y2+= dy;
875                 }
876         }
877         
878         if(pixsize) {
879                 float viewfac;
880                 
881                 if(orth) {
882                         viewfac= (winx >= winy)? winx: winy;
883                         *pixsize= 1.0f/viewfac;
884                 }
885                 else {
886                         viewfac= (((winx >= winy)? winx: winy)*lens)/32.0;
887                         *pixsize= *clipsta/viewfac;
888                 }
889         }
890         
891         viewplane->xmin= x1;
892         viewplane->ymin= y1;
893         viewplane->xmax= x2;
894         viewplane->ymax= y2;
895         
896         return orth;
897 }
898
899 void setwinmatrixview3d(ARegion *ar, View3D *v3d, rctf *rect)           /* rect: for picking */
900 {
901         RegionView3D *rv3d= ar->regiondata;
902         rctf viewplane;
903         float clipsta, clipend, x1, y1, x2, y2;
904         int orth;
905         
906         orth= get_view3d_viewplane(v3d, rv3d, ar->winx, ar->winy, &viewplane, &clipsta, &clipend, NULL);
907         //      printf("%d %d %f %f %f %f %f %f\n", winx, winy, viewplane.xmin, viewplane.ymin, viewplane.xmax, viewplane.ymax, clipsta, clipend);
908         x1= viewplane.xmin;
909         y1= viewplane.ymin;
910         x2= viewplane.xmax;
911         y2= viewplane.ymax;
912         
913         if(rect) {              /* picking */
914                 rect->xmin/= (float)ar->winx;
915                 rect->xmin= x1+rect->xmin*(x2-x1);
916                 rect->ymin/= (float)ar->winy;
917                 rect->ymin= y1+rect->ymin*(y2-y1);
918                 rect->xmax/= (float)ar->winx;
919                 rect->xmax= x1+rect->xmax*(x2-x1);
920                 rect->ymax/= (float)ar->winy;
921                 rect->ymax= y1+rect->ymax*(y2-y1);
922                 
923                 if(orth) wmOrtho(rect->xmin, rect->xmax, rect->ymin, rect->ymax, -clipend, clipend);
924                 else wmFrustum(rect->xmin, rect->xmax, rect->ymin, rect->ymax, clipsta, clipend);
925                 
926         }
927         else {
928                 if(orth) wmOrtho(x1, x2, y1, y2, clipsta, clipend);
929                 else wmFrustum(x1, x2, y1, y2, clipsta, clipend);
930         }
931
932         /* not sure what this was for? (ton) */
933         glMatrixMode(GL_PROJECTION);
934         wmGetMatrix(rv3d->winmat);
935         glMatrixMode(GL_MODELVIEW);
936 }
937
938
939 static void obmat_to_viewmat(View3D *v3d, RegionView3D *rv3d, Object *ob, short smooth)
940 {
941         float bmat[4][4];
942         float tmat[3][3];
943         
944         rv3d->view= 0; /* dont show the grid */
945         
946         Mat4CpyMat4(bmat, ob->obmat);
947         Mat4Ortho(bmat);
948         Mat4Invert(rv3d->viewmat, bmat);
949         
950         /* view quat calculation, needed for add object */
951         Mat3CpyMat4(tmat, rv3d->viewmat);
952         if (smooth) {
953                 float new_quat[4];
954                 if (rv3d->persp==V3D_CAMOB && v3d->camera) {
955                         /* were from a camera view */
956                         
957                         float orig_ofs[3];
958                         float orig_dist= rv3d->dist;
959                         float orig_lens= v3d->lens;
960                         VECCOPY(orig_ofs, rv3d->ofs);
961                         
962                         /* Switch from camera view */
963                         Mat3ToQuat(tmat, new_quat);
964                         
965                         rv3d->persp=V3D_PERSP;
966                         rv3d->dist= 0.0;
967                         
968                         view_settings_from_ob(v3d->camera, rv3d->ofs, NULL, NULL, &v3d->lens);
969                         smooth_view(NULL, NULL, NULL, orig_ofs, new_quat, &orig_dist, &orig_lens); // XXX
970                         
971                         rv3d->persp=V3D_CAMOB; /* just to be polite, not needed */
972                         
973                 } else {
974                         Mat3ToQuat(tmat, new_quat);
975                         smooth_view(NULL, NULL, NULL, NULL, new_quat, NULL, NULL); // XXX
976                 }
977         } else {
978                 Mat3ToQuat(tmat, rv3d->viewquat);
979         }
980 }
981
982 #define QUATSET(a, b, c, d, e)  a[0]=b; a[1]=c; a[2]=d; a[3]=e; 
983
984 static void view3d_viewlock(RegionView3D *rv3d)
985 {
986         switch(rv3d->view) {
987         case V3D_VIEW_BOTTOM :
988                 QUATSET(rv3d->viewquat,0.0, -1.0, 0.0, 0.0);
989                 break;
990                 
991         case V3D_VIEW_BACK:
992                 QUATSET(rv3d->viewquat,0.0, 0.0, (float)-cos(M_PI/4.0), (float)-cos(M_PI/4.0));
993                 break;
994                 
995         case V3D_VIEW_LEFT:
996                 QUATSET(rv3d->viewquat,0.5, -0.5, 0.5, 0.5);
997                 break;
998                 
999         case V3D_VIEW_TOP:
1000                 QUATSET(rv3d->viewquat,1.0, 0.0, 0.0, 0.0);
1001                 break;
1002                 
1003         case V3D_VIEW_FRONT:
1004                 QUATSET(rv3d->viewquat,(float)cos(M_PI/4.0), (float)-sin(M_PI/4.0), 0.0, 0.0);
1005                 break;
1006                 
1007         case V3D_VIEW_RIGHT:
1008                 QUATSET(rv3d->viewquat, 0.5, -0.5, -0.5, -0.5);
1009                 break;
1010         }
1011 }
1012
1013 /* dont set windows active in in here, is used by renderwin too */
1014 void setviewmatrixview3d(Scene *scene, View3D *v3d, RegionView3D *rv3d)
1015 {
1016         if(rv3d->persp==V3D_CAMOB) {        /* obs/camera */
1017                 if(v3d->camera) {
1018                         where_is_object(scene, v3d->camera);    
1019                         obmat_to_viewmat(v3d, rv3d, v3d->camera, 0);
1020                 }
1021                 else {
1022                         QuatToMat4(rv3d->viewquat, rv3d->viewmat);
1023                         rv3d->viewmat[3][2]-= rv3d->dist;
1024                 }
1025         }
1026         else {
1027                 /* should be moved to better initialize later on XXX */
1028                 if(rv3d->viewlock)
1029                         view3d_viewlock(rv3d);
1030                 
1031                 QuatToMat4(rv3d->viewquat, rv3d->viewmat);
1032                 if(rv3d->persp==V3D_PERSP) rv3d->viewmat[3][2]-= rv3d->dist;
1033                 if(v3d->ob_centre) {
1034                         Object *ob= v3d->ob_centre;
1035                         float vec[3];
1036                         
1037                         VECCOPY(vec, ob->obmat[3]);
1038                         if(ob->type==OB_ARMATURE && v3d->ob_centre_bone[0]) {
1039                                 bPoseChannel *pchan= get_pose_channel(ob->pose, v3d->ob_centre_bone);
1040                                 if(pchan) {
1041                                         VECCOPY(vec, pchan->pose_mat[3]);
1042                                         Mat4MulVecfl(ob->obmat, vec);
1043                                 }
1044                         }
1045                         i_translate(-vec[0], -vec[1], -vec[2], rv3d->viewmat);
1046                 }
1047                 else i_translate(rv3d->ofs[0], rv3d->ofs[1], rv3d->ofs[2], rv3d->viewmat);
1048         }
1049 }
1050
1051 /* IGLuint-> GLuint*/
1052 /* Warning: be sure to account for a negative return value
1053 *   This is an error, "Too many objects in select buffer"
1054 *   and no action should be taken (can crash blender) if this happens
1055 */
1056 short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int bufsize, rcti *input)
1057 {
1058         Scene *scene= vc->scene;
1059         View3D *v3d= vc->v3d;
1060         ARegion *ar= vc->ar;
1061         rctf rect;
1062         short code, hits;
1063         
1064         G.f |= G_PICKSEL;
1065         
1066         /* case not a border select */
1067         if(input->xmin==input->xmax) {
1068                 rect.xmin= input->xmin-12;      // seems to be default value for bones only now
1069                 rect.xmax= input->xmin+12;
1070                 rect.ymin= input->ymin-12;
1071                 rect.ymax= input->ymin+12;
1072         }
1073         else {
1074                 rect.xmin= input->xmin;
1075                 rect.xmax= input->xmax;
1076                 rect.ymin= input->ymin;
1077                 rect.ymax= input->ymax;
1078         }
1079         
1080         setwinmatrixview3d(ar, v3d, &rect);
1081         Mat4MulMat4(vc->rv3d->persmat, vc->rv3d->viewmat, vc->rv3d->winmat);
1082         
1083         if(v3d->drawtype > OB_WIRE) {
1084                 v3d->zbuf= TRUE;
1085                 glEnable(GL_DEPTH_TEST);
1086         }
1087         
1088         if(vc->rv3d->rflag & RV3D_CLIPPING)
1089                 view3d_set_clipping(vc->rv3d);
1090         
1091         glSelectBuffer( bufsize, (GLuint *)buffer);
1092         glRenderMode(GL_SELECT);
1093         glInitNames();  /* these two calls whatfor? It doesnt work otherwise */
1094         glPushName(-1);
1095         code= 1;
1096         
1097         if(vc->obedit && vc->obedit->type==OB_MBALL) {
1098                 draw_object(scene, ar, v3d, BASACT, DRAW_PICKING|DRAW_CONSTCOLOR);
1099         }
1100         else if((vc->obedit && vc->obedit->type==OB_ARMATURE)) {
1101                 /* if not drawing sketch, draw bones */
1102                 if(!BDR_drawSketchNames(vc)) {
1103                         draw_object(scene, ar, v3d, BASACT, DRAW_PICKING|DRAW_CONSTCOLOR);
1104                 }
1105         }
1106         else {
1107                 Base *base;
1108                 
1109                 v3d->xray= TRUE;        // otherwise it postpones drawing
1110                 for(base= scene->base.first; base; base= base->next) {
1111                         if(base->lay & v3d->lay) {
1112                                 
1113                                 if (base->object->restrictflag & OB_RESTRICT_SELECT)
1114                                         base->selcol= 0;
1115                                 else {
1116                                         base->selcol= code;
1117                                         glLoadName(code);
1118                                         draw_object(scene, ar, v3d, base, DRAW_PICKING|DRAW_CONSTCOLOR);
1119                                         
1120                                         /* we draw group-duplicators for selection too */
1121                                         if((base->object->transflag & OB_DUPLI) && base->object->dup_group) {
1122                                                 ListBase *lb;
1123                                                 DupliObject *dob;
1124                                                 Base tbase;
1125                                                 
1126                                                 tbase.flag= OB_FROMDUPLI;
1127                                                 lb= object_duplilist(scene, base->object);
1128                                                 
1129                                                 for(dob= lb->first; dob; dob= dob->next) {
1130                                                         tbase.object= dob->ob;
1131                                                         Mat4CpyMat4(dob->ob->obmat, dob->mat);
1132                                                         
1133                                                         draw_object(scene, ar, v3d, &tbase, DRAW_PICKING|DRAW_CONSTCOLOR);
1134                                                         
1135                                                         Mat4CpyMat4(dob->ob->obmat, dob->omat);
1136                                                 }
1137                                                 free_object_duplilist(lb);
1138                                         }
1139                                         code++;
1140                                 }                               
1141                         }
1142                 }
1143                 v3d->xray= FALSE;       // restore
1144         }
1145         
1146         glPopName();    /* see above (pushname) */
1147         hits= glRenderMode(GL_RENDER);
1148         
1149         G.f &= ~G_PICKSEL;
1150         setwinmatrixview3d(ar, v3d, NULL);
1151         Mat4MulMat4(vc->rv3d->persmat, vc->rv3d->viewmat, vc->rv3d->winmat);
1152         
1153         if(v3d->drawtype > OB_WIRE) {
1154                 v3d->zbuf= 0;
1155                 glDisable(GL_DEPTH_TEST);
1156         }
1157 // XXX  persp(PERSP_WIN);
1158         
1159         if(vc->rv3d->rflag & RV3D_CLIPPING)
1160                 view3d_clr_clipping();
1161         
1162         if(hits<0) printf("Too many objects in select buffer\n");       // XXX make error message
1163         
1164         return hits;
1165 }
1166
1167 /* ********************** local view operator ******************** */
1168
1169 static unsigned int free_localbit(void)
1170 {
1171         unsigned int lay;
1172         ScrArea *sa;
1173         bScreen *sc;
1174         
1175         lay= 0;
1176         
1177         /* sometimes we loose a localview: when an area is closed */
1178         /* check all areas: which localviews are in use? */
1179         for(sc= G.main->screen.first; sc; sc= sc->id.next) {
1180                 for(sa= sc->areabase.first; sa; sa= sa->next) {
1181                         SpaceLink *sl= sa->spacedata.first;
1182                         for(; sl; sl= sl->next) {
1183                                 if(sl->spacetype==SPACE_VIEW3D) {
1184                                         View3D *v3d= (View3D*) sl;
1185                                         lay |= v3d->lay;
1186                                 }
1187                         }
1188                 }
1189         }
1190         
1191         if( (lay & 0x01000000)==0) return 0x01000000;
1192         if( (lay & 0x02000000)==0) return 0x02000000;
1193         if( (lay & 0x04000000)==0) return 0x04000000;
1194         if( (lay & 0x08000000)==0) return 0x08000000;
1195         if( (lay & 0x10000000)==0) return 0x10000000;
1196         if( (lay & 0x20000000)==0) return 0x20000000;
1197         if( (lay & 0x40000000)==0) return 0x40000000;
1198         if( (lay & 0x80000000)==0) return 0x80000000;
1199         
1200         return 0;
1201 }
1202
1203
1204 static void initlocalview(Scene *scene, ScrArea *sa)
1205 {
1206         View3D *v3d= sa->spacedata.first;
1207         Base *base;
1208         float size = 0.0, min[3], max[3], box[3];
1209         unsigned int locallay;
1210         int ok=0;
1211
1212         if(v3d->localvd) return;
1213
1214         INIT_MINMAX(min, max);
1215
1216         locallay= free_localbit();
1217
1218         if(locallay==0) {
1219                 printf("Sorry, no more than 8 localviews\n");   // XXX error 
1220                 ok= 0;
1221         }
1222         else {
1223                 if(scene->obedit) {
1224                         minmax_object(scene->obedit, min, max);
1225                         
1226                         ok= 1;
1227                 
1228                         BASACT->lay |= locallay;
1229                         scene->obedit->lay= BASACT->lay;
1230                 }
1231                 else {
1232                         for(base= FIRSTBASE; base; base= base->next) {
1233                                 if(TESTBASE(v3d, base))  {
1234                                         minmax_object(base->object, min, max);
1235                                         base->lay |= locallay;
1236                                         base->object->lay= base->lay;
1237                                         ok= 1;
1238                                 }
1239                         }
1240                 }
1241                 
1242                 box[0]= (max[0]-min[0]);
1243                 box[1]= (max[1]-min[1]);
1244                 box[2]= (max[2]-min[2]);
1245                 size= MAX3(box[0], box[1], box[2]);
1246                 if(size<=0.01) size= 0.01;
1247         }
1248         
1249         if(ok) {
1250                 ARegion *ar;
1251                 
1252                 v3d->localvd= MEM_mallocN(sizeof(View3D), "localview");
1253                 
1254                 memcpy(v3d->localvd, v3d, sizeof(View3D));
1255
1256                 for(ar= sa->regionbase.first; ar; ar= ar->next) {
1257                         if(ar->regiontype == RGN_TYPE_WINDOW) {
1258                                 RegionView3D *rv3d= ar->regiondata;
1259
1260                                 rv3d->localvd= MEM_mallocN(sizeof(RegionView3D), "localview region");
1261                                 memcpy(rv3d->localvd, rv3d, sizeof(RegionView3D));
1262                                 
1263                                 rv3d->ofs[0]= -(min[0]+max[0])/2.0;
1264                                 rv3d->ofs[1]= -(min[1]+max[1])/2.0;
1265                                 rv3d->ofs[2]= -(min[2]+max[2])/2.0;
1266
1267                                 rv3d->dist= size;
1268                                 /* perspective should be a bit farther away to look nice */
1269                                 if(rv3d->persp==V3D_ORTHO)
1270                                         rv3d->dist*= 0.7;
1271
1272                                 // correction for window aspect ratio
1273                                 if(ar->winy>2 && ar->winx>2) {
1274                                         float asp= (float)ar->winx/(float)ar->winy;
1275                                         if(asp<1.0) asp= 1.0/asp;
1276                                         rv3d->dist*= asp;
1277                                 }
1278                                 
1279                                 if (rv3d->persp==V3D_CAMOB) rv3d->persp= V3D_PERSP;
1280                                 
1281                                 v3d->cursor[0]= -rv3d->ofs[0];
1282                                 v3d->cursor[1]= -rv3d->ofs[1];
1283                                 v3d->cursor[2]= -rv3d->ofs[2];
1284                         }
1285                 }
1286                 if (v3d->near> 0.1) v3d->near= 0.1;
1287                 
1288                 v3d->lay= locallay;
1289         }
1290         else {
1291                 /* clear flags */ 
1292                 for(base= FIRSTBASE; base; base= base->next) {
1293                         if( base->lay & locallay ) {
1294                                 base->lay-= locallay;
1295                                 if(base->lay==0) base->lay= v3d->layact;
1296                                 if(base->object != scene->obedit) base->flag |= SELECT;
1297                                 base->object->lay= base->lay;
1298                         }
1299                 }               
1300                 v3d->localview= 0;
1301         }
1302
1303 }
1304
1305 static void restore_localviewdata(ScrArea *sa, int free)
1306 {
1307         ARegion *ar;
1308         View3D *v3d= sa->spacedata.first;
1309         
1310         if(v3d->localvd==NULL) return;
1311         
1312         v3d->near= v3d->localvd->near;
1313         v3d->far= v3d->localvd->far;
1314         v3d->lay= v3d->localvd->lay;
1315         v3d->layact= v3d->localvd->layact;
1316         v3d->drawtype= v3d->localvd->drawtype;
1317         v3d->camera= v3d->localvd->camera;
1318         
1319         if(free) {
1320                 MEM_freeN(v3d->localvd);
1321                 v3d->localvd= NULL;
1322                 v3d->localview= 0;
1323         }
1324         
1325         for(ar= sa->regionbase.first; ar; ar= ar->next) {
1326                 if(ar->regiontype == RGN_TYPE_WINDOW) {
1327                         RegionView3D *rv3d= ar->regiondata;
1328                         
1329                         if(rv3d->localvd) {
1330                                 rv3d->dist= rv3d->localvd->dist;
1331                                 VECCOPY(rv3d->ofs, rv3d->localvd->ofs);
1332                                 QUATCOPY(rv3d->viewquat, rv3d->localvd->viewquat);
1333                                 rv3d->view= rv3d->localvd->view;
1334                                 rv3d->persp= rv3d->localvd->persp;
1335                                 rv3d->camzoom= rv3d->localvd->camzoom;
1336
1337                                 if(free) {
1338                                         MEM_freeN(rv3d->localvd);
1339                                         rv3d->localvd= NULL;
1340                                 }
1341                         }
1342                 }
1343         }
1344 }
1345
1346 static void endlocalview(Scene *scene, ScrArea *sa)
1347 {
1348         View3D *v3d= sa->spacedata.first;
1349         struct Base *base;
1350         unsigned int locallay;
1351         
1352         if(v3d->localvd) {
1353                 
1354                 locallay= v3d->lay & 0xFF000000;
1355                 
1356                 restore_localviewdata(sa, 1); // 1 = free
1357
1358                 /* for when in other window the layers have changed */
1359                 if(v3d->scenelock) v3d->lay= scene->lay;
1360                 
1361                 for(base= FIRSTBASE; base; base= base->next) {
1362                         if( base->lay & locallay ) {
1363                                 base->lay-= locallay;
1364                                 if(base->lay==0) base->lay= v3d->layact;
1365                                 if(base->object != scene->obedit) {
1366                                         base->flag |= SELECT;
1367                                         base->object->flag |= SELECT;
1368                                 }
1369                                 base->object->lay= base->lay;
1370                         }
1371                 }
1372         } 
1373 }
1374
1375 static int localview_exec(bContext *C, wmOperator *unused)
1376 {
1377         View3D *v3d= CTX_wm_view3d(C);
1378         
1379         if(v3d->localvd)
1380                 endlocalview(CTX_data_scene(C), CTX_wm_area(C));
1381         else
1382                 initlocalview(CTX_data_scene(C), CTX_wm_area(C));
1383         
1384         ED_area_tag_redraw(CTX_wm_area(C));
1385         
1386         return OPERATOR_FINISHED;
1387 }
1388
1389 void VIEW3D_OT_localview(wmOperatorType *ot)
1390 {
1391         
1392         /* identifiers */
1393         ot->name= "Local View";
1394         ot->idname= "VIEW3D_OT_localview";
1395         
1396         /* api callbacks */
1397         ot->exec= localview_exec;
1398         
1399         ot->poll= ED_operator_view3d_active;
1400 }
1401
1402 #if GAMEBLENDER == 1
1403
1404 static ListBase queue_back;
1405 static void SaveState(bContext *C)
1406 {
1407         wmWindow *win= CTX_wm_window(C);
1408         Object *obact = CTX_data_active_object(C);
1409         
1410         glPushAttrib(GL_ALL_ATTRIB_BITS);
1411
1412         GPU_state_init();
1413
1414         if(obact && obact->mode & OB_MODE_TEXTURE_PAINT)
1415                 GPU_paint_set_mipmap(1);
1416         
1417         queue_back= win->queue;
1418         
1419         win->queue.first= win->queue.last= NULL;
1420         
1421         //XXX waitcursor(1);
1422 }
1423
1424 static void RestoreState(bContext *C)
1425 {
1426         wmWindow *win= CTX_wm_window(C);
1427         Object *obact = CTX_data_active_object(C);
1428         
1429         if(obact && obact->mode & OB_MODE_TEXTURE_PAINT)
1430                 GPU_paint_set_mipmap(0);
1431
1432         //XXX curarea->win_swap = 0;
1433         //XXX curarea->head_swap=0;
1434         //XXX allqueue(REDRAWVIEW3D, 1);
1435         //XXX allqueue(REDRAWBUTSALL, 0);
1436         //XXX reset_slowparents();
1437         //XXX waitcursor(0);
1438         //XXX G.qual= 0;
1439         
1440         win->queue= queue_back;
1441         
1442         glPopAttrib();
1443 }
1444
1445 /* maybe we need this defined somewhere else */
1446 extern void StartKetsjiShell(struct bContext *C, struct ARegion *ar, int always_use_expand_framing);
1447
1448 #endif // GAMEBLENDER == 1
1449
1450 int game_engine_poll(bContext *C)
1451 {
1452         return CTX_data_mode_enum(C)==CTX_MODE_OBJECT ? 1:0;
1453 }
1454
1455 static int game_engine_exec(bContext *C, wmOperator *unused)
1456 {
1457 #if GAMEBLENDER == 1
1458         Scene *startscene = CTX_data_scene(C);
1459         bScreen *sc= CTX_wm_screen(C);
1460         ScrArea *sa, *prevsa= CTX_wm_area(C);
1461         ARegion *ar, *prevar= CTX_wm_region(C);
1462
1463         sa= prevsa;
1464         if(sa->spacetype != SPACE_VIEW3D) {
1465                 for(sa=sc->areabase.first; sa; sa= sa->next)
1466                         if(sa->spacetype==SPACE_VIEW3D)
1467                                 break;
1468         }
1469
1470         if(!sa)
1471                 return OPERATOR_CANCELLED;
1472         
1473         for(ar=sa->regionbase.first; ar; ar=ar->next)
1474                 if(ar->regiontype == RGN_TYPE_WINDOW)
1475                         break;
1476         
1477         if(!ar)
1478                 return OPERATOR_CANCELLED;
1479         
1480         // bad context switch ..
1481         CTX_wm_area_set(C, sa);
1482         CTX_wm_region_set(C, ar);
1483
1484         view3d_operator_needs_opengl(C);
1485         
1486         SaveState(C);
1487         StartKetsjiShell(C, ar, 1);
1488         RestoreState(C);
1489         
1490         CTX_wm_region_set(C, prevar);
1491         CTX_wm_area_set(C, prevsa);
1492
1493         //XXX restore_all_scene_cfra(scene_cfra_store);
1494         set_scene_bg(startscene);
1495         //XXX scene_update_for_newframe(G.scene, G.scene->lay);
1496         
1497 #else
1498         printf("GameEngine Disabled\n");
1499 #endif
1500         ED_area_tag_redraw(CTX_wm_area(C));
1501         return OPERATOR_FINISHED;
1502 }
1503
1504 void VIEW3D_OT_game_start(wmOperatorType *ot)
1505 {
1506         
1507         /* identifiers */
1508         ot->name= "Start Game Engine";
1509         ot->idname= "VIEW3D_OT_game_start";
1510         
1511         /* api callbacks */
1512         ot->exec= game_engine_exec;
1513         
1514         ot->poll= game_engine_poll;
1515 }
1516
1517 /* ************************************** */
1518
1519 void view3d_align_axis_to_vector(View3D *v3d, RegionView3D *rv3d, int axisidx, float vec[3])
1520 {
1521         float alignaxis[3] = {0.0, 0.0, 0.0};
1522         float norm[3], axis[3], angle, new_quat[4];
1523         
1524         if(axisidx > 0) alignaxis[axisidx-1]= 1.0;
1525         else alignaxis[-axisidx-1]= -1.0;
1526         
1527         VECCOPY(norm, vec);
1528         Normalize(norm);
1529         
1530         angle= (float)acos(Inpf(alignaxis, norm));
1531         Crossf(axis, alignaxis, norm);
1532         VecRotToQuat(axis, -angle, new_quat);
1533         
1534         rv3d->view= 0;
1535         
1536         if (rv3d->persp==V3D_CAMOB && v3d->camera) {
1537                 /* switch out of camera view */
1538                 float orig_ofs[3];
1539                 float orig_dist= rv3d->dist;
1540                 float orig_lens= v3d->lens;
1541                 
1542                 VECCOPY(orig_ofs, rv3d->ofs);
1543                 rv3d->persp= V3D_PERSP;
1544                 rv3d->dist= 0.0;
1545                 view_settings_from_ob(v3d->camera, rv3d->ofs, NULL, NULL, &v3d->lens);
1546                 smooth_view(NULL, NULL, NULL, orig_ofs, new_quat, &orig_dist, &orig_lens); // XXX
1547         } else {
1548                 if (rv3d->persp==V3D_CAMOB) rv3d->persp= V3D_PERSP; /* switch out of camera mode */
1549                 smooth_view(NULL, NULL, NULL, NULL, new_quat, NULL, NULL); // XXX
1550         }
1551 }
1552