converted more mixed tab/space indentations to tabs. only whitespace changes.
[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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 /** \file blender/editors/space_view3d/view3d_view.c
30  *  \ingroup spview3d
31  */
32
33
34 #include "DNA_camera_types.h"
35 #include "DNA_lamp_types.h"
36 #include "DNA_scene_types.h"
37 #include "DNA_object_types.h"
38
39 #include "MEM_guardedalloc.h"
40
41 #include "BLI_math.h"
42 #include "BLI_rect.h"
43 #include "BLI_listbase.h"
44 #include "BLI_utildefines.h"
45
46 #include "BKE_anim.h"
47 #include "BKE_action.h"
48 #include "BKE_context.h"
49 #include "BKE_depsgraph.h"
50 #include "BKE_object.h"
51 #include "BKE_global.h"
52 #include "BKE_main.h"
53 #include "BKE_report.h"
54 #include "BKE_scene.h"
55
56 #include "BIF_gl.h"
57 #include "BIF_glutil.h"
58
59 #include "GPU_draw.h"
60
61 #include "WM_api.h"
62 #include "WM_types.h"
63
64 #include "ED_screen.h"
65 #include "ED_armature.h"
66
67 #ifdef WITH_GAMEENGINE
68 #include "SYS_System.h"
69 #endif
70
71 #include "view3d_intern.h"      // own include
72
73 /* use this call when executing an operator,
74    event system doesn't set for each event the
75    opengl drawing context */
76 void view3d_operator_needs_opengl(const bContext *C)
77 {
78         wmWindow *win = CTX_wm_window(C);
79         ARegion *ar= CTX_wm_region(C);
80         
81         view3d_region_operator_needs_opengl(win, ar);
82 }
83
84 void view3d_region_operator_needs_opengl(wmWindow *win, ARegion *ar)
85 {
86         /* for debugging purpose, context should always be OK */
87         if ((ar == NULL) || (ar->regiontype!=RGN_TYPE_WINDOW))
88                 printf("view3d_region_operator_needs_opengl error, wrong region\n");
89         else {
90                 RegionView3D *rv3d= ar->regiondata;
91                 
92                 wmSubWindowSet(win, ar->swinid);
93                 glMatrixMode(GL_PROJECTION);
94                 glLoadMatrixf(rv3d->winmat);
95                 glMatrixMode(GL_MODELVIEW);
96                 glLoadMatrixf(rv3d->viewmat);
97         }
98 }
99
100 float *give_cursor(Scene *scene, View3D *v3d)
101 {
102         if(v3d && v3d->localvd) return v3d->cursor;
103         else return scene->cursor;
104 }
105
106
107 /* Gets the lens and clipping values from a camera of lamp type object */
108 static void object_lens_clip_settings(Object *ob, float *lens, float *clipsta, float *clipend)
109 {       
110         if (!ob) return;
111         
112         if(ob->type==OB_LAMP ) {
113                 Lamp *la = ob->data;
114                 if (lens) {
115                         float x1, fac;
116                         fac= cosf((float)M_PI*la->spotsize/360.0f);
117                         x1= saacos(fac);
118                         *lens= 16.0f*fac/sinf(x1);
119                 }
120                 if (clipsta)    *clipsta= la->clipsta;
121                 if (clipend)    *clipend= la->clipend;
122         }
123         else if(ob->type==OB_CAMERA) {
124                 Camera *cam= ob->data;
125                 if (lens)               *lens= cam->lens;
126                 if (clipsta)    *clipsta= cam->clipsta;
127                 if (clipend)    *clipend= cam->clipend;
128         }
129         else {
130                 if (lens)               *lens= 35.0f;
131         }
132 }
133
134
135 /* Gets the view trasnformation from a camera
136 * currently dosnt take camzoom into account
137
138 * The dist is not modified for this function, if NULL its assimed zero
139 * */
140 void view3d_settings_from_ob(Object *ob, float *ofs, float *quat, float *dist, float *lens)
141 {
142         if (!ob) return;
143
144         /* Offset */
145         if (ofs)
146                 negate_v3_v3(ofs, ob->obmat[3]);
147
148         /* Quat */
149         if (quat) {
150                 float imat[4][4];
151                 invert_m4_m4(imat, ob->obmat);
152                 mat4_to_quat(quat, imat);
153         }
154
155         if (dist) {
156                 float tquat[4];
157                 float vec[3];
158
159                 vec[0]= 0.0f;
160                 vec[1]= 0.0f;
161                 vec[2]= -(*dist);
162
163                 mat4_to_quat(tquat, ob->obmat);
164
165                 mul_qt_v3(tquat, vec);
166
167                 sub_v3_v3(ofs, vec);
168         }
169
170         /* Lens */
171         if (lens)
172                 object_lens_clip_settings(ob, lens, NULL, NULL);
173 }
174
175
176 /* ****************** smooth view operator ****************** */
177 /* This operator is one of the 'timer refresh' ones like animation playback */
178
179 struct SmoothViewStore {
180         float orig_dist, new_dist;
181         float orig_lens, new_lens;
182         float orig_quat[4], new_quat[4];
183         float orig_ofs[3], new_ofs[3];
184         
185         int to_camera, orig_view;
186         
187         double time_allowed;
188 };
189
190 /* will start timer if appropriate */
191 /* the arguments are the desired situation */
192 void smooth_view(bContext *C, Object *oldcamera, Object *camera, float *ofs, float *quat, float *dist, float *lens)
193 {
194         View3D *v3d = CTX_wm_view3d(C);
195         RegionView3D *rv3d= CTX_wm_region_view3d(C);
196         struct SmoothViewStore sms= {0};
197         short ok= FALSE;
198         
199         /* initialize sms */
200         copy_v3_v3(sms.new_ofs, rv3d->ofs);
201         copy_qt_qt(sms.new_quat, rv3d->viewquat);
202         sms.new_dist= rv3d->dist;
203         sms.new_lens= v3d->lens;
204         sms.to_camera= 0;
205         
206         /* store the options we want to end with */
207         if(ofs) copy_v3_v3(sms.new_ofs, ofs);
208         if(quat) copy_qt_qt(sms.new_quat, quat);
209         if(dist) sms.new_dist= *dist;
210         if(lens) sms.new_lens= *lens;
211
212         if (camera) {
213                 view3d_settings_from_ob(camera, sms.new_ofs, sms.new_quat, &sms.new_dist, &sms.new_lens);
214                 sms.to_camera= 1; /* restore view3d values in end */
215         }
216         
217         if (C && U.smooth_viewtx) {
218                 int changed = 0; /* zero means no difference */
219                 
220                 if (oldcamera != camera)
221                         changed = 1;
222                 else if (sms.new_dist != rv3d->dist)
223                         changed = 1;
224                 else if (sms.new_lens != v3d->lens)
225                         changed = 1;
226                 else if (!equals_v3v3(sms.new_ofs, rv3d->ofs))
227                         changed = 1;
228                 else if (!equals_v4v4(sms.new_quat, rv3d->viewquat))
229                         changed = 1;
230                 
231                 /* The new view is different from the old one
232                         * so animate the view */
233                 if (changed) {
234
235                         /* original values */
236                         if (oldcamera) {
237                                 sms.orig_dist= rv3d->dist; // below function does weird stuff with it...
238                                 view3d_settings_from_ob(oldcamera, sms.orig_ofs, sms.orig_quat, &sms.orig_dist, &sms.orig_lens);
239                         }
240                         else {
241                                 copy_v3_v3(sms.orig_ofs, rv3d->ofs);
242                                 copy_qt_qt(sms.orig_quat, rv3d->viewquat);
243                                 sms.orig_dist= rv3d->dist;
244                                 sms.orig_lens= v3d->lens;
245                         }
246                         /* grid draw as floor */
247                         if((rv3d->viewlock & RV3D_LOCKED)==0) {
248                                 /* use existing if exists, means multiple calls to smooth view wont loose the original 'view' setting */
249                                 sms.orig_view= rv3d->sms ? rv3d->sms->orig_view : rv3d->view;
250                                 rv3d->view= 0;
251                         }
252
253                         sms.time_allowed= (double)U.smooth_viewtx / 1000.0;
254                         
255                         /* if this is view rotation only
256                                 * we can decrease the time allowed by
257                                 * the angle between quats 
258                                 * this means small rotations wont lag */
259                         if (quat && !ofs && !dist) {
260                                 float vec1[3]={0,0,1}, vec2[3]= {0,0,1};
261                                 float q1[4], q2[4];
262
263                                 invert_qt_qt(q1, sms.new_quat);
264                                 invert_qt_qt(q2, sms.orig_quat);
265
266                                 mul_qt_v3(q1, vec1);
267                                 mul_qt_v3(q2, vec2);
268
269                                 /* scale the time allowed by the rotation */
270                                 sms.time_allowed *= (double)angle_v3v3(vec1, vec2) / M_PI; /* 180deg == 1.0 */
271                         }
272
273                         /* ensure it shows correct */
274                         if(sms.to_camera) rv3d->persp= RV3D_PERSP;
275
276                         rv3d->rflag |= RV3D_NAVIGATING;
277                         
278                         /* keep track of running timer! */
279                         if(rv3d->sms==NULL)
280                                 rv3d->sms= MEM_mallocN(sizeof(struct SmoothViewStore), "smoothview v3d");
281                         *rv3d->sms= sms;
282                         if(rv3d->smooth_timer)
283                                 WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), rv3d->smooth_timer);
284                         /* TIMER1 is hardcoded in keymap */
285                         rv3d->smooth_timer= WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER1, 1.0/100.0); /* max 30 frs/sec */
286                         
287                         ok= TRUE;
288                 }
289         }
290         
291         /* if we get here nothing happens */
292         if(ok == FALSE) {
293                 ARegion *ar= CTX_wm_region(C);
294
295                 if(sms.to_camera==0) {
296                         copy_v3_v3(rv3d->ofs, sms.new_ofs);
297                         copy_qt_qt(rv3d->viewquat, sms.new_quat);
298                         rv3d->dist = sms.new_dist;
299                         v3d->lens = sms.new_lens;
300                 }
301
302                 if(rv3d->viewlock & RV3D_BOXVIEW)
303                         view3d_boxview_copy(CTX_wm_area(C), ar);
304
305                 ED_region_tag_redraw(ar);
306         }
307 }
308
309 /* only meant for timer usage */
310 static int view3d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
311 {
312         View3D *v3d = CTX_wm_view3d(C);
313         RegionView3D *rv3d= CTX_wm_region_view3d(C);
314         struct SmoothViewStore *sms= rv3d->sms;
315         float step, step_inv;
316         
317         /* escape if not our timer */
318         if(rv3d->smooth_timer==NULL || rv3d->smooth_timer!=event->customdata)
319                 return OPERATOR_PASS_THROUGH;
320         
321         if(sms->time_allowed != 0.0)
322                 step = (float)((rv3d->smooth_timer->duration)/sms->time_allowed);
323         else
324                 step = 1.0f;
325         
326         /* end timer */
327         if(step >= 1.0f) {
328                 
329                 /* if we went to camera, store the original */
330                 if(sms->to_camera) {
331                         rv3d->persp= RV3D_CAMOB;
332                         copy_v3_v3(rv3d->ofs, sms->orig_ofs);
333                         copy_qt_qt(rv3d->viewquat, sms->orig_quat);
334                         rv3d->dist = sms->orig_dist;
335                         v3d->lens = sms->orig_lens;
336                 }
337                 else {
338                         copy_v3_v3(rv3d->ofs, sms->new_ofs);
339                         copy_qt_qt(rv3d->viewquat, sms->new_quat);
340                         rv3d->dist = sms->new_dist;
341                         v3d->lens = sms->new_lens;
342                 }
343                 
344                 if((rv3d->viewlock & RV3D_LOCKED)==0) {
345                         rv3d->view= sms->orig_view;
346                 }
347
348                 MEM_freeN(rv3d->sms);
349                 rv3d->sms= NULL;
350                 
351                 WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), rv3d->smooth_timer);
352                 rv3d->smooth_timer= NULL;
353                 rv3d->rflag &= ~RV3D_NAVIGATING;
354         }
355         else {
356                 int i;
357                 
358                 /* ease in/out */
359                 if (step < 0.5f)        step = (float)pow(step*2.0f, 2.0)/2.0f;
360                 else                            step = (float)1.0f-(powf(2.0f*(1.0f-step),2.0f)/2.0f);
361
362                 step_inv = 1.0f-step;
363
364                 for (i=0; i<3; i++)
365                         rv3d->ofs[i] = sms->new_ofs[i] * step + sms->orig_ofs[i]*step_inv;
366
367                 interp_qt_qtqt(rv3d->viewquat, sms->orig_quat, sms->new_quat, step);
368                 
369                 rv3d->dist = sms->new_dist * step + sms->orig_dist*step_inv;
370                 v3d->lens = sms->new_lens * step + sms->orig_lens*step_inv;
371         }
372         
373         if(rv3d->viewlock & RV3D_BOXVIEW)
374                 view3d_boxview_copy(CTX_wm_area(C), CTX_wm_region(C));
375         
376         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, v3d);
377         
378         return OPERATOR_FINISHED;
379 }
380
381 void VIEW3D_OT_smoothview(wmOperatorType *ot)
382 {
383         
384         /* identifiers */
385         ot->name= "Smooth View";
386         ot->idname= "VIEW3D_OT_smoothview";
387         ot->description="The time to animate the change of view (in milliseconds)";
388         
389         /* api callbacks */
390         ot->invoke= view3d_smoothview_invoke;
391         
392         ot->poll= ED_operator_view3d_active;
393 }
394
395 /* ****************** change view operators ****************** */
396
397 static void setcameratoview3d(RegionView3D *rv3d, Object *ob)
398 {
399         float dvec[3];
400         float mat3[3][3];
401
402         mul_v3_v3fl(dvec, rv3d->viewinv[2], rv3d->dist);
403         sub_v3_v3v3(ob->loc, dvec, rv3d->ofs);
404         rv3d->viewquat[0]= -rv3d->viewquat[0];
405
406         // quat_to_eul( ob->rot,rv3d->viewquat); // in 2.4x for xyz eulers only
407         quat_to_mat3(mat3, rv3d->viewquat);
408         object_mat3_to_rot(ob, mat3, 0);
409
410         rv3d->viewquat[0]= -rv3d->viewquat[0];
411         
412         ob->recalc= OB_RECALC_OB;
413 }
414
415
416 static int view3d_setcameratoview_exec(bContext *C, wmOperator *UNUSED(op))
417 {
418         View3D *v3d = CTX_wm_view3d(C);
419         RegionView3D *rv3d= CTX_wm_region_view3d(C);
420
421         copy_qt_qt(rv3d->lviewquat, rv3d->viewquat);
422         rv3d->lview= rv3d->view;
423         if(rv3d->persp != RV3D_CAMOB) {
424                 rv3d->lpersp= rv3d->persp;
425         }
426
427         setcameratoview3d(rv3d, v3d->camera);
428         DAG_id_tag_update(&v3d->camera->id, OB_RECALC_OB);
429         rv3d->persp = RV3D_CAMOB;
430         
431         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, v3d->camera);
432         
433         return OPERATOR_FINISHED;
434
435 }
436
437 static int view3d_setcameratoview_poll(bContext *C)
438 {
439         View3D *v3d = CTX_wm_view3d(C);
440         RegionView3D *rv3d= CTX_wm_region_view3d(C);
441
442         if (v3d==NULL || v3d->camera==NULL)     return 0;
443         if (rv3d && rv3d->viewlock != 0)                return 0;
444         return 1;
445 }
446
447 void VIEW3D_OT_setcameratoview(wmOperatorType *ot)
448 {
449         
450         /* identifiers */
451         ot->name= "Align Camera To View";
452         ot->description= "Set camera view to active view";
453         ot->idname= "VIEW3D_OT_camera_to_view";
454         
455         /* api callbacks */
456         ot->exec= view3d_setcameratoview_exec;  
457         ot->poll= view3d_setcameratoview_poll;
458         
459         /* flags */
460         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
461 }
462
463
464 static int view3d_setobjectascamera_exec(bContext *C, wmOperator *UNUSED(op))
465 {
466         View3D *v3d = CTX_wm_view3d(C);
467         RegionView3D *rv3d= CTX_wm_region_view3d(C);
468         Scene *scene= CTX_data_scene(C);
469         Object *ob = CTX_data_active_object(C);
470
471         if(ob) {
472                 Object *camera_old= (rv3d->persp == RV3D_CAMOB && scene->camera) ? scene->camera : NULL;
473                 rv3d->persp= RV3D_CAMOB;
474                 v3d->camera= ob;
475                 if(v3d->scenelock)
476                         scene->camera= ob;
477
478                 if(camera_old != ob) /* unlikely but looks like a glitch when set to the same */
479                         smooth_view(C, camera_old, v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, &v3d->lens);
480
481                 WM_event_add_notifier(C, NC_SCENE|ND_RENDER_OPTIONS|NC_OBJECT|ND_DRAW, CTX_data_scene(C));
482         }
483         
484         return OPERATOR_FINISHED;
485 }
486
487 static int region3d_unlocked_poll(bContext *C)
488 {
489         RegionView3D *rv3d= CTX_wm_region_view3d(C);
490         return (rv3d && rv3d->viewlock==0);
491 }
492
493
494 void VIEW3D_OT_object_as_camera(wmOperatorType *ot)
495 {
496         
497         /* identifiers */
498         ot->name= "Set Active Object as Camera";
499         ot->description= "Set the active object as the active camera for this view or scene";
500         ot->idname= "VIEW3D_OT_object_as_camera";
501         
502         /* api callbacks */
503         ot->exec= view3d_setobjectascamera_exec;        
504         ot->poll= region3d_unlocked_poll;
505         
506         /* flags */
507         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
508 }
509
510 /* ********************************** */
511
512 void view3d_calculate_clipping(BoundBox *bb, float planes[4][4], bglMats *mats, rcti *rect)
513 {
514         double xs, ys, p[3];
515         short val;
516
517         /* near zero floating point values can give issues with gluUnProject
518                 in side view on some implementations */
519         if(fabs(mats->modelview[0]) < 1e-6) mats->modelview[0]= 0.0;
520         if(fabs(mats->modelview[5]) < 1e-6) mats->modelview[5]= 0.0;
521
522         /* Set up viewport so that gluUnProject will give correct values */
523         mats->viewport[0] = 0;
524         mats->viewport[1] = 0;
525
526         /* four clipping planes and bounding volume */
527         /* first do the bounding volume */
528         for(val=0; val<4; val++) {
529                 xs= (val==0||val==3)?rect->xmin:rect->xmax;
530                 ys= (val==0||val==1)?rect->ymin:rect->ymax;
531
532                 gluUnProject(xs, ys, 0.0, mats->modelview, mats->projection, mats->viewport, &p[0], &p[1], &p[2]);
533                 VECCOPY(bb->vec[val], p);
534
535                 gluUnProject(xs, ys, 1.0, mats->modelview, mats->projection, mats->viewport, &p[0], &p[1], &p[2]);
536                 VECCOPY(bb->vec[4+val], p);
537         }
538
539         /* then plane equations */
540         for(val=0; val<4; val++) {
541
542                 normal_tri_v3(planes[val], bb->vec[val], bb->vec[val==3?0:val+1], bb->vec[val+4]);
543
544                 planes[val][3]= - planes[val][0]*bb->vec[val][0]
545                         - planes[val][1]*bb->vec[val][1]
546                         - planes[val][2]*bb->vec[val][2];
547         }
548 }
549
550 /* create intersection coordinates in view Z direction at mouse coordinates */
551 void viewline(ARegion *ar, View3D *v3d, float mval[2], float ray_start[3], float ray_end[3])
552 {
553         RegionView3D *rv3d= ar->regiondata;
554         float vec[4];
555         int a;
556         
557         if(!get_view3d_ortho(v3d, rv3d)) {
558                 vec[0]= 2.0f * mval[0] / ar->winx - 1;
559                 vec[1]= 2.0f * mval[1] / ar->winy - 1;
560                 vec[2]= -1.0f;
561                 vec[3]= 1.0f;
562                 
563                 mul_m4_v4(rv3d->persinv, vec);
564                 mul_v3_fl(vec, 1.0f / vec[3]);
565                 
566                 copy_v3_v3(ray_start, rv3d->viewinv[3]);
567                 sub_v3_v3(vec, ray_start);
568                 normalize_v3(vec);
569                 
570                 VECADDFAC(ray_start, rv3d->viewinv[3], vec, v3d->near);
571                 VECADDFAC(ray_end, rv3d->viewinv[3], vec, v3d->far);
572         }
573         else {
574                 vec[0] = 2.0f * mval[0] / ar->winx - 1;
575                 vec[1] = 2.0f * mval[1] / ar->winy - 1;
576                 vec[2] = 0.0f;
577                 vec[3] = 1.0f;
578                 
579                 mul_m4_v4(rv3d->persinv, vec);
580                 
581                 VECADDFAC(ray_start, vec, rv3d->viewinv[2],  1000.0f);
582                 VECADDFAC(ray_end, vec, rv3d->viewinv[2], -1000.0f);
583         }
584
585         /* clipping */
586         if(rv3d->rflag & RV3D_CLIPPING)
587                 for(a=0; a<4; a++)
588                         clip_line_plane(ray_start, ray_end, rv3d->clip[a]);
589 }
590
591 /* create intersection ray in view Z direction at mouse coordinates */
592 void viewray(ARegion *ar, View3D *v3d, float mval[2], float ray_start[3], float ray_normal[3])
593 {
594         float ray_end[3];
595         
596         viewline(ar, v3d, mval, ray_start, ray_end);
597         sub_v3_v3v3(ray_normal, ray_end, ray_start);
598         normalize_v3(ray_normal);
599 }
600
601 void viewvector(RegionView3D *rv3d, float coord[3], float vec[3])
602 {
603         if (rv3d->persp != RV3D_ORTHO)
604         {
605                 float p1[4], p2[4];
606
607                 copy_v3_v3(p1, coord);
608                 p1[3] = 1.0f;
609                 copy_v3_v3(p2, p1);
610                 p2[3] = 1.0f;
611                 mul_m4_v4(rv3d->viewmat, p2);
612
613                 mul_v3_fl(p2, 2.0f);
614
615                 mul_m4_v4(rv3d->viewinv, p2);
616
617                 sub_v3_v3v3(vec, p1, p2);
618         }
619         else {
620                 copy_v3_v3(vec, rv3d->viewinv[2]);
621         }
622         normalize_v3(vec);
623 }
624
625 int initgrabz(RegionView3D *rv3d, float x, float y, float z)
626 {
627         int flip= FALSE;
628         if(rv3d==NULL) return flip;
629         rv3d->zfac= rv3d->persmat[0][3]*x+ rv3d->persmat[1][3]*y+ rv3d->persmat[2][3]*z+ rv3d->persmat[3][3];
630         if (rv3d->zfac < 0.0f)
631                 flip= TRUE;
632         /* if x,y,z is exactly the viewport offset, zfac is 0 and we don't want that 
633                 * (accounting for near zero values)
634                 * */
635         if (rv3d->zfac < 1.e-6f && rv3d->zfac > -1.e-6f) rv3d->zfac = 1.0f;
636         
637         /* Negative zfac means x, y, z was behind the camera (in perspective).
638                 * This gives flipped directions, so revert back to ok default case.
639         */
640         // NOTE: I've changed this to flip zfac to be positive again for now so that GPencil draws ok
641         //      -- Aligorith, 2009Aug31
642         //if (rv3d->zfac < 0.0f) rv3d->zfac = 1.0f;
643         if (rv3d->zfac < 0.0f) rv3d->zfac= -rv3d->zfac;
644         
645         return flip;
646 }
647
648 /* always call initgrabz */
649 void window_to_3d(ARegion *ar, float *vec, short mx, short my)
650 {
651         RegionView3D *rv3d= ar->regiondata;
652         
653         float dx= ((float)(mx-(ar->winx/2)))*rv3d->zfac/(ar->winx/2);
654         float dy= ((float)(my-(ar->winy/2)))*rv3d->zfac/(ar->winy/2);
655         
656         float fz= rv3d->persmat[0][3]*vec[0]+ rv3d->persmat[1][3]*vec[1]+ rv3d->persmat[2][3]*vec[2]+ rv3d->persmat[3][3];
657         fz= fz/rv3d->zfac;
658         
659         vec[0]= (rv3d->persinv[0][0]*dx + rv3d->persinv[1][0]*dy+ rv3d->persinv[2][0]*fz)-rv3d->ofs[0];
660         vec[1]= (rv3d->persinv[0][1]*dx + rv3d->persinv[1][1]*dy+ rv3d->persinv[2][1]*fz)-rv3d->ofs[1];
661         vec[2]= (rv3d->persinv[0][2]*dx + rv3d->persinv[1][2]*dy+ rv3d->persinv[2][2]*fz)-rv3d->ofs[2];
662         
663 }
664
665 /* always call initgrabz */
666 /* only to detect delta motion */
667 void window_to_3d_delta(ARegion *ar, float *vec, short mx, short my)
668 {
669         RegionView3D *rv3d= ar->regiondata;
670         float dx, dy;
671         
672         dx= 2.0f*mx*rv3d->zfac/ar->winx;
673         dy= 2.0f*my*rv3d->zfac/ar->winy;
674         
675         vec[0]= (rv3d->persinv[0][0]*dx + rv3d->persinv[1][0]*dy);
676         vec[1]= (rv3d->persinv[0][1]*dx + rv3d->persinv[1][1]*dy);
677         vec[2]= (rv3d->persinv[0][2]*dx + rv3d->persinv[1][2]*dy);
678 }
679
680 /* doesn't rely on initgrabz */
681 /* for perspective view, get the vector direction to
682  * the mouse cursor as a normalized vector */
683 void window_to_3d_vector(ARegion *ar, float *vec, short mx, short my)
684 {
685         RegionView3D *rv3d= ar->regiondata;
686         float dx, dy;
687         float viewvec[3];
688
689         dx= 2.0f*mx/ar->winx;
690         dy= 2.0f*my/ar->winy;
691
692         /* normalize here so vecs are proportional to eachother */
693         normalize_v3_v3(viewvec, rv3d->viewinv[2]);
694
695         vec[0]= viewvec[0] - (rv3d->persinv[0][0]*dx + rv3d->persinv[1][0]*dy);
696         vec[1]= viewvec[1] - (rv3d->persinv[0][1]*dx + rv3d->persinv[1][1]*dy);
697         vec[2]= viewvec[2] - (rv3d->persinv[0][2]*dx + rv3d->persinv[1][2]*dy);
698
699         normalize_v3(vec);
700 }
701
702 float read_cached_depth(ViewContext *vc, int x, int y)
703 {
704         ViewDepths *vd = vc->rv3d->depths;
705                 
706         x -= vc->ar->winrct.xmin;
707         y -= vc->ar->winrct.ymin;
708
709         if(vd && vd->depths && x > 0 && y > 0 && x < vd->w && y < vd->h)
710                 return vd->depths[y * vd->w + x];
711         else
712                 return 1;
713 }
714
715 void request_depth_update(RegionView3D *rv3d)
716 {
717         if(rv3d->depths)
718                 rv3d->depths->damaged= 1;
719 }
720
721 void view3d_get_object_project_mat(RegionView3D *rv3d, Object *ob, float pmat[4][4])
722 {
723         float vmat[4][4];
724         
725         mul_m4_m4m4(vmat, ob->obmat, rv3d->viewmat);
726         mul_m4_m4m4(pmat, vmat, rv3d->winmat);
727 }
728
729 /* Uses window coordinates (x,y) and depth component z to find a point in
730    modelspace */
731 void view3d_unproject(bglMats *mats, float out[3], const short x, const short y, const float z)
732 {
733         double ux, uy, uz;
734
735                 gluUnProject(x,y,z, mats->modelview, mats->projection,
736                          (GLint *)mats->viewport, &ux, &uy, &uz );
737         out[0] = ux;
738         out[1] = uy;
739         out[2] = uz;
740 }
741
742 /* use above call to get projecting mat */
743 void view3d_project_float(ARegion *ar, float *vec, float *adr, float mat[4][4])
744 {
745         float vec4[4];
746         
747         adr[0]= IS_CLIPPED;
748         copy_v3_v3(vec4, vec);
749         vec4[3]= 1.0;
750         
751         mul_m4_v4(mat, vec4);
752         
753         if( vec4[3]>FLT_EPSILON ) {
754                 adr[0] = (float)(ar->winx/2.0f)+(ar->winx/2.0f)*vec4[0]/vec4[3];        
755                 adr[1] = (float)(ar->winy/2.0f)+(ar->winy/2.0f)*vec4[1]/vec4[3];
756         } else {
757                 adr[0] = adr[1] = 0.0f;
758         }
759 }
760
761 int boundbox_clip(RegionView3D *rv3d, float obmat[][4], BoundBox *bb)
762 {
763         /* return 1: draw */
764         
765         float mat[4][4];
766         float vec[4], min, max;
767         int a, flag= -1, fl;
768         
769         if(bb==NULL) return 1;
770         if(bb->flag & OB_BB_DISABLED) return 1;
771         
772         mul_m4_m4m4(mat, obmat, rv3d->persmat);
773         
774         for(a=0; a<8; a++) {
775                 copy_v3_v3(vec, bb->vec[a]);
776                 vec[3]= 1.0;
777                 mul_m4_v4(mat, vec);
778                 max= vec[3];
779                 min= -vec[3];
780                 
781                 fl= 0;
782                 if(vec[0] < min) fl+= 1;
783                 if(vec[0] > max) fl+= 2;
784                 if(vec[1] < min) fl+= 4;
785                 if(vec[1] > max) fl+= 8;
786                 if(vec[2] < min) fl+= 16;
787                 if(vec[2] > max) fl+= 32;
788                 
789                 flag &= fl;
790                 if(flag==0) return 1;
791         }
792         
793         return 0;
794 }
795
796 void project_short(ARegion *ar, float *vec, short *adr) /* clips */
797 {
798         RegionView3D *rv3d= ar->regiondata;
799         float fx, fy, vec4[4];
800         
801         adr[0]= IS_CLIPPED;
802         
803         if(rv3d->rflag & RV3D_CLIPPING) {
804                 if(view3d_test_clipping(rv3d, vec, 0))
805                         return;
806         }
807         
808         copy_v3_v3(vec4, vec);
809         vec4[3]= 1.0;
810         mul_m4_v4(rv3d->persmat, vec4);
811         
812         if( vec4[3] > (float)BL_NEAR_CLIP ) {   /* 0.001 is the NEAR clipping cutoff for picking */
813                 fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]);
814                 
815                 if( fx>0 && fx<ar->winx) {
816                         
817                         fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]);
818                         
819                         if(fy > 0.0f && fy < (float)ar->winy) {
820                                 adr[0]= (short)floor(fx); 
821                                 adr[1]= (short)floor(fy);
822                         }
823                 }
824         }
825 }
826
827 void project_int(ARegion *ar, float *vec, int *adr)
828 {
829         RegionView3D *rv3d= ar->regiondata;
830         float fx, fy, vec4[4];
831         
832         adr[0]= (int)2140000000.0f;
833         copy_v3_v3(vec4, vec);
834         vec4[3]= 1.0;
835         
836         mul_m4_v4(rv3d->persmat, vec4);
837         
838         if( vec4[3] > (float)BL_NEAR_CLIP ) {   /* 0.001 is the NEAR clipping cutoff for picking */
839                 fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]);
840                 
841                 if( fx>-2140000000.0f && fx<2140000000.0f) {
842                         fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]);
843                         
844                         if(fy>-2140000000.0f && fy<2140000000.0f) {
845                                 adr[0]= (int)floor(fx); 
846                                 adr[1]= (int)floor(fy);
847                         }
848                 }
849         }
850 }
851
852 void project_int_noclip(ARegion *ar, float *vec, int *adr)
853 {
854         RegionView3D *rv3d= ar->regiondata;
855         float fx, fy, vec4[4];
856         
857         copy_v3_v3(vec4, vec);
858         vec4[3]= 1.0;
859         
860         mul_m4_v4(rv3d->persmat, vec4);
861         
862         if( fabs(vec4[3]) > BL_NEAR_CLIP ) {
863                 fx = (ar->winx/2)*(1 + vec4[0]/vec4[3]);
864                 fy = (ar->winy/2)*(1 + vec4[1]/vec4[3]);
865                 
866                 adr[0] = (int)floor(fx); 
867                 adr[1] = (int)floor(fy);
868         }
869         else
870         {
871                 adr[0] = ar->winx / 2;
872                 adr[1] = ar->winy / 2;
873         }
874 }
875
876 void project_short_noclip(ARegion *ar, float *vec, short *adr)
877 {
878         RegionView3D *rv3d= ar->regiondata;
879         float fx, fy, vec4[4];
880         
881         adr[0]= IS_CLIPPED;
882         copy_v3_v3(vec4, vec);
883         vec4[3]= 1.0;
884         
885         mul_m4_v4(rv3d->persmat, vec4);
886         
887         if( vec4[3] > (float)BL_NEAR_CLIP ) {   /* 0.001 is the NEAR clipping cutoff for picking */
888                 fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]);
889                 
890                 if( fx>-32700 && fx<32700) {
891                         
892                         fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]);
893                         
894                         if(fy > -32700.0f && fy < 32700.0f) {
895                                 adr[0]= (short)floor(fx); 
896                                 adr[1]= (short)floor(fy);
897                         }
898                 }
899         }
900 }
901
902 void project_float(ARegion *ar, float *vec, float *adr)
903 {
904         RegionView3D *rv3d= ar->regiondata;
905         float vec4[4];
906         
907         adr[0]= IS_CLIPPED;
908         copy_v3_v3(vec4, vec);
909         vec4[3]= 1.0;
910         
911         mul_m4_v4(rv3d->persmat, vec4);
912         
913         if(vec4[3] > (float)BL_NEAR_CLIP) {
914                 adr[0] = (float)(ar->winx/2.0f)+(ar->winx/2.0f)*vec4[0]/vec4[3];
915                 adr[1] = (float)(ar->winy/2.0f)+(ar->winy/2.0f)*vec4[1]/vec4[3];
916         }
917 }
918
919 void project_float_noclip(ARegion *ar, float *vec, float *adr)
920 {
921         RegionView3D *rv3d= ar->regiondata;
922         float vec4[4];
923         
924         copy_v3_v3(vec4, vec);
925         vec4[3]= 1.0;
926         
927         mul_m4_v4(rv3d->persmat, vec4);
928         
929         if( fabs(vec4[3]) > BL_NEAR_CLIP ) {
930                 adr[0] = (float)(ar->winx/2.0f)+(ar->winx/2.0f)*vec4[0]/vec4[3];
931                 adr[1] = (float)(ar->winy/2.0f)+(ar->winy/2.0f)*vec4[1]/vec4[3];
932         }
933         else
934         {
935                 adr[0] = ar->winx / 2.0f;
936                 adr[1] = ar->winy / 2.0f;
937         }
938 }
939
940 int get_view3d_ortho(View3D *v3d, RegionView3D *rv3d)
941 {
942         Camera *cam;
943
944         if(rv3d->persp==RV3D_CAMOB) {
945                 if(v3d->camera && v3d->camera->type==OB_CAMERA) {
946                         cam= v3d->camera->data;
947
948                         if(cam && cam->type==CAM_ORTHO)
949                                 return 1;
950                         else
951                                 return 0;
952                 }
953                 else
954                         return 0;
955         }
956
957         if(rv3d->persp==RV3D_ORTHO)
958                 return 1;
959
960         return 0;
961 }
962
963 /* copies logic of get_view3d_viewplane(), keep in sync */
964 int get_view3d_cliprange(View3D *v3d, RegionView3D *rv3d, float *clipsta, float *clipend)
965 {
966         int orth= 0;
967
968         *clipsta= v3d->near;
969         *clipend= v3d->far;
970
971         if(rv3d->persp==RV3D_CAMOB) {
972                 if(v3d->camera) {
973                         if(v3d->camera->type==OB_LAMP ) {
974                                 Lamp *la= v3d->camera->data;
975                                 *clipsta= la->clipsta;
976                                 *clipend= la->clipend;
977                         }
978                         else if(v3d->camera->type==OB_CAMERA) {
979                                 Camera *cam= v3d->camera->data;
980                                 *clipsta= cam->clipsta;
981                                 *clipend= cam->clipend;
982
983                                 if(cam->type==CAM_ORTHO)
984                                         orth= 1;
985                         }
986                 }
987         }
988
989         if(rv3d->persp==RV3D_ORTHO) {
990                 *clipend *= 0.5f;       // otherwise too extreme low zbuffer quality
991                 *clipsta= - *clipend;
992                 orth= 1;
993         }
994
995         return orth;
996 }
997
998 /* also exposed in previewrender.c */
999 int get_view3d_viewplane(View3D *v3d, RegionView3D *rv3d, int winxi, int winyi, rctf *viewplane, float *clipsta, float *clipend, float *pixsize)
1000 {
1001         Camera *cam=NULL;
1002         float lens, fac, x1, y1, x2, y2;
1003         float winx= (float)winxi, winy= (float)winyi;
1004         int orth= 0;
1005         
1006         lens= v3d->lens;        
1007         
1008         *clipsta= v3d->near;
1009         *clipend= v3d->far;
1010         
1011         if(rv3d->persp==RV3D_CAMOB) {
1012                 if(v3d->camera) {
1013                         if(v3d->camera->type==OB_LAMP ) {
1014                                 Lamp *la;
1015                                 
1016                                 la= v3d->camera->data;
1017                                 fac= cosf(((float)M_PI)*la->spotsize/360.0f);
1018                                 
1019                                 x1= saacos(fac);
1020                                 lens= 16.0f*fac/sinf(x1);
1021                                 
1022                                 *clipsta= la->clipsta;
1023                                 *clipend= la->clipend;
1024                         }
1025                         else if(v3d->camera->type==OB_CAMERA) {
1026                                 cam= v3d->camera->data;
1027                                 lens= cam->lens;
1028                                 *clipsta= cam->clipsta;
1029                                 *clipend= cam->clipend;
1030                         }
1031                 }
1032         }
1033         
1034         if(rv3d->persp==RV3D_ORTHO) {
1035                 if(winx>winy) x1= -rv3d->dist;
1036                 else x1= -winx*rv3d->dist/winy;
1037                 x2= -x1;
1038                 
1039                 if(winx>winy) y1= -winy*rv3d->dist/winx;
1040                 else y1= -rv3d->dist;
1041                 y2= -y1;
1042                 
1043                 *clipend *= 0.5f;       // otherwise too extreme low zbuffer quality
1044                 *clipsta= - *clipend;
1045                 orth= 1;
1046         }
1047         else {
1048                 /* fac for zoom, also used for camdx */
1049                 if(rv3d->persp==RV3D_CAMOB) {
1050                         fac= (1.41421f + ( (float)rv3d->camzoom )/50.0f);
1051                         fac*= fac;
1052                 }
1053                 else fac= 2.0;
1054                 
1055                 /* viewplane size depends... */
1056                 if(cam && cam->type==CAM_ORTHO) {
1057                         /* ortho_scale == 1 means exact 1 to 1 mapping */
1058                         float dfac= 2.0f*cam->ortho_scale/fac;
1059                         
1060                         if(winx>winy) x1= -dfac;
1061                         else x1= -winx*dfac/winy;
1062                         x2= -x1;
1063                         
1064                         if(winx>winy) y1= -winy*dfac/winx;
1065                         else y1= -dfac;
1066                         y2= -y1;
1067                         orth= 1;
1068                 }
1069                 else {
1070                         float dfac;
1071                         
1072                         if(winx>winy) dfac= 64.0f/(fac*winx*lens);
1073                         else dfac= 64.0f/(fac*winy*lens);
1074                         
1075                         x1= - *clipsta * winx*dfac;
1076                         x2= -x1;
1077                         y1= - *clipsta * winy*dfac;
1078                         y2= -y1;
1079                         orth= 0;
1080                 }
1081                 /* cam view offset */
1082                 if(cam) {
1083                         float dx= 0.5f*fac*rv3d->camdx*(x2-x1);
1084                         float dy= 0.5f*fac*rv3d->camdy*(y2-y1);
1085
1086                         /* shift offset */              
1087                         if(cam->type==CAM_ORTHO) {
1088                                 dx += cam->shiftx * cam->ortho_scale;
1089                                 dy += cam->shifty * cam->ortho_scale;
1090                         }
1091                         else {
1092                                 dx += cam->shiftx * (cam->clipsta / cam->lens) * 32.0f;
1093                                 dy += cam->shifty * (cam->clipsta / cam->lens) * 32.0f;
1094                         }
1095
1096                         x1+= dx;
1097                         x2+= dx;
1098                         y1+= dy;
1099                         y2+= dy;
1100                 }
1101         }
1102         
1103         if(pixsize) {
1104                 float viewfac;
1105                 
1106                 if(orth) {
1107                         viewfac= (winx >= winy)? winx: winy;
1108                         *pixsize= 1.0f/viewfac;
1109                 }
1110                 else {
1111                         viewfac= (((winx >= winy)? winx: winy)*lens)/32.0f;
1112                         *pixsize= *clipsta/viewfac;
1113                 }
1114         }
1115         
1116         viewplane->xmin= x1;
1117         viewplane->ymin= y1;
1118         viewplane->xmax= x2;
1119         viewplane->ymax= y2;
1120         
1121         return orth;
1122 }
1123
1124 void setwinmatrixview3d(ARegion *ar, View3D *v3d, rctf *rect)           /* rect: for picking */
1125 {
1126         RegionView3D *rv3d= ar->regiondata;
1127         rctf viewplane;
1128         float clipsta, clipend, x1, y1, x2, y2;
1129         int orth;
1130         
1131         orth= get_view3d_viewplane(v3d, rv3d, ar->winx, ar->winy, &viewplane, &clipsta, &clipend, NULL);
1132         //      printf("%d %d %f %f %f %f %f %f\n", winx, winy, viewplane.xmin, viewplane.ymin, viewplane.xmax, viewplane.ymax, clipsta, clipend);
1133         x1= viewplane.xmin;
1134         y1= viewplane.ymin;
1135         x2= viewplane.xmax;
1136         y2= viewplane.ymax;
1137         
1138         if(rect) {              /* picking */
1139                 rect->xmin/= (float)ar->winx;
1140                 rect->xmin= x1+rect->xmin*(x2-x1);
1141                 rect->ymin/= (float)ar->winy;
1142                 rect->ymin= y1+rect->ymin*(y2-y1);
1143                 rect->xmax/= (float)ar->winx;
1144                 rect->xmax= x1+rect->xmax*(x2-x1);
1145                 rect->ymax/= (float)ar->winy;
1146                 rect->ymax= y1+rect->ymax*(y2-y1);
1147                 
1148                 if(orth) wmOrtho(rect->xmin, rect->xmax, rect->ymin, rect->ymax, -clipend, clipend);
1149                 else wmFrustum(rect->xmin, rect->xmax, rect->ymin, rect->ymax, clipsta, clipend);
1150                 
1151         }
1152         else {
1153                 if(orth) wmOrtho(x1, x2, y1, y2, clipsta, clipend);
1154                 else wmFrustum(x1, x2, y1, y2, clipsta, clipend);
1155         }
1156
1157         /* update matrix in 3d view region */
1158         glGetFloatv(GL_PROJECTION_MATRIX, (float*)rv3d->winmat);
1159 }
1160
1161 static void obmat_to_viewmat(View3D *v3d, RegionView3D *rv3d, Object *ob, short smooth)
1162 {
1163         float bmat[4][4];
1164         float tmat[3][3];
1165         
1166         rv3d->view= 0; /* dont show the grid */
1167         
1168         copy_m4_m4(bmat, ob->obmat);
1169         normalize_m4(bmat);
1170         invert_m4_m4(rv3d->viewmat, bmat);
1171         
1172         /* view quat calculation, needed for add object */
1173         copy_m3_m4(tmat, rv3d->viewmat);
1174         if (smooth) {
1175                 float new_quat[4];
1176                 if (rv3d->persp==RV3D_CAMOB && v3d->camera) {
1177                         /* were from a camera view */
1178                         
1179                         float orig_ofs[3];
1180                         float orig_dist= rv3d->dist;
1181                         float orig_lens= v3d->lens;
1182                         copy_v3_v3(orig_ofs, rv3d->ofs);
1183                         
1184                         /* Switch from camera view */
1185                         mat3_to_quat( new_quat,tmat);
1186                         
1187                         rv3d->persp=RV3D_PERSP;
1188                         rv3d->dist= 0.0;
1189                         
1190                         view3d_settings_from_ob(v3d->camera, rv3d->ofs, NULL, NULL, &v3d->lens);
1191                         smooth_view(NULL, NULL, NULL, orig_ofs, new_quat, &orig_dist, &orig_lens); // XXX
1192                         
1193                         rv3d->persp=RV3D_CAMOB; /* just to be polite, not needed */
1194                         
1195                 } else {
1196                         mat3_to_quat( new_quat,tmat);
1197                         smooth_view(NULL, NULL, NULL, NULL, new_quat, NULL, NULL); // XXX
1198                 }
1199         } else {
1200                 mat3_to_quat( rv3d->viewquat,tmat);
1201         }
1202 }
1203
1204 #define QUATSET(a, b, c, d, e)  a[0]=b; a[1]=c; a[2]=d; a[3]=e; 
1205
1206 int ED_view3d_lock(RegionView3D *rv3d)
1207 {
1208         switch(rv3d->view) {
1209         case RV3D_VIEW_BOTTOM :
1210                 QUATSET(rv3d->viewquat,0.0, -1.0, 0.0, 0.0);
1211                 break;
1212
1213         case RV3D_VIEW_BACK:
1214                 QUATSET(rv3d->viewquat,0.0, 0.0, (float)-cos(M_PI/4.0), (float)-cos(M_PI/4.0));
1215                 break;
1216
1217         case RV3D_VIEW_LEFT:
1218                 QUATSET(rv3d->viewquat,0.5, -0.5, 0.5, 0.5);
1219                 break;
1220
1221         case RV3D_VIEW_TOP:
1222                 QUATSET(rv3d->viewquat,1.0, 0.0, 0.0, 0.0);
1223                 break;
1224
1225         case RV3D_VIEW_FRONT:
1226                 QUATSET(rv3d->viewquat,(float)cos(M_PI/4.0), (float)-sin(M_PI/4.0), 0.0, 0.0);
1227                 break;
1228
1229         case RV3D_VIEW_RIGHT:
1230                 QUATSET(rv3d->viewquat, 0.5, -0.5, -0.5, -0.5);
1231                 break;
1232         default:
1233                 return FALSE;
1234         }
1235
1236         return TRUE;
1237 }
1238
1239 /* dont set windows active in in here, is used by renderwin too */
1240 void setviewmatrixview3d(Scene *scene, View3D *v3d, RegionView3D *rv3d)
1241 {
1242         if(rv3d->persp==RV3D_CAMOB) {       /* obs/camera */
1243                 if(v3d->camera) {
1244                         where_is_object(scene, v3d->camera);    
1245                         obmat_to_viewmat(v3d, rv3d, v3d->camera, 0);
1246                 }
1247                 else {
1248                         quat_to_mat4( rv3d->viewmat,rv3d->viewquat);
1249                         rv3d->viewmat[3][2]-= rv3d->dist;
1250                 }
1251         }
1252         else {
1253                 /* should be moved to better initialize later on XXX */
1254                 if(rv3d->viewlock)
1255                         ED_view3d_lock(rv3d);
1256                 
1257                 quat_to_mat4( rv3d->viewmat,rv3d->viewquat);
1258                 if(rv3d->persp==RV3D_PERSP) rv3d->viewmat[3][2]-= rv3d->dist;
1259                 if(v3d->ob_centre) {
1260                         Object *ob= v3d->ob_centre;
1261                         float vec[3];
1262                         
1263                         copy_v3_v3(vec, ob->obmat[3]);
1264                         if(ob->type==OB_ARMATURE && v3d->ob_centre_bone[0]) {
1265                                 bPoseChannel *pchan= get_pose_channel(ob->pose, v3d->ob_centre_bone);
1266                                 if(pchan) {
1267                                         copy_v3_v3(vec, pchan->pose_mat[3]);
1268                                         mul_m4_v3(ob->obmat, vec);
1269                                 }
1270                         }
1271                         translate_m4( rv3d->viewmat,-vec[0], -vec[1], -vec[2]);
1272                 }
1273                 else if (v3d->ob_centre_cursor) {
1274                         float vec[3];
1275                         copy_v3_v3(vec, give_cursor(scene, v3d));
1276                         translate_m4(rv3d->viewmat, -vec[0], -vec[1], -vec[2]);
1277                 }
1278                 else translate_m4( rv3d->viewmat,rv3d->ofs[0], rv3d->ofs[1], rv3d->ofs[2]);
1279         }
1280 }
1281
1282 /* IGLuint-> GLuint*/
1283 /* Warning: be sure to account for a negative return value
1284 *   This is an error, "Too many objects in select buffer"
1285 *   and no action should be taken (can crash blender) if this happens
1286 */
1287 short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int bufsize, rcti *input)
1288 {
1289         Scene *scene= vc->scene;
1290         View3D *v3d= vc->v3d;
1291         ARegion *ar= vc->ar;
1292         rctf rect;
1293         short code, hits;
1294         char dt, dtx;
1295         
1296         G.f |= G_PICKSEL;
1297         
1298         /* case not a border select */
1299         if(input->xmin==input->xmax) {
1300                 rect.xmin= input->xmin-12;      // seems to be default value for bones only now
1301                 rect.xmax= input->xmin+12;
1302                 rect.ymin= input->ymin-12;
1303                 rect.ymax= input->ymin+12;
1304         }
1305         else {
1306                 rect.xmin= input->xmin;
1307                 rect.xmax= input->xmax;
1308                 rect.ymin= input->ymin;
1309                 rect.ymax= input->ymax;
1310         }
1311         
1312         setwinmatrixview3d(ar, v3d, &rect);
1313         mul_m4_m4m4(vc->rv3d->persmat, vc->rv3d->viewmat, vc->rv3d->winmat);
1314         
1315         if(v3d->drawtype > OB_WIRE) {
1316                 v3d->zbuf= TRUE;
1317                 glEnable(GL_DEPTH_TEST);
1318         }
1319         
1320         if(vc->rv3d->rflag & RV3D_CLIPPING)
1321                 view3d_set_clipping(vc->rv3d);
1322         
1323         glSelectBuffer( bufsize, (GLuint *)buffer);
1324         glRenderMode(GL_SELECT);
1325         glInitNames();  /* these two calls whatfor? It doesnt work otherwise */
1326         glPushName(-1);
1327         code= 1;
1328         
1329         if(vc->obedit && vc->obedit->type==OB_MBALL) {
1330                 draw_object(scene, ar, v3d, BASACT, DRAW_PICKING|DRAW_CONSTCOLOR);
1331         }
1332         else if((vc->obedit && vc->obedit->type==OB_ARMATURE)) {
1333                 /* if not drawing sketch, draw bones */
1334                 if(!BDR_drawSketchNames(vc)) {
1335                         draw_object(scene, ar, v3d, BASACT, DRAW_PICKING|DRAW_CONSTCOLOR);
1336                 }
1337         }
1338         else {
1339                 Base *base;
1340                 
1341                 v3d->xray= TRUE;        // otherwise it postpones drawing
1342                 for(base= scene->base.first; base; base= base->next) {
1343                         if(base->lay & v3d->lay) {
1344                                 
1345                                 if (base->object->restrictflag & OB_RESTRICT_SELECT)
1346                                         base->selcol= 0;
1347                                 else {
1348                                         base->selcol= code;
1349                                         glLoadName(code);
1350                                         draw_object(scene, ar, v3d, base, DRAW_PICKING|DRAW_CONSTCOLOR);
1351                                         
1352                                         /* we draw group-duplicators for selection too */
1353                                         if((base->object->transflag & OB_DUPLI) && base->object->dup_group) {
1354                                                 ListBase *lb;
1355                                                 DupliObject *dob;
1356                                                 Base tbase;
1357                                                 
1358                                                 tbase.flag= OB_FROMDUPLI;
1359                                                 lb= object_duplilist(scene, base->object);
1360                                                 
1361                                                 for(dob= lb->first; dob; dob= dob->next) {
1362                                                         tbase.object= dob->ob;
1363                                                         copy_m4_m4(dob->ob->obmat, dob->mat);
1364                                                         
1365                                                         /* extra service: draw the duplicator in drawtype of parent */
1366                                                         /* MIN2 for the drawtype to allow bounding box objects in groups for lods */
1367                                                         dt= tbase.object->dt;   tbase.object->dt= MIN2(tbase.object->dt, base->object->dt);
1368                                                         dtx= tbase.object->dtx; tbase.object->dtx= base->object->dtx;
1369
1370                                                         draw_object(scene, ar, v3d, &tbase, DRAW_PICKING|DRAW_CONSTCOLOR);
1371                                                         
1372                                                         tbase.object->dt= dt;
1373                                                         tbase.object->dtx= dtx;
1374
1375                                                         copy_m4_m4(dob->ob->obmat, dob->omat);
1376                                                 }
1377                                                 free_object_duplilist(lb);
1378                                         }
1379                                         code++;
1380                                 }                               
1381                         }
1382                 }
1383                 v3d->xray= FALSE;       // restore
1384         }
1385         
1386         glPopName();    /* see above (pushname) */
1387         hits= glRenderMode(GL_RENDER);
1388         
1389         G.f &= ~G_PICKSEL;
1390         setwinmatrixview3d(ar, v3d, NULL);
1391         mul_m4_m4m4(vc->rv3d->persmat, vc->rv3d->viewmat, vc->rv3d->winmat);
1392         
1393         if(v3d->drawtype > OB_WIRE) {
1394                 v3d->zbuf= 0;
1395                 glDisable(GL_DEPTH_TEST);
1396         }
1397 // XXX  persp(PERSP_WIN);
1398         
1399         if(vc->rv3d->rflag & RV3D_CLIPPING)
1400                 view3d_clr_clipping();
1401         
1402         if(hits<0) printf("Too many objects in select buffer\n");       // XXX make error message
1403         
1404         return hits;
1405 }
1406
1407 /* ********************** local view operator ******************** */
1408
1409 static unsigned int free_localbit(Main *bmain)
1410 {
1411         unsigned int lay;
1412         ScrArea *sa;
1413         bScreen *sc;
1414         
1415         lay= 0;
1416         
1417         /* sometimes we loose a localview: when an area is closed */
1418         /* check all areas: which localviews are in use? */
1419         for(sc= bmain->screen.first; sc; sc= sc->id.next) {
1420                 for(sa= sc->areabase.first; sa; sa= sa->next) {
1421                         SpaceLink *sl= sa->spacedata.first;
1422                         for(; sl; sl= sl->next) {
1423                                 if(sl->spacetype==SPACE_VIEW3D) {
1424                                         View3D *v3d= (View3D*) sl;
1425                                         lay |= v3d->lay;
1426                                 }
1427                         }
1428                 }
1429         }
1430         
1431         if( (lay & 0x01000000)==0) return 0x01000000;
1432         if( (lay & 0x02000000)==0) return 0x02000000;
1433         if( (lay & 0x04000000)==0) return 0x04000000;
1434         if( (lay & 0x08000000)==0) return 0x08000000;
1435         if( (lay & 0x10000000)==0) return 0x10000000;
1436         if( (lay & 0x20000000)==0) return 0x20000000;
1437         if( (lay & 0x40000000)==0) return 0x40000000;
1438         if( (lay & 0x80000000)==0) return 0x80000000;
1439         
1440         return 0;
1441 }
1442
1443 int ED_view3d_scene_layer_set(int lay, const int *values, int *active)
1444 {
1445         int i, tot= 0;
1446         
1447         /* ensure we always have some layer selected */
1448         for(i=0; i<20; i++)
1449                 if(values[i])
1450                         tot++;
1451         
1452         if(tot==0)
1453                 return lay;
1454         
1455         for(i=0; i<20; i++) {
1456                 
1457                 if (active) {
1458                         /* if this value has just been switched on, make that layer active */
1459                         if (values[i] && (lay & (1<<i))==0) {
1460                                 *active = (1<<i);
1461                         }
1462                 }
1463                         
1464                 if (values[i]) lay |= (1<<i);
1465                 else lay &= ~(1<<i);
1466         }
1467         
1468         /* ensure always an active layer */
1469         if (active && (lay & *active)==0) {
1470                 for(i=0; i<20; i++) {
1471                         if(lay & (1<<i)) {
1472                                 *active= 1<<i;
1473                                 break;
1474                         }
1475                 }
1476         }
1477         
1478         return lay;
1479 }
1480
1481 static void initlocalview(Main *bmain, Scene *scene, ScrArea *sa)
1482 {
1483         View3D *v3d= sa->spacedata.first;
1484         Base *base;
1485         float size = 0.0, min[3], max[3], box[3];
1486         unsigned int locallay;
1487         int ok=0;
1488
1489         if(v3d->localvd) return;
1490
1491         INIT_MINMAX(min, max);
1492
1493         locallay= free_localbit(bmain);
1494
1495         if(locallay==0) {
1496                 printf("Sorry, no more than 8 localviews\n");   // XXX error 
1497                 ok= 0;
1498         }
1499         else {
1500                 if(scene->obedit) {
1501                         minmax_object(scene->obedit, min, max);
1502                         
1503                         ok= 1;
1504                 
1505                         BASACT->lay |= locallay;
1506                         scene->obedit->lay= BASACT->lay;
1507                 }
1508                 else {
1509                         for(base= FIRSTBASE; base; base= base->next) {
1510                                 if(TESTBASE(v3d, base))  {
1511                                         minmax_object(base->object, min, max);
1512                                         base->lay |= locallay;
1513                                         base->object->lay= base->lay;
1514                                         ok= 1;
1515                                 }
1516                         }
1517                 }
1518                 
1519                 box[0]= (max[0]-min[0]);
1520                 box[1]= (max[1]-min[1]);
1521                 box[2]= (max[2]-min[2]);
1522                 size= MAX3(box[0], box[1], box[2]);
1523                 if(size <= 0.01f) size= 0.01f;
1524         }
1525         
1526         if(ok) {
1527                 ARegion *ar;
1528                 
1529                 v3d->localvd= MEM_mallocN(sizeof(View3D), "localview");
1530                 
1531                 memcpy(v3d->localvd, v3d, sizeof(View3D));
1532
1533                 for(ar= sa->regionbase.first; ar; ar= ar->next) {
1534                         if(ar->regiontype == RGN_TYPE_WINDOW) {
1535                                 RegionView3D *rv3d= ar->regiondata;
1536
1537                                 rv3d->localvd= MEM_mallocN(sizeof(RegionView3D), "localview region");
1538                                 memcpy(rv3d->localvd, rv3d, sizeof(RegionView3D));
1539                                 
1540                                 rv3d->ofs[0]= -(min[0]+max[0])/2.0f;
1541                                 rv3d->ofs[1]= -(min[1]+max[1])/2.0f;
1542                                 rv3d->ofs[2]= -(min[2]+max[2])/2.0f;
1543
1544                                 rv3d->dist= size;
1545                                 /* perspective should be a bit farther away to look nice */
1546                                 if(rv3d->persp==RV3D_ORTHO)
1547                                         rv3d->dist*= 0.7f;
1548
1549                                 // correction for window aspect ratio
1550                                 if(ar->winy>2 && ar->winx>2) {
1551                                         float asp= (float)ar->winx/(float)ar->winy;
1552                                         if(asp < 1.0f) asp= 1.0f/asp;
1553                                         rv3d->dist*= asp;
1554                                 }
1555                                 
1556                                 if (rv3d->persp==RV3D_CAMOB) rv3d->persp= RV3D_PERSP;
1557                                 
1558                                 v3d->cursor[0]= -rv3d->ofs[0];
1559                                 v3d->cursor[1]= -rv3d->ofs[1];
1560                                 v3d->cursor[2]= -rv3d->ofs[2];
1561                         }
1562                 }
1563                 
1564                 v3d->lay= locallay;
1565         }
1566         else {
1567                 /* clear flags */ 
1568                 for(base= FIRSTBASE; base; base= base->next) {
1569                         if( base->lay & locallay ) {
1570                                 base->lay-= locallay;
1571                                 if(base->lay==0) base->lay= v3d->layact;
1572                                 if(base->object != scene->obedit) base->flag |= SELECT;
1573                                 base->object->lay= base->lay;
1574                         }
1575                 }               
1576         }
1577
1578 }
1579
1580 static void restore_localviewdata(ScrArea *sa, int free)
1581 {
1582         ARegion *ar;
1583         View3D *v3d= sa->spacedata.first;
1584         
1585         if(v3d->localvd==NULL) return;
1586         
1587         v3d->near= v3d->localvd->near;
1588         v3d->far= v3d->localvd->far;
1589         v3d->lay= v3d->localvd->lay;
1590         v3d->layact= v3d->localvd->layact;
1591         v3d->drawtype= v3d->localvd->drawtype;
1592         v3d->camera= v3d->localvd->camera;
1593         
1594         if(free) {
1595                 MEM_freeN(v3d->localvd);
1596                 v3d->localvd= NULL;
1597         }
1598         
1599         for(ar= sa->regionbase.first; ar; ar= ar->next) {
1600                 if(ar->regiontype == RGN_TYPE_WINDOW) {
1601                         RegionView3D *rv3d= ar->regiondata;
1602                         
1603                         if(rv3d->localvd) {
1604                                 rv3d->dist= rv3d->localvd->dist;
1605                                 copy_v3_v3(rv3d->ofs, rv3d->localvd->ofs);
1606                                 copy_qt_qt(rv3d->viewquat, rv3d->localvd->viewquat);
1607                                 rv3d->view= rv3d->localvd->view;
1608                                 rv3d->persp= rv3d->localvd->persp;
1609                                 rv3d->camzoom= rv3d->localvd->camzoom;
1610
1611                                 if(free) {
1612                                         MEM_freeN(rv3d->localvd);
1613                                         rv3d->localvd= NULL;
1614                                 }
1615                         }
1616                 }
1617         }
1618 }
1619
1620 static void endlocalview(Scene *scene, ScrArea *sa)
1621 {
1622         View3D *v3d= sa->spacedata.first;
1623         struct Base *base;
1624         unsigned int locallay;
1625         
1626         if(v3d->localvd) {
1627                 
1628                 locallay= v3d->lay & 0xFF000000;
1629                 
1630                 restore_localviewdata(sa, 1); // 1 = free
1631
1632                 /* for when in other window the layers have changed */
1633                 if(v3d->scenelock) v3d->lay= scene->lay;
1634                 
1635                 for(base= FIRSTBASE; base; base= base->next) {
1636                         if( base->lay & locallay ) {
1637                                 base->lay-= locallay;
1638                                 if(base->lay==0) base->lay= v3d->layact;
1639                                 if(base->object != scene->obedit) {
1640                                         base->flag |= SELECT;
1641                                         base->object->flag |= SELECT;
1642                                 }
1643                                 base->object->lay= base->lay;
1644                         }
1645                 }
1646         } 
1647 }
1648
1649 static int localview_exec(bContext *C, wmOperator *UNUSED(unused))
1650 {
1651         View3D *v3d= CTX_wm_view3d(C);
1652         
1653         if(v3d->localvd)
1654                 endlocalview(CTX_data_scene(C), CTX_wm_area(C));
1655         else
1656                 initlocalview(CTX_data_main(C), CTX_data_scene(C), CTX_wm_area(C));
1657         
1658         ED_area_tag_redraw(CTX_wm_area(C));
1659         
1660         return OPERATOR_FINISHED;
1661 }
1662
1663 void VIEW3D_OT_localview(wmOperatorType *ot)
1664 {
1665         
1666         /* identifiers */
1667         ot->name= "Local View";
1668         ot->description= "Toggle display of selected object(s) separately and centered in view";
1669         ot->idname= "VIEW3D_OT_localview";
1670         
1671         /* api callbacks */
1672         ot->exec= localview_exec;
1673         ot->flag= OPTYPE_UNDO; /* localview changes object layer bitflags */
1674         
1675         ot->poll= ED_operator_view3d_active;
1676 }
1677
1678 #ifdef WITH_GAMEENGINE
1679
1680 static ListBase queue_back;
1681 static void SaveState(bContext *C, wmWindow *win)
1682 {
1683         Object *obact = CTX_data_active_object(C);
1684         
1685         glPushAttrib(GL_ALL_ATTRIB_BITS);
1686
1687         if(obact && obact->mode & OB_MODE_TEXTURE_PAINT)
1688                 GPU_paint_set_mipmap(1);
1689         
1690         queue_back= win->queue;
1691         
1692         win->queue.first= win->queue.last= NULL;
1693         
1694         //XXX waitcursor(1);
1695 }
1696
1697 static void RestoreState(bContext *C, wmWindow *win)
1698 {
1699         Object *obact = CTX_data_active_object(C);
1700         
1701         if(obact && obact->mode & OB_MODE_TEXTURE_PAINT)
1702                 GPU_paint_set_mipmap(0);
1703
1704         //XXX curarea->win_swap = 0;
1705         //XXX curarea->head_swap=0;
1706         //XXX allqueue(REDRAWVIEW3D, 1);
1707         //XXX allqueue(REDRAWBUTSALL, 0);
1708         //XXX reset_slowparents();
1709         //XXX waitcursor(0);
1710         //XXX G.qual= 0;
1711         
1712         if(win) /* check because closing win can set to NULL */
1713                 win->queue= queue_back;
1714         
1715         GPU_state_init();
1716         GPU_set_tpage(NULL, 0);
1717
1718         glPopAttrib();
1719 }
1720
1721 /* was space_set_commmandline_options in 2.4x */
1722 static void game_set_commmandline_options(GameData *gm)
1723 {
1724         SYS_SystemHandle syshandle;
1725         int test;
1726
1727         if ( (syshandle = SYS_GetSystem()) ) {
1728                 /* User defined settings */
1729                 test= (U.gameflags & USER_DISABLE_MIPMAP);
1730                 GPU_set_mipmap(!test);
1731                 SYS_WriteCommandLineInt(syshandle, "nomipmap", test);
1732
1733                 /* File specific settings: */
1734                 /* Only test the first one. These two are switched
1735                  * simultaneously. */
1736                 test= (gm->flag & GAME_SHOW_FRAMERATE);
1737                 SYS_WriteCommandLineInt(syshandle, "show_framerate", test);
1738                 SYS_WriteCommandLineInt(syshandle, "show_profile", test);
1739
1740                 test = (gm->flag & GAME_SHOW_DEBUG_PROPS);
1741                 SYS_WriteCommandLineInt(syshandle, "show_properties", test);
1742
1743                 test= (gm->flag & GAME_SHOW_PHYSICS);
1744                 SYS_WriteCommandLineInt(syshandle, "show_physics", test);
1745
1746                 test= (gm->flag & GAME_ENABLE_ALL_FRAMES);
1747                 SYS_WriteCommandLineInt(syshandle, "fixedtime", test);
1748
1749                 test= (gm->flag & GAME_ENABLE_ANIMATION_RECORD);
1750                 SYS_WriteCommandLineInt(syshandle, "animation_record", test);
1751
1752                 test= (gm->flag & GAME_IGNORE_DEPRECATION_WARNINGS);
1753                 SYS_WriteCommandLineInt(syshandle, "ignore_deprecation_warnings", test);
1754
1755                 test= (gm->matmode == GAME_MAT_MULTITEX);
1756                 SYS_WriteCommandLineInt(syshandle, "blender_material", test);
1757                 test= (gm->matmode == GAME_MAT_GLSL);
1758                 SYS_WriteCommandLineInt(syshandle, "blender_glsl_material", test);
1759                 test= (gm->flag & GAME_DISPLAY_LISTS);
1760                 SYS_WriteCommandLineInt(syshandle, "displaylists", test);
1761
1762
1763         }
1764 }
1765
1766 /* maybe we need this defined somewhere else */
1767 extern void StartKetsjiShell(struct bContext *C, struct ARegion *ar, rcti *cam_frame, int always_use_expand_framing);
1768
1769 #endif // WITH_GAMEENGINE
1770
1771 static int game_engine_poll(bContext *C)
1772 {
1773         /* we need a context and area to launch BGE
1774         it's a temporary solution to avoid crash at load time
1775         if we try to auto run the BGE. Ideally we want the
1776         context to be set as soon as we load the file. */
1777
1778         if(CTX_wm_window(C)==NULL) return 0;
1779         if(CTX_wm_screen(C)==NULL) return 0;
1780         if(CTX_wm_area(C)==NULL) return 0;
1781
1782         if(CTX_data_mode_enum(C)!=CTX_MODE_OBJECT)
1783                 return 0;
1784
1785         return 1;
1786 }
1787
1788 int ED_view3d_context_activate(bContext *C)
1789 {
1790         bScreen *sc= CTX_wm_screen(C);
1791         ScrArea *sa= CTX_wm_area(C);
1792         ARegion *ar;
1793
1794         /* sa can be NULL when called from python */
1795         if(sa==NULL || sa->spacetype != SPACE_VIEW3D)
1796                 for(sa=sc->areabase.first; sa; sa= sa->next)
1797                         if(sa->spacetype==SPACE_VIEW3D)
1798                                 break;
1799
1800         if(!sa)
1801                 return 0;
1802         
1803         for(ar=sa->regionbase.first; ar; ar=ar->next)
1804                 if(ar->regiontype == RGN_TYPE_WINDOW)
1805                         break;
1806         
1807         if(!ar)
1808                 return 0;
1809         
1810         // bad context switch ..
1811         CTX_wm_area_set(C, sa);
1812         CTX_wm_region_set(C, ar);
1813
1814         return 1;
1815 }
1816
1817 static int game_engine_exec(bContext *C, wmOperator *op)
1818 {
1819 #ifdef WITH_GAMEENGINE
1820         Scene *startscene = CTX_data_scene(C);
1821         ScrArea *sa, *prevsa= CTX_wm_area(C);
1822         ARegion *ar, *prevar= CTX_wm_region(C);
1823         wmWindow *prevwin= CTX_wm_window(C);
1824         RegionView3D *rv3d;
1825         rcti cam_frame;
1826
1827         (void)op; /* unused */
1828         
1829         // bad context switch ..
1830         if(!ED_view3d_context_activate(C))
1831                 return OPERATOR_CANCELLED;
1832         
1833         rv3d= CTX_wm_region_view3d(C);
1834         sa= CTX_wm_area(C);
1835         ar= CTX_wm_region(C);
1836
1837         view3d_operator_needs_opengl(C);
1838         
1839         game_set_commmandline_options(&startscene->gm);
1840
1841         if(rv3d->persp==RV3D_CAMOB && startscene->gm.framing.type == SCE_GAMEFRAMING_BARS && startscene->gm.stereoflag != STEREO_DOME) { /* Letterbox */
1842                 rctf cam_framef;
1843                 view3d_calc_camera_border(startscene, ar, rv3d, CTX_wm_view3d(C), &cam_framef, FALSE);
1844                 cam_frame.xmin = cam_framef.xmin + ar->winrct.xmin;
1845                 cam_frame.xmax = cam_framef.xmax + ar->winrct.xmin;
1846                 cam_frame.ymin = cam_framef.ymin + ar->winrct.ymin;
1847                 cam_frame.ymax = cam_framef.ymax + ar->winrct.ymin;
1848                 BLI_isect_rcti(&ar->winrct, &cam_frame, &cam_frame);
1849         }
1850         else {
1851                 cam_frame.xmin = ar->winrct.xmin;
1852                 cam_frame.xmax = ar->winrct.xmax;
1853                 cam_frame.ymin = ar->winrct.ymin;
1854                 cam_frame.ymax = ar->winrct.ymax;
1855         }
1856
1857
1858         SaveState(C, prevwin);
1859
1860         StartKetsjiShell(C, ar, &cam_frame, 1);
1861
1862         /* window wasnt closed while the BGE was running */
1863         if(BLI_findindex(&CTX_wm_manager(C)->windows, prevwin) == -1) {
1864                 prevwin= NULL;
1865                 CTX_wm_window_set(C, NULL);
1866         }
1867         
1868         if(prevwin) {
1869                 /* restore context, in case it changed in the meantime, for
1870                    example by working in another window or closing it */
1871                 CTX_wm_region_set(C, prevar);
1872                 CTX_wm_window_set(C, prevwin);
1873                 CTX_wm_area_set(C, prevsa);
1874         }
1875
1876         RestoreState(C, prevwin);
1877
1878         //XXX restore_all_scene_cfra(scene_cfra_store);
1879         set_scene_bg(CTX_data_main(C), startscene);
1880         //XXX scene_update_for_newframe(bmain, scene, scene->lay);
1881         
1882         ED_area_tag_redraw(CTX_wm_area(C));
1883
1884         return OPERATOR_FINISHED;
1885 #else
1886         (void)C; /* unused */
1887         BKE_report(op->reports, RPT_ERROR, "Game engine is disabled in this build.");
1888         return OPERATOR_CANCELLED;
1889 #endif
1890 }
1891
1892 void VIEW3D_OT_game_start(wmOperatorType *ot)
1893 {
1894         
1895         /* identifiers */
1896         ot->name= "Start Game Engine";
1897         ot->description= "Start game engine";
1898         ot->idname= "VIEW3D_OT_game_start";
1899         
1900         /* api callbacks */
1901         ot->exec= game_engine_exec;
1902         
1903         ot->poll= game_engine_poll;
1904 }
1905
1906 /* ************************************** */
1907
1908 void view3d_align_axis_to_vector(View3D *v3d, RegionView3D *rv3d, int axisidx, float vec[3])
1909 {
1910         float alignaxis[3] = {0.0, 0.0, 0.0};
1911         float norm[3], axis[3], angle, new_quat[4];
1912         
1913         if(axisidx > 0) alignaxis[axisidx-1]= 1.0;
1914         else alignaxis[-axisidx-1]= -1.0;
1915
1916         normalize_v3_v3(norm, vec);
1917
1918         angle= (float)acos(dot_v3v3(alignaxis, norm));
1919         cross_v3_v3v3(axis, alignaxis, norm);
1920         axis_angle_to_quat( new_quat,axis, -angle);
1921         
1922         rv3d->view= 0;
1923         
1924         if (rv3d->persp==RV3D_CAMOB && v3d->camera) {
1925                 /* switch out of camera view */
1926                 float orig_ofs[3];
1927                 float orig_dist= rv3d->dist;
1928                 float orig_lens= v3d->lens;
1929                 
1930                 copy_v3_v3(orig_ofs, rv3d->ofs);
1931                 rv3d->persp= RV3D_PERSP;
1932                 rv3d->dist= 0.0;
1933                 view3d_settings_from_ob(v3d->camera, rv3d->ofs, NULL, NULL, &v3d->lens);
1934                 smooth_view(NULL, NULL, NULL, orig_ofs, new_quat, &orig_dist, &orig_lens); // XXX
1935         } else {
1936                 if (rv3d->persp==RV3D_CAMOB) rv3d->persp= RV3D_PERSP; /* switch out of camera mode */
1937                 smooth_view(NULL, NULL, NULL, NULL, new_quat, NULL, NULL); // XXX
1938         }
1939 }
1940
1941 int view3d_is_ortho(View3D *v3d, RegionView3D *rv3d)
1942 {
1943         return (rv3d->persp == RV3D_ORTHO || (v3d->camera && ((Camera *)v3d->camera->data)->type == CAM_ORTHO));
1944 }
1945
1946 float view3d_pixel_size(struct RegionView3D *rv3d, const float co[3])
1947 {
1948         return  (rv3d->persmat[3][3] + (
1949                                 rv3d->persmat[0][3]*co[0] +
1950                                 rv3d->persmat[1][3]*co[1] +
1951                                 rv3d->persmat[2][3]*co[2])
1952                         ) * rv3d->pixsize;
1953 }