code cleanup:
[blender.git] / source / blender / editors / space_view3d / view3d_view.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version. 
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2008 Blender Foundation.
19  * All rights reserved.
20  *
21  * 
22  * Contributor(s): Blender Foundation
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 /** \file blender/editors/space_view3d/view3d_view.c
28  *  \ingroup spview3d
29  */
30
31
32 #include "DNA_camera_types.h"
33 #include "DNA_scene_types.h"
34 #include "DNA_object_types.h"
35 #include "DNA_lamp_types.h"
36
37 #include "MEM_guardedalloc.h"
38
39 #include "BLI_math.h"
40 #include "BLI_rect.h"
41 #include "BLI_listbase.h"
42 #include "BLI_utildefines.h"
43
44 #include "BKE_anim.h"
45 #include "BKE_action.h"
46 #include "BKE_camera.h"
47 #include "BKE_context.h"
48 #include "BKE_depsgraph.h"
49 #include "BKE_object.h"
50 #include "BKE_global.h"
51 #include "BKE_main.h"
52 #include "BKE_report.h"
53 #include "BKE_scene.h"
54 #include "BKE_screen.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 "BL_System.h"
69 #endif
70
71 #include "RNA_access.h"
72 #include "RNA_define.h"
73
74 #include "view3d_intern.h"  /* own include */
75
76 /* use this call when executing an operator,
77  * event system doesn't set for each event the
78  * opengl drawing context */
79 void view3d_operator_needs_opengl(const bContext *C)
80 {
81         wmWindow *win = CTX_wm_window(C);
82         ARegion *ar = CTX_wm_region(C);
83         
84         view3d_region_operator_needs_opengl(win, ar);
85 }
86
87 void view3d_region_operator_needs_opengl(wmWindow *win, ARegion *ar)
88 {
89         /* for debugging purpose, context should always be OK */
90         if ((ar == NULL) || (ar->regiontype != RGN_TYPE_WINDOW)) {
91                 printf("view3d_region_operator_needs_opengl error, wrong region\n");
92         }
93         else {
94                 RegionView3D *rv3d = ar->regiondata;
95                 
96                 wmSubWindowSet(win, ar->swinid);
97                 glMatrixMode(GL_PROJECTION);
98                 glLoadMatrixf(rv3d->winmat);
99                 glMatrixMode(GL_MODELVIEW);
100                 glLoadMatrixf(rv3d->viewmat);
101         }
102 }
103
104 float *give_cursor(Scene *scene, View3D *v3d)
105 {
106         if (v3d && v3d->localvd) return v3d->cursor;
107         else return scene->cursor;
108 }
109
110
111 /* ****************** smooth view operator ****************** */
112 /* This operator is one of the 'timer refresh' ones like animation playback */
113
114 struct SmoothView3DStore {
115         float orig_dist, new_dist;
116         float orig_lens, new_lens;
117         float orig_quat[4], new_quat[4];
118         float orig_ofs[3], new_ofs[3];
119         
120         int to_camera, orig_view;
121         
122         double time_allowed;
123 };
124
125 /* will start timer if appropriate */
126 /* the arguments are the desired situation */
127 void view3d_smooth_view(bContext *C, View3D *v3d, ARegion *ar, Object *oldcamera, Object *camera,
128                         float *ofs, float *quat, float *dist, float *lens)
129 {
130         wmWindowManager *wm = CTX_wm_manager(C);
131         wmWindow *win = CTX_wm_window(C);
132         ScrArea *sa = CTX_wm_area(C);
133
134         RegionView3D *rv3d = ar->regiondata;
135         struct SmoothView3DStore sms = {0};
136         short ok = FALSE;
137         
138         /* initialize sms */
139         copy_v3_v3(sms.new_ofs, rv3d->ofs);
140         copy_qt_qt(sms.new_quat, rv3d->viewquat);
141         sms.new_dist = rv3d->dist;
142         sms.new_lens = v3d->lens;
143         sms.to_camera = FALSE;
144
145         /* note on camera locking, this is a little confusing but works ok.
146          * we may be changing the view 'as if' there is no active camera, but in fact
147          * there is an active camera which is locked to the view.
148          *
149          * In the case where smooth view is moving _to_ a camera we don't want that
150          * camera to be moved or changed, so only when the camera is not being set should
151          * we allow camera option locking to initialize the view settings from the camera.
152          */
153         if (camera == NULL && oldcamera == NULL) {
154                 ED_view3d_camera_lock_init(v3d, rv3d);
155         }
156
157         /* store the options we want to end with */
158         if (ofs) copy_v3_v3(sms.new_ofs, ofs);
159         if (quat) copy_qt_qt(sms.new_quat, quat);
160         if (dist) sms.new_dist = *dist;
161         if (lens) sms.new_lens = *lens;
162
163         if (camera) {
164                 ED_view3d_from_object(camera, sms.new_ofs, sms.new_quat, &sms.new_dist, &sms.new_lens);
165                 sms.to_camera = TRUE; /* restore view3d values in end */
166         }
167         
168         if (C && U.smooth_viewtx) {
169                 int changed = FALSE; /* zero means no difference */
170                 
171                 if (oldcamera != camera)
172                         changed = TRUE;
173                 else if (sms.new_dist != rv3d->dist)
174                         changed = TRUE;
175                 else if (sms.new_lens != v3d->lens)
176                         changed = TRUE;
177                 else if (!equals_v3v3(sms.new_ofs, rv3d->ofs))
178                         changed = TRUE;
179                 else if (!equals_v4v4(sms.new_quat, rv3d->viewquat))
180                         changed = TRUE;
181                 
182                 /* The new view is different from the old one
183                  * so animate the view */
184                 if (changed) {
185
186                         /* original values */
187                         if (oldcamera) {
188                                 sms.orig_dist = rv3d->dist;  /* below function does weird stuff with it... */
189                                 ED_view3d_from_object(oldcamera, sms.orig_ofs, sms.orig_quat, &sms.orig_dist, &sms.orig_lens);
190                         }
191                         else {
192                                 copy_v3_v3(sms.orig_ofs, rv3d->ofs);
193                                 copy_qt_qt(sms.orig_quat, rv3d->viewquat);
194                                 sms.orig_dist = rv3d->dist;
195                                 sms.orig_lens = v3d->lens;
196                         }
197                         /* grid draw as floor */
198                         if ((rv3d->viewlock & RV3D_LOCKED) == 0) {
199                                 /* use existing if exists, means multiple calls to smooth view wont loose the original 'view' setting */
200                                 sms.orig_view = rv3d->sms ? rv3d->sms->orig_view : rv3d->view;
201                                 rv3d->view = RV3D_VIEW_USER;
202                         }
203
204                         sms.time_allowed = (double)U.smooth_viewtx / 1000.0;
205                         
206                         /* if this is view rotation only
207                          * we can decrease the time allowed by
208                          * the angle between quats 
209                          * this means small rotations wont lag */
210                         if (quat && !ofs && !dist) {
211                                 float vec1[3] = {0, 0, 1}, vec2[3] = {0, 0, 1};
212                                 float q1[4], q2[4];
213
214                                 invert_qt_qt(q1, sms.new_quat);
215                                 invert_qt_qt(q2, sms.orig_quat);
216
217                                 mul_qt_v3(q1, vec1);
218                                 mul_qt_v3(q2, vec2);
219
220                                 /* scale the time allowed by the rotation */
221                                 sms.time_allowed *= (double)angle_v3v3(vec1, vec2) / M_PI; /* 180deg == 1.0 */
222                         }
223
224                         /* ensure it shows correct */
225                         if (sms.to_camera) rv3d->persp = RV3D_PERSP;
226
227                         rv3d->rflag |= RV3D_NAVIGATING;
228                         
229                         /* keep track of running timer! */
230                         if (rv3d->sms == NULL)
231                                 rv3d->sms = MEM_mallocN(sizeof(struct SmoothView3DStore), "smoothview v3d");
232                         *rv3d->sms = sms;
233                         if (rv3d->smooth_timer)
234                                 WM_event_remove_timer(wm, win, rv3d->smooth_timer);
235                         /* TIMER1 is hardcoded in keymap */
236                         rv3d->smooth_timer = WM_event_add_timer(wm, win, TIMER1, 1.0 / 100.0); /* max 30 frs/sec */
237                         
238                         ok = TRUE;
239                 }
240         }
241         
242         /* if we get here nothing happens */
243         if (ok == FALSE) {
244                 if (sms.to_camera == FALSE) {
245                         copy_v3_v3(rv3d->ofs, sms.new_ofs);
246                         copy_qt_qt(rv3d->viewquat, sms.new_quat);
247                         rv3d->dist = sms.new_dist;
248                         v3d->lens = sms.new_lens;
249                 }
250
251                 ED_view3d_camera_lock_sync(v3d, rv3d);
252
253                 if (rv3d->viewlock & RV3D_BOXVIEW)
254                         view3d_boxview_copy(sa, ar);
255
256                 ED_region_tag_redraw(ar);
257         }
258 }
259
260 /* only meant for timer usage */
261 static int view3d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
262 {
263         View3D *v3d = CTX_wm_view3d(C);
264         RegionView3D *rv3d = CTX_wm_region_view3d(C);
265         struct SmoothView3DStore *sms = rv3d->sms;
266         float step, step_inv;
267         
268         /* escape if not our timer */
269         if (rv3d->smooth_timer == NULL || rv3d->smooth_timer != event->customdata)
270                 return OPERATOR_PASS_THROUGH;
271         
272         if (sms->time_allowed != 0.0)
273                 step = (float)((rv3d->smooth_timer->duration) / sms->time_allowed);
274         else
275                 step = 1.0f;
276         
277         /* end timer */
278         if (step >= 1.0f) {
279                 
280                 /* if we went to camera, store the original */
281                 if (sms->to_camera) {
282                         rv3d->persp = RV3D_CAMOB;
283                         copy_v3_v3(rv3d->ofs, sms->orig_ofs);
284                         copy_qt_qt(rv3d->viewquat, sms->orig_quat);
285                         rv3d->dist = sms->orig_dist;
286                         v3d->lens = sms->orig_lens;
287                 }
288                 else {
289                         copy_v3_v3(rv3d->ofs, sms->new_ofs);
290                         copy_qt_qt(rv3d->viewquat, sms->new_quat);
291                         rv3d->dist = sms->new_dist;
292                         v3d->lens = sms->new_lens;
293
294                         ED_view3d_camera_lock_sync(v3d, rv3d);
295                 }
296                 
297                 if ((rv3d->viewlock & RV3D_LOCKED) == 0) {
298                         rv3d->view = sms->orig_view;
299                 }
300
301                 MEM_freeN(rv3d->sms);
302                 rv3d->sms = NULL;
303                 
304                 WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), rv3d->smooth_timer);
305                 rv3d->smooth_timer = NULL;
306                 rv3d->rflag &= ~RV3D_NAVIGATING;
307         }
308         else {
309                 /* ease in/out */
310                 step = (3.0f * step * step - 2.0f * step * step * step);
311
312                 step_inv = 1.0f - step;
313
314                 interp_v3_v3v3(rv3d->ofs,      sms->orig_ofs,  sms->new_ofs,  step);
315                 interp_qt_qtqt(rv3d->viewquat, sms->orig_quat, sms->new_quat, step);
316                 
317                 rv3d->dist = sms->new_dist * step + sms->orig_dist * step_inv;
318                 v3d->lens  = sms->new_lens * step + sms->orig_lens * step_inv;
319
320                 ED_view3d_camera_lock_sync(v3d, rv3d);
321         }
322         
323         if (rv3d->viewlock & RV3D_BOXVIEW)
324                 view3d_boxview_copy(CTX_wm_area(C), CTX_wm_region(C));
325         
326         WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
327         
328         return OPERATOR_FINISHED;
329 }
330
331 void VIEW3D_OT_smoothview(wmOperatorType *ot)
332 {
333         
334         /* identifiers */
335         ot->name = "Smooth View";
336         ot->idname = "VIEW3D_OT_smoothview";
337         ot->description = "The time to animate the change of view (in milliseconds)";
338         
339         /* api callbacks */
340         ot->invoke = view3d_smoothview_invoke;
341         
342         ot->poll = ED_operator_view3d_active;
343 }
344
345 /* ****************** change view operators ****************** */
346
347 static int view3d_camera_to_view_exec(bContext *C, wmOperator *UNUSED(op))
348 {
349         View3D *v3d = CTX_wm_view3d(C);
350         RegionView3D *rv3d = CTX_wm_region_view3d(C);
351         ObjectTfmProtectedChannels obtfm;
352
353         copy_qt_qt(rv3d->lviewquat, rv3d->viewquat);
354         rv3d->lview = rv3d->view;
355         if (rv3d->persp != RV3D_CAMOB) {
356                 rv3d->lpersp = rv3d->persp;
357         }
358
359         BKE_object_tfm_protected_backup(v3d->camera, &obtfm);
360
361         ED_view3d_to_object(v3d->camera, rv3d->ofs, rv3d->viewquat, rv3d->dist);
362
363         BKE_object_tfm_protected_restore(v3d->camera, &obtfm, v3d->camera->protectflag);
364
365         DAG_id_tag_update(&v3d->camera->id, OB_RECALC_OB);
366         rv3d->persp = RV3D_CAMOB;
367         
368         WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, v3d->camera);
369         
370         return OPERATOR_FINISHED;
371
372 }
373
374 static int view3d_camera_to_view_poll(bContext *C)
375 {
376         View3D *v3d = CTX_wm_view3d(C);
377         if (v3d && v3d->camera && v3d->camera->id.lib == NULL) {
378                 RegionView3D *rv3d = CTX_wm_region_view3d(C);
379                 if (rv3d && !rv3d->viewlock) {
380                         return 1;
381                 }
382         }
383
384         return 0;
385 }
386
387 void VIEW3D_OT_camera_to_view(wmOperatorType *ot)
388 {
389         /* identifiers */
390         ot->name = "Align Camera To View";
391         ot->description = "Set camera view to active view";
392         ot->idname = "VIEW3D_OT_camera_to_view";
393         
394         /* api callbacks */
395         ot->exec = view3d_camera_to_view_exec;
396         ot->poll = view3d_camera_to_view_poll;
397         
398         /* flags */
399         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
400 }
401
402 /* unlike VIEW3D_OT_view_selected this is for framing a render and not
403  * meant to take into account vertex/bone selection for eg. */
404 static int view3d_camera_to_view_selected_exec(bContext *C, wmOperator *UNUSED(op))
405 {
406         Scene *scene = CTX_data_scene(C);
407         View3D *v3d = CTX_wm_view3d(C);
408         Object *camera_ob = v3d->camera;
409
410         float r_co[3]; /* the new location to apply */
411
412         /* this function does all the important stuff */
413         if (BKE_camera_view_frame_fit_to_scene(scene, v3d, camera_ob, r_co)) {
414
415                 ObjectTfmProtectedChannels obtfm;
416                 float obmat_new[4][4];
417
418                 copy_m4_m4(obmat_new, camera_ob->obmat);
419                 copy_v3_v3(obmat_new[3], r_co);
420
421                 /* only touch location */
422                 BKE_object_tfm_protected_backup(camera_ob, &obtfm);
423                 BKE_object_apply_mat4(camera_ob, obmat_new, TRUE, TRUE);
424                 BKE_object_tfm_protected_restore(camera_ob, &obtfm, OB_LOCK_SCALE | OB_LOCK_ROT4D);
425
426                 /* notifiers */
427                 DAG_id_tag_update(&camera_ob->id, OB_RECALC_OB);
428                 WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, camera_ob);
429                 return OPERATOR_FINISHED;
430         }
431         else {
432                 return OPERATOR_CANCELLED;
433         }
434 }
435
436 static int view3d_camera_to_view_selected_poll(bContext *C)
437 {
438         View3D *v3d = CTX_wm_view3d(C);
439         if (v3d && v3d->camera && v3d->camera->id.lib == NULL) {
440                 RegionView3D *rv3d = CTX_wm_region_view3d(C);
441                 if (rv3d) {
442                         if (rv3d->is_persp == FALSE) {
443                                 CTX_wm_operator_poll_msg_set(C, "Only valid for a perspective camera view");
444                         }
445                         else if (!rv3d->viewlock) {
446                                 return 1;
447                         }
448                 }
449         }
450
451         return 0;
452 }
453
454 void VIEW3D_OT_camera_to_view_selected(wmOperatorType *ot)
455 {
456         /* identifiers */
457         ot->name = "Camera Fit Frame to Selected";
458         ot->description = "Move the camera so selected objects are framed";
459         ot->idname = "VIEW3D_OT_camera_to_view_selected";
460
461         /* api callbacks */
462         ot->exec = view3d_camera_to_view_selected_exec;
463         ot->poll = view3d_camera_to_view_selected_poll;
464
465         /* flags */
466         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
467 }
468
469
470 static int view3d_setobjectascamera_exec(bContext *C, wmOperator *UNUSED(op))
471 {       
472         View3D *v3d;
473         ARegion *ar;
474         RegionView3D *rv3d;
475
476         Scene *scene = CTX_data_scene(C);
477         Object *ob = CTX_data_active_object(C);
478
479         /* no NULL check is needed, poll checks */
480         ED_view3d_context_user_region(C, &v3d, &ar);
481         rv3d = ar->regiondata;
482
483         if (ob) {
484                 Object *camera_old = (rv3d->persp == RV3D_CAMOB) ? V3D_CAMERA_SCENE(scene, v3d) : NULL;
485                 rv3d->persp = RV3D_CAMOB;
486                 v3d->camera = ob;
487                 if (v3d->scenelock)
488                         scene->camera = ob;
489
490                 if (camera_old != ob) /* unlikely but looks like a glitch when set to the same */
491                         view3d_smooth_view(C, v3d, ar, camera_old, v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, &v3d->lens);
492
493                 WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS | NC_OBJECT | ND_DRAW, CTX_data_scene(C));
494         }
495         
496         return OPERATOR_FINISHED;
497 }
498
499 int ED_operator_rv3d_user_region_poll(bContext *C)
500 {
501         View3D *v3d_dummy;
502         ARegion *ar_dummy;
503
504         return ED_view3d_context_user_region(C, &v3d_dummy, &ar_dummy);
505 }
506
507 void VIEW3D_OT_object_as_camera(wmOperatorType *ot)
508 {
509         
510         /* identifiers */
511         ot->name = "Set Active Object as Camera";
512         ot->description = "Set the active object as the active camera for this view or scene";
513         ot->idname = "VIEW3D_OT_object_as_camera";
514         
515         /* api callbacks */
516         ot->exec = view3d_setobjectascamera_exec;
517         ot->poll = ED_operator_rv3d_user_region_poll;
518         
519         /* flags */
520         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
521 }
522
523 /* ********************************** */
524
525 void ED_view3d_clipping_calc(BoundBox *bb, float planes[4][4], bglMats *mats, const rcti *rect)
526 {
527         float modelview[4][4];
528         double xs, ys, p[3];
529         int val, flip_sign, a;
530
531         /* near zero floating point values can give issues with gluUnProject
532          * in side view on some implementations */
533         if (fabs(mats->modelview[0]) < 1e-6) mats->modelview[0] = 0.0;
534         if (fabs(mats->modelview[5]) < 1e-6) mats->modelview[5] = 0.0;
535
536         /* Set up viewport so that gluUnProject will give correct values */
537         mats->viewport[0] = 0;
538         mats->viewport[1] = 0;
539
540         /* four clipping planes and bounding volume */
541         /* first do the bounding volume */
542         for (val = 0; val < 4; val++) {
543                 xs = (val == 0 || val == 3) ? rect->xmin : rect->xmax;
544                 ys = (val == 0 || val == 1) ? rect->ymin : rect->ymax;
545
546                 gluUnProject(xs, ys, 0.0, mats->modelview, mats->projection, mats->viewport, &p[0], &p[1], &p[2]);
547                 copy_v3fl_v3db(bb->vec[val], p);
548
549                 gluUnProject(xs, ys, 1.0, mats->modelview, mats->projection, mats->viewport, &p[0], &p[1], &p[2]);
550                 copy_v3fl_v3db(bb->vec[4 + val], p);
551         }
552
553         /* verify if we have negative scale. doing the transform before cross
554          * product flips the sign of the vector compared to doing cross product
555          * before transform then, so we correct for that. */
556         for (a = 0; a < 16; a++)
557                 ((float *)modelview)[a] = mats->modelview[a];
558         flip_sign = is_negative_m4(modelview);
559
560         /* then plane equations */
561         for (val = 0; val < 4; val++) {
562
563                 normal_tri_v3(planes[val], bb->vec[val], bb->vec[val == 3 ? 0 : val + 1], bb->vec[val + 4]);
564
565                 if (flip_sign)
566                         negate_v3(planes[val]);
567
568                 planes[val][3] = -planes[val][0] * bb->vec[val][0] -
569                                   planes[val][1] * bb->vec[val][1] -
570                                   planes[val][2] * bb->vec[val][2];
571         }
572 }
573
574
575 int ED_view3d_boundbox_clip(RegionView3D *rv3d, float obmat[][4], BoundBox *bb)
576 {
577         /* return 1: draw */
578
579         float mat[4][4];
580         float vec[4], min, max;
581         int a, flag = -1, fl;
582
583         if (bb == NULL) return 1;
584         if (bb->flag & OB_BB_DISABLED) return 1;
585
586         mult_m4_m4m4(mat, rv3d->persmat, obmat);
587
588         for (a = 0; a < 8; a++) {
589                 copy_v3_v3(vec, bb->vec[a]);
590                 vec[3] = 1.0;
591                 mul_m4_v4(mat, vec);
592                 max = vec[3];
593                 min = -vec[3];
594
595                 fl = 0;
596                 if (vec[0] < min) fl += 1;
597                 if (vec[0] > max) fl += 2;
598                 if (vec[1] < min) fl += 4;
599                 if (vec[1] > max) fl += 8;
600                 if (vec[2] < min) fl += 16;
601                 if (vec[2] > max) fl += 32;
602
603                 flag &= fl;
604                 if (flag == 0) return 1;
605         }
606
607         return 0;
608 }
609
610 float ED_view3d_depth_read_cached(ViewContext *vc, int x, int y)
611 {
612         ViewDepths *vd = vc->rv3d->depths;
613                 
614         x -= vc->ar->winrct.xmin;
615         y -= vc->ar->winrct.ymin;
616
617         if (vd && vd->depths && x > 0 && y > 0 && x < vd->w && y < vd->h)
618                 return vd->depths[y * vd->w + x];
619         else
620                 return 1;
621 }
622
623 void ED_view3d_depth_tag_update(RegionView3D *rv3d)
624 {
625         if (rv3d->depths)
626                 rv3d->depths->damaged = 1;
627 }
628
629 /* copies logic of get_view3d_viewplane(), keep in sync */
630 int ED_view3d_clip_range_get(View3D *v3d, RegionView3D *rv3d, float *clipsta, float *clipend)
631 {
632         CameraParams params;
633
634         BKE_camera_params_init(&params);
635         BKE_camera_params_from_view3d(&params, v3d, rv3d);
636
637         if (clipsta) *clipsta = params.clipsta;
638         if (clipend) *clipend = params.clipend;
639
640         return params.is_ortho;
641 }
642
643 /* also exposed in previewrender.c */
644 int ED_view3d_viewplane_get(View3D *v3d, RegionView3D *rv3d, int winx, int winy,
645                             rctf *viewplane, float *clipsta, float *clipend)
646 {
647         CameraParams params;
648
649         BKE_camera_params_init(&params);
650         BKE_camera_params_from_view3d(&params, v3d, rv3d);
651         BKE_camera_params_compute_viewplane(&params, winx, winy, 1.0f, 1.0f);
652
653         if (viewplane) *viewplane = params.viewplane;
654         if (clipsta) *clipsta = params.clipsta;
655         if (clipend) *clipend = params.clipend;
656         
657         return params.is_ortho;
658 }
659
660 void setwinmatrixview3d(ARegion *ar, View3D *v3d, rctf *rect)       /* rect: for picking */
661 {
662         RegionView3D *rv3d = ar->regiondata;
663         rctf viewplane;
664         float clipsta, clipend, x1, y1, x2, y2;
665         int orth;
666         
667         orth = ED_view3d_viewplane_get(v3d, rv3d, ar->winx, ar->winy, &viewplane, &clipsta, &clipend);
668         rv3d->is_persp = !orth;
669
670 #if 0
671         printf("%s: %d %d %f %f %f %f %f %f\n", __func__, winx, winy,
672                viewplane.xmin, viewplane.ymin, viewplane.xmax, viewplane.ymax,
673                clipsta, clipend);
674 #endif
675
676         x1 = viewplane.xmin;
677         y1 = viewplane.ymin;
678         x2 = viewplane.xmax;
679         y2 = viewplane.ymax;
680
681         if (rect) {  /* picking */
682                 rect->xmin /= (float)ar->winx;
683                 rect->xmin = x1 + rect->xmin * (x2 - x1);
684                 rect->ymin /= (float)ar->winy;
685                 rect->ymin = y1 + rect->ymin * (y2 - y1);
686                 rect->xmax /= (float)ar->winx;
687                 rect->xmax = x1 + rect->xmax * (x2 - x1);
688                 rect->ymax /= (float)ar->winy;
689                 rect->ymax = y1 + rect->ymax * (y2 - y1);
690                 
691                 if (orth) wmOrtho(rect->xmin, rect->xmax, rect->ymin, rect->ymax, -clipend, clipend);
692                 else wmFrustum(rect->xmin, rect->xmax, rect->ymin, rect->ymax, clipsta, clipend);
693                 
694         }
695         else {
696                 if (orth) wmOrtho(x1, x2, y1, y2, clipsta, clipend);
697                 else wmFrustum(x1, x2, y1, y2, clipsta, clipend);
698         }
699
700         /* update matrix in 3d view region */
701         glGetFloatv(GL_PROJECTION_MATRIX, (float *)rv3d->winmat);
702 }
703
704 static void obmat_to_viewmat(View3D *v3d, RegionView3D *rv3d, Object *ob, short smooth)
705 {
706         float bmat[4][4];
707         float tmat[3][3];
708         
709         rv3d->view = RV3D_VIEW_USER; /* don't show the grid */
710         
711         copy_m4_m4(bmat, ob->obmat);
712         normalize_m4(bmat);
713         invert_m4_m4(rv3d->viewmat, bmat);
714         
715         /* view quat calculation, needed for add object */
716         copy_m3_m4(tmat, rv3d->viewmat);
717         if (smooth) {
718                 float new_quat[4];
719                 if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
720                         /* were from a camera view */
721                         
722                         float orig_ofs[3];
723                         float orig_dist = rv3d->dist;
724                         float orig_lens = v3d->lens;
725                         copy_v3_v3(orig_ofs, rv3d->ofs);
726                         
727                         /* Switch from camera view */
728                         mat3_to_quat(new_quat, tmat);
729                         
730                         rv3d->persp = RV3D_PERSP;
731                         rv3d->dist = 0.0;
732                         
733                         ED_view3d_from_object(v3d->camera, rv3d->ofs, NULL, NULL, &v3d->lens);
734                         view3d_smooth_view(NULL, NULL, NULL, NULL, NULL, orig_ofs, new_quat, &orig_dist, &orig_lens); /* XXX */
735
736                         rv3d->persp = RV3D_CAMOB; /* just to be polite, not needed */
737                         
738                 }
739                 else {
740                         mat3_to_quat(new_quat, tmat);
741                         view3d_smooth_view(NULL, NULL, NULL, NULL, NULL, NULL, new_quat, NULL, NULL); /* XXX */
742                 }
743         }
744         else {
745                 mat3_to_quat(rv3d->viewquat, tmat);
746         }
747 }
748
749 #define QUATSET(a, b, c, d, e) { a[0] = b; a[1] = c; a[2] = d; a[3] = e; } (void)0
750
751 int ED_view3d_lock(RegionView3D *rv3d)
752 {
753         switch (rv3d->view) {
754                 case RV3D_VIEW_BOTTOM:
755                         QUATSET(rv3d->viewquat, 0.0, -1.0, 0.0, 0.0);
756                         break;
757
758                 case RV3D_VIEW_BACK:
759                         QUATSET(rv3d->viewquat, 0.0, 0.0, -M_SQRT1_2, -M_SQRT1_2);
760                         break;
761
762                 case RV3D_VIEW_LEFT:
763                         QUATSET(rv3d->viewquat, 0.5, -0.5, 0.5, 0.5);
764                         break;
765
766                 case RV3D_VIEW_TOP:
767                         QUATSET(rv3d->viewquat, 1.0, 0.0, 0.0, 0.0);
768                         break;
769
770                 case RV3D_VIEW_FRONT:
771                         QUATSET(rv3d->viewquat, M_SQRT1_2, -M_SQRT1_2, 0.0, 0.0);
772                         break;
773
774                 case RV3D_VIEW_RIGHT:
775                         QUATSET(rv3d->viewquat, 0.5, -0.5, -0.5, -0.5);
776                         break;
777                 default:
778                         return FALSE;
779         }
780
781         return TRUE;
782 }
783
784 /* don't set windows active in here, is used by renderwin too */
785 void setviewmatrixview3d(Scene *scene, View3D *v3d, RegionView3D *rv3d)
786 {
787         if (rv3d->persp == RV3D_CAMOB) {      /* obs/camera */
788                 if (v3d->camera) {
789                         BKE_object_where_is_calc(scene, v3d->camera);   
790                         obmat_to_viewmat(v3d, rv3d, v3d->camera, 0);
791                 }
792                 else {
793                         quat_to_mat4(rv3d->viewmat, rv3d->viewquat);
794                         rv3d->viewmat[3][2] -= rv3d->dist;
795                 }
796         }
797         else {
798                 /* should be moved to better initialize later on XXX */
799                 if (rv3d->viewlock)
800                         ED_view3d_lock(rv3d);
801                 
802                 quat_to_mat4(rv3d->viewmat, rv3d->viewquat);
803                 if (rv3d->persp == RV3D_PERSP) rv3d->viewmat[3][2] -= rv3d->dist;
804                 if (v3d->ob_centre) {
805                         Object *ob = v3d->ob_centre;
806                         float vec[3];
807                         
808                         copy_v3_v3(vec, ob->obmat[3]);
809                         if (ob->type == OB_ARMATURE && v3d->ob_centre_bone[0]) {
810                                 bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, v3d->ob_centre_bone);
811                                 if (pchan) {
812                                         copy_v3_v3(vec, pchan->pose_mat[3]);
813                                         mul_m4_v3(ob->obmat, vec);
814                                 }
815                         }
816                         translate_m4(rv3d->viewmat, -vec[0], -vec[1], -vec[2]);
817                 }
818                 else if (v3d->ob_centre_cursor) {
819                         float vec[3];
820                         copy_v3_v3(vec, give_cursor(scene, v3d));
821                         translate_m4(rv3d->viewmat, -vec[0], -vec[1], -vec[2]);
822                 }
823                 else translate_m4(rv3d->viewmat, rv3d->ofs[0], rv3d->ofs[1], rv3d->ofs[2]);
824         }
825 }
826
827 /* IGLuint-> GLuint */
828 /* Warning: be sure to account for a negative return value
829  *   This is an error, "Too many objects in select buffer"
830  *   and no action should be taken (can crash blender) if this happens
831  */
832 short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int bufsize, rcti *input)
833 {
834         Scene *scene = vc->scene;
835         View3D *v3d = vc->v3d;
836         ARegion *ar = vc->ar;
837         rctf rect;
838         short code, hits;
839         char dt, dtx;
840         
841         G.f |= G_PICKSEL;
842         
843         /* case not a border select */
844         if (input->xmin == input->xmax) {
845                 rect.xmin = input->xmin - 12;  /* seems to be default value for bones only now */
846                 rect.xmax = input->xmin + 12;
847                 rect.ymin = input->ymin - 12;
848                 rect.ymax = input->ymin + 12;
849         }
850         else {
851                 BLI_rctf_rcti_copy(&rect, input);
852         }
853         
854         setwinmatrixview3d(ar, v3d, &rect);
855         mult_m4_m4m4(vc->rv3d->persmat, vc->rv3d->winmat, vc->rv3d->viewmat);
856         
857         if (v3d->drawtype > OB_WIRE) {
858                 v3d->zbuf = TRUE;
859                 glEnable(GL_DEPTH_TEST);
860         }
861         
862         if (vc->rv3d->rflag & RV3D_CLIPPING)
863                 ED_view3d_clipping_set(vc->rv3d);
864         
865         glSelectBuffer(bufsize, (GLuint *)buffer);
866         glRenderMode(GL_SELECT);
867         glInitNames();  /* these two calls whatfor? It doesnt work otherwise */
868         glPushName(-1);
869         code = 1;
870         
871         if (vc->obedit && vc->obedit->type == OB_MBALL) {
872                 draw_object(scene, ar, v3d, BASACT, DRAW_PICKING | DRAW_CONSTCOLOR);
873         }
874         else if ((vc->obedit && vc->obedit->type == OB_ARMATURE)) {
875                 /* if not drawing sketch, draw bones */
876                 if (!BDR_drawSketchNames(vc)) {
877                         draw_object(scene, ar, v3d, BASACT, DRAW_PICKING | DRAW_CONSTCOLOR);
878                 }
879         }
880         else {
881                 Base *base;
882                 
883                 v3d->xray = TRUE;  /* otherwise it postpones drawing */
884                 for (base = scene->base.first; base; base = base->next) {
885                         if (base->lay & v3d->lay) {
886                                 
887                                 if (base->object->restrictflag & OB_RESTRICT_SELECT)
888                                         base->selcol = 0;
889                                 else {
890                                         base->selcol = code;
891                                         glLoadName(code);
892                                         draw_object(scene, ar, v3d, base, DRAW_PICKING | DRAW_CONSTCOLOR);
893                                         
894                                         /* we draw group-duplicators for selection too */
895                                         if ((base->object->transflag & OB_DUPLI) && base->object->dup_group) {
896                                                 ListBase *lb;
897                                                 DupliObject *dob;
898                                                 Base tbase;
899                                                 
900                                                 tbase.flag = OB_FROMDUPLI;
901                                                 lb = object_duplilist(scene, base->object, FALSE);
902                                                 
903                                                 for (dob = lb->first; dob; dob = dob->next) {
904                                                         tbase.object = dob->ob;
905                                                         copy_m4_m4(dob->ob->obmat, dob->mat);
906                                                         
907                                                         /* extra service: draw the duplicator in drawtype of parent */
908                                                         /* MIN2 for the drawtype to allow bounding box objects in groups for lods */
909                                                         dt = tbase.object->dt;   tbase.object->dt = MIN2(tbase.object->dt, base->object->dt);
910                                                         dtx = tbase.object->dtx; tbase.object->dtx = base->object->dtx;
911
912                                                         draw_object(scene, ar, v3d, &tbase, DRAW_PICKING | DRAW_CONSTCOLOR);
913                                                         
914                                                         tbase.object->dt = dt;
915                                                         tbase.object->dtx = dtx;
916
917                                                         copy_m4_m4(dob->ob->obmat, dob->omat);
918                                                 }
919                                                 free_object_duplilist(lb);
920                                         }
921                                         code++;
922                                 }                               
923                         }
924                 }
925                 v3d->xray = FALSE;  /* restore */
926         }
927         
928         glPopName();    /* see above (pushname) */
929         hits = glRenderMode(GL_RENDER);
930         
931         G.f &= ~G_PICKSEL;
932         setwinmatrixview3d(ar, v3d, NULL);
933         mult_m4_m4m4(vc->rv3d->persmat, vc->rv3d->winmat, vc->rv3d->viewmat);
934         
935         if (v3d->drawtype > OB_WIRE) {
936                 v3d->zbuf = 0;
937                 glDisable(GL_DEPTH_TEST);
938         }
939 // XXX  persp(PERSP_WIN);
940         
941         if (vc->rv3d->rflag & RV3D_CLIPPING)
942                 ED_view3d_clipping_disable();
943         
944         if (hits < 0) printf("Too many objects in select buffer\n");  /* XXX make error message */
945
946         return hits;
947 }
948
949 /* ********************** local view operator ******************** */
950
951 static unsigned int free_localbit(Main *bmain)
952 {
953         unsigned int lay;
954         ScrArea *sa;
955         bScreen *sc;
956         
957         lay = 0;
958         
959         /* sometimes we loose a localview: when an area is closed */
960         /* check all areas: which localviews are in use? */
961         for (sc = bmain->screen.first; sc; sc = sc->id.next) {
962                 for (sa = sc->areabase.first; sa; sa = sa->next) {
963                         SpaceLink *sl = sa->spacedata.first;
964                         for (; sl; sl = sl->next) {
965                                 if (sl->spacetype == SPACE_VIEW3D) {
966                                         View3D *v3d = (View3D *) sl;
967                                         lay |= v3d->lay;
968                                 }
969                         }
970                 }
971         }
972         
973         if ((lay & 0x01000000) == 0) return 0x01000000;
974         if ((lay & 0x02000000) == 0) return 0x02000000;
975         if ((lay & 0x04000000) == 0) return 0x04000000;
976         if ((lay & 0x08000000) == 0) return 0x08000000;
977         if ((lay & 0x10000000) == 0) return 0x10000000;
978         if ((lay & 0x20000000) == 0) return 0x20000000;
979         if ((lay & 0x40000000) == 0) return 0x40000000;
980         if ((lay & 0x80000000) == 0) return 0x80000000;
981         
982         return 0;
983 }
984
985 int ED_view3d_scene_layer_set(int lay, const int *values, int *active)
986 {
987         int i, tot = 0;
988         
989         /* ensure we always have some layer selected */
990         for (i = 0; i < 20; i++)
991                 if (values[i])
992                         tot++;
993         
994         if (tot == 0)
995                 return lay;
996         
997         for (i = 0; i < 20; i++) {
998                 
999                 if (active) {
1000                         /* if this value has just been switched on, make that layer active */
1001                         if (values[i] && (lay & (1 << i)) == 0) {
1002                                 *active = (1 << i);
1003                         }
1004                 }
1005                         
1006                 if (values[i]) lay |= (1 << i);
1007                 else lay &= ~(1 << i);
1008         }
1009         
1010         /* ensure always an active layer */
1011         if (active && (lay & *active) == 0) {
1012                 for (i = 0; i < 20; i++) {
1013                         if (lay & (1 << i)) {
1014                                 *active = 1 << i;
1015                                 break;
1016                         }
1017                 }
1018         }
1019         
1020         return lay;
1021 }
1022
1023 static int view3d_localview_init(Main *bmain, Scene *scene, ScrArea *sa, ReportList *reports)
1024 {
1025         View3D *v3d = sa->spacedata.first;
1026         Base *base;
1027         float size = 0.0, min[3], max[3], box[3];
1028         unsigned int locallay;
1029         int ok = FALSE;
1030
1031         if (v3d->localvd) {
1032                 return ok;
1033         }
1034
1035         INIT_MINMAX(min, max);
1036
1037         locallay = free_localbit(bmain);
1038
1039         if (locallay == 0) {
1040                 BKE_reportf(reports, RPT_ERROR, "No more than 8 local views");
1041                 ok = FALSE;
1042         }
1043         else {
1044                 if (scene->obedit) {
1045                         BKE_object_minmax(scene->obedit, min, max, FALSE);
1046                         
1047                         ok = TRUE;
1048                 
1049                         BASACT->lay |= locallay;
1050                         scene->obedit->lay = BASACT->lay;
1051                 }
1052                 else {
1053                         for (base = FIRSTBASE; base; base = base->next) {
1054                                 if (TESTBASE(v3d, base)) {
1055                                         BKE_object_minmax(base->object, min, max, FALSE);
1056                                         base->lay |= locallay;
1057                                         base->object->lay = base->lay;
1058                                         ok = TRUE;
1059                                 }
1060                         }
1061                 }
1062                 
1063                 box[0] = (max[0] - min[0]);
1064                 box[1] = (max[1] - min[1]);
1065                 box[2] = (max[2] - min[2]);
1066                 size = MAX3(box[0], box[1], box[2]);
1067                 if (size <= 0.01f) size = 0.01f;
1068         }
1069         
1070         if (ok == TRUE) {
1071                 ARegion *ar;
1072                 
1073                 v3d->localvd = MEM_mallocN(sizeof(View3D), "localview");
1074                 
1075                 memcpy(v3d->localvd, v3d, sizeof(View3D));
1076
1077                 for (ar = sa->regionbase.first; ar; ar = ar->next) {
1078                         if (ar->regiontype == RGN_TYPE_WINDOW) {
1079                                 RegionView3D *rv3d = ar->regiondata;
1080
1081                                 rv3d->localvd = MEM_mallocN(sizeof(RegionView3D), "localview region");
1082                                 memcpy(rv3d->localvd, rv3d, sizeof(RegionView3D));
1083                                 
1084                                 rv3d->ofs[0] = -(min[0] + max[0]) / 2.0f;
1085                                 rv3d->ofs[1] = -(min[1] + max[1]) / 2.0f;
1086                                 rv3d->ofs[2] = -(min[2] + max[2]) / 2.0f;
1087
1088                                 rv3d->dist = size;
1089                                 /* perspective should be a bit farther away to look nice */
1090                                 if (rv3d->persp == RV3D_ORTHO)
1091                                         rv3d->dist *= 0.7f;
1092
1093                                 /* correction for window aspect ratio */
1094                                 if (ar->winy > 2 && ar->winx > 2) {
1095                                         float asp = (float)ar->winx / (float)ar->winy;
1096                                         if (asp < 1.0f) asp = 1.0f / asp;
1097                                         rv3d->dist *= asp;
1098                                 }
1099                                 
1100                                 if (rv3d->persp == RV3D_CAMOB) rv3d->persp = RV3D_PERSP;
1101                                 
1102                                 v3d->cursor[0] = -rv3d->ofs[0];
1103                                 v3d->cursor[1] = -rv3d->ofs[1];
1104                                 v3d->cursor[2] = -rv3d->ofs[2];
1105                         }
1106                 }
1107                 
1108                 v3d->lay = locallay;
1109         }
1110         else {
1111                 /* clear flags */ 
1112                 for (base = FIRSTBASE; base; base = base->next) {
1113                         if (base->lay & locallay) {
1114                                 base->lay -= locallay;
1115                                 if (base->lay == 0) base->lay = v3d->layact;
1116                                 if (base->object != scene->obedit) base->flag |= SELECT;
1117                                 base->object->lay = base->lay;
1118                         }
1119                 }
1120         }
1121
1122         return ok;
1123 }
1124
1125 static void restore_localviewdata(ScrArea *sa, int free)
1126 {
1127         ARegion *ar;
1128         View3D *v3d = sa->spacedata.first;
1129         
1130         if (v3d->localvd == NULL) return;
1131         
1132         v3d->near = v3d->localvd->near;
1133         v3d->far = v3d->localvd->far;
1134         v3d->lay = v3d->localvd->lay;
1135         v3d->layact = v3d->localvd->layact;
1136         v3d->drawtype = v3d->localvd->drawtype;
1137         v3d->camera = v3d->localvd->camera;
1138         
1139         if (free) {
1140                 MEM_freeN(v3d->localvd);
1141                 v3d->localvd = NULL;
1142         }
1143         
1144         for (ar = sa->regionbase.first; ar; ar = ar->next) {
1145                 if (ar->regiontype == RGN_TYPE_WINDOW) {
1146                         RegionView3D *rv3d = ar->regiondata;
1147                         
1148                         if (rv3d->localvd) {
1149                                 rv3d->dist = rv3d->localvd->dist;
1150                                 copy_v3_v3(rv3d->ofs, rv3d->localvd->ofs);
1151                                 copy_qt_qt(rv3d->viewquat, rv3d->localvd->viewquat);
1152                                 rv3d->view = rv3d->localvd->view;
1153                                 rv3d->persp = rv3d->localvd->persp;
1154                                 rv3d->camzoom = rv3d->localvd->camzoom;
1155
1156                                 if (free) {
1157                                         MEM_freeN(rv3d->localvd);
1158                                         rv3d->localvd = NULL;
1159                                 }
1160                         }
1161                 }
1162         }
1163 }
1164
1165 static int view3d_localview_exit(Main *bmain, Scene *scene, ScrArea *sa)
1166 {
1167         View3D *v3d = sa->spacedata.first;
1168         struct Base *base;
1169         unsigned int locallay;
1170         
1171         if (v3d->localvd) {
1172                 
1173                 locallay = v3d->lay & 0xFF000000;
1174                 
1175                 restore_localviewdata(sa, 1); /* 1 = free */
1176
1177                 /* for when in other window the layers have changed */
1178                 if (v3d->scenelock) v3d->lay = scene->lay;
1179                 
1180                 for (base = FIRSTBASE; base; base = base->next) {
1181                         if (base->lay & locallay) {
1182                                 base->lay -= locallay;
1183                                 if (base->lay == 0) base->lay = v3d->layact;
1184                                 if (base->object != scene->obedit) {
1185                                         base->flag |= SELECT;
1186                                         base->object->flag |= SELECT;
1187                                 }
1188                                 base->object->lay = base->lay;
1189                         }
1190                 }
1191                 
1192                 DAG_on_visible_update(bmain, FALSE);
1193
1194                 return TRUE;
1195         } 
1196         else {
1197                 return FALSE;
1198         }
1199 }
1200
1201 static int localview_exec(bContext *C, wmOperator *op)
1202 {
1203         Main *bmain = CTX_data_main(C);
1204         Scene *scene = CTX_data_scene(C);
1205         ScrArea *sa = CTX_wm_area(C);
1206         View3D *v3d = CTX_wm_view3d(C);
1207         int change;
1208         
1209         if (v3d->localvd) {
1210                 change = view3d_localview_exit(bmain, scene, sa);
1211         }
1212         else {
1213                 change = view3d_localview_init(bmain, scene, sa, op->reports);
1214         }
1215
1216         if (change) {
1217                 DAG_id_type_tag(bmain, ID_OB);
1218                 ED_area_tag_redraw(CTX_wm_area(C));
1219
1220                 return OPERATOR_FINISHED;
1221         }
1222         else {
1223                 return OPERATOR_CANCELLED;
1224         }
1225 }
1226
1227 void VIEW3D_OT_localview(wmOperatorType *ot)
1228 {
1229         /* identifiers */
1230         ot->name = "Local View";
1231         ot->description = "Toggle display of selected object(s) separately and centered in view";
1232         ot->idname = "VIEW3D_OT_localview";
1233         
1234         /* api callbacks */
1235         ot->exec = localview_exec;
1236         ot->flag = OPTYPE_UNDO; /* localview changes object layer bitflags */
1237         
1238         ot->poll = ED_operator_view3d_active;
1239 }
1240
1241 #ifdef WITH_GAMEENGINE
1242
1243 static ListBase queue_back;
1244 static void SaveState(bContext *C, wmWindow *win)
1245 {
1246         Object *obact = CTX_data_active_object(C);
1247         
1248         glPushAttrib(GL_ALL_ATTRIB_BITS);
1249
1250         if (obact && obact->mode & OB_MODE_TEXTURE_PAINT)
1251                 GPU_paint_set_mipmap(1);
1252         
1253         queue_back = win->queue;
1254         
1255         win->queue.first = win->queue.last = NULL;
1256         
1257         //XXX waitcursor(1);
1258 }
1259
1260 static void RestoreState(bContext *C, wmWindow *win)
1261 {
1262         Object *obact = CTX_data_active_object(C);
1263         
1264         if (obact && obact->mode & OB_MODE_TEXTURE_PAINT)
1265                 GPU_paint_set_mipmap(0);
1266
1267         //XXX curarea->win_swap = 0;
1268         //XXX curarea->head_swap=0;
1269         //XXX allqueue(REDRAWVIEW3D, 1);
1270         //XXX allqueue(REDRAWBUTSALL, 0);
1271         //XXX reset_slowparents();
1272         //XXX waitcursor(0);
1273         //XXX G.qual= 0;
1274         
1275         if (win) /* check because closing win can set to NULL */
1276                 win->queue = queue_back;
1277         
1278         GPU_state_init();
1279         GPU_set_tpage(NULL, 0, 0);
1280
1281         glPopAttrib();
1282 }
1283
1284 /* was space_set_commmandline_options in 2.4x */
1285 static void game_set_commmandline_options(GameData *gm)
1286 {
1287         SYS_SystemHandle syshandle;
1288         int test;
1289
1290         if ((syshandle = SYS_GetSystem())) {
1291                 /* User defined settings */
1292                 test = (U.gameflags & USER_DISABLE_MIPMAP);
1293                 GPU_set_mipmap(!test);
1294                 SYS_WriteCommandLineInt(syshandle, "nomipmap", test);
1295
1296                 /* File specific settings: */
1297                 /* Only test the first one. These two are switched
1298                  * simultaneously. */
1299                 test = (gm->flag & GAME_SHOW_FRAMERATE);
1300                 SYS_WriteCommandLineInt(syshandle, "show_framerate", test);
1301                 SYS_WriteCommandLineInt(syshandle, "show_profile", test);
1302
1303                 test = (gm->flag & GAME_SHOW_DEBUG_PROPS);
1304                 SYS_WriteCommandLineInt(syshandle, "show_properties", test);
1305
1306                 test = (gm->flag & GAME_SHOW_PHYSICS);
1307                 SYS_WriteCommandLineInt(syshandle, "show_physics", test);
1308
1309                 test = (gm->flag & GAME_ENABLE_ALL_FRAMES);
1310                 SYS_WriteCommandLineInt(syshandle, "fixedtime", test);
1311
1312                 test = (gm->flag & GAME_ENABLE_ANIMATION_RECORD);
1313                 SYS_WriteCommandLineInt(syshandle, "animation_record", test);
1314
1315                 test = (gm->flag & GAME_IGNORE_DEPRECATION_WARNINGS);
1316                 SYS_WriteCommandLineInt(syshandle, "ignore_deprecation_warnings", test);
1317
1318                 test = (gm->matmode == GAME_MAT_MULTITEX);
1319                 SYS_WriteCommandLineInt(syshandle, "blender_material", test);
1320                 test = (gm->matmode == GAME_MAT_GLSL);
1321                 SYS_WriteCommandLineInt(syshandle, "blender_glsl_material", test);
1322                 test = (gm->flag & GAME_DISPLAY_LISTS);
1323                 SYS_WriteCommandLineInt(syshandle, "displaylists", test);
1324
1325
1326         }
1327 }
1328
1329 #endif /* WITH_GAMEENGINE */
1330
1331 static int game_engine_poll(bContext *C)
1332 {
1333         /* we need a context and area to launch BGE
1334          * it's a temporary solution to avoid crash at load time
1335          * if we try to auto run the BGE. Ideally we want the
1336          * context to be set as soon as we load the file. */
1337
1338         if (CTX_wm_window(C) == NULL) return 0;
1339         if (CTX_wm_screen(C) == NULL) return 0;
1340         if (CTX_wm_area(C) == NULL) return 0;
1341
1342         if (CTX_data_mode_enum(C) != CTX_MODE_OBJECT)
1343                 return 0;
1344
1345         return 1;
1346 }
1347
1348 int ED_view3d_context_activate(bContext *C)
1349 {
1350         bScreen *sc = CTX_wm_screen(C);
1351         ScrArea *sa = CTX_wm_area(C);
1352         ARegion *ar;
1353
1354         /* sa can be NULL when called from python */
1355         if (sa == NULL || sa->spacetype != SPACE_VIEW3D)
1356                 for (sa = sc->areabase.first; sa; sa = sa->next)
1357                         if (sa->spacetype == SPACE_VIEW3D)
1358                                 break;
1359
1360         if (!sa)
1361                 return 0;
1362         
1363         for (ar = sa->regionbase.first; ar; ar = ar->next)
1364                 if (ar->regiontype == RGN_TYPE_WINDOW)
1365                         break;
1366         
1367         if (!ar)
1368                 return 0;
1369         
1370         /* bad context switch .. */
1371         CTX_wm_area_set(C, sa);
1372         CTX_wm_region_set(C, ar);
1373
1374         return 1;
1375 }
1376
1377 static int game_engine_exec(bContext *C, wmOperator *op)
1378 {
1379 #ifdef WITH_GAMEENGINE
1380         Scene *startscene = CTX_data_scene(C);
1381         ScrArea /* *sa, */ /* UNUSED */ *prevsa = CTX_wm_area(C);
1382         ARegion *ar, *prevar = CTX_wm_region(C);
1383         wmWindow *prevwin = CTX_wm_window(C);
1384         RegionView3D *rv3d;
1385         rcti cam_frame;
1386
1387         (void)op; /* unused */
1388         
1389         /* bad context switch .. */
1390         if (!ED_view3d_context_activate(C))
1391                 return OPERATOR_CANCELLED;
1392         
1393         /* redraw to hide any menus/popups, we don't go back to
1394          * the window manager until after this operator exits */
1395         WM_redraw_windows(C);
1396
1397         rv3d = CTX_wm_region_view3d(C);
1398         /* sa= CTX_wm_area(C); */ /* UNUSED */
1399         ar = CTX_wm_region(C);
1400
1401         view3d_operator_needs_opengl(C);
1402         
1403         game_set_commmandline_options(&startscene->gm);
1404
1405         if ((rv3d->persp == RV3D_CAMOB) &&
1406             (startscene->gm.framing.type == SCE_GAMEFRAMING_BARS) &&
1407             (startscene->gm.stereoflag != STEREO_DOME))
1408         {
1409                 /* Letterbox */
1410                 rctf cam_framef;
1411                 ED_view3d_calc_camera_border(startscene, ar, CTX_wm_view3d(C), rv3d, &cam_framef, FALSE);
1412                 cam_frame.xmin = cam_framef.xmin + ar->winrct.xmin;
1413                 cam_frame.xmax = cam_framef.xmax + ar->winrct.xmin;
1414                 cam_frame.ymin = cam_framef.ymin + ar->winrct.ymin;
1415                 cam_frame.ymax = cam_framef.ymax + ar->winrct.ymin;
1416                 BLI_rcti_isect(&ar->winrct, &cam_frame, &cam_frame);
1417         }
1418         else {
1419                 cam_frame.xmin = ar->winrct.xmin;
1420                 cam_frame.xmax = ar->winrct.xmax;
1421                 cam_frame.ymin = ar->winrct.ymin;
1422                 cam_frame.ymax = ar->winrct.ymax;
1423         }
1424
1425
1426         SaveState(C, prevwin);
1427
1428         StartKetsjiShell(C, ar, &cam_frame, 1);
1429
1430         /* window wasnt closed while the BGE was running */
1431         if (BLI_findindex(&CTX_wm_manager(C)->windows, prevwin) == -1) {
1432                 prevwin = NULL;
1433                 CTX_wm_window_set(C, NULL);
1434         }
1435         
1436         ED_area_tag_redraw(CTX_wm_area(C));
1437
1438         if (prevwin) {
1439                 /* restore context, in case it changed in the meantime, for
1440                  * example by working in another window or closing it */
1441                 CTX_wm_region_set(C, prevar);
1442                 CTX_wm_window_set(C, prevwin);
1443                 CTX_wm_area_set(C, prevsa);
1444         }
1445
1446         RestoreState(C, prevwin);
1447
1448         //XXX restore_all_scene_cfra(scene_cfra_store);
1449         BKE_scene_set_background(CTX_data_main(C), startscene);
1450         //XXX BKE_scene_update_for_newframe(bmain, scene, scene->lay);
1451
1452         return OPERATOR_FINISHED;
1453 #else
1454         (void)C; /* unused */
1455         BKE_report(op->reports, RPT_ERROR, "Game engine is disabled in this build");
1456         return OPERATOR_CANCELLED;
1457 #endif
1458 }
1459
1460 void VIEW3D_OT_game_start(wmOperatorType *ot)
1461 {
1462         
1463         /* identifiers */
1464         ot->name = "Start Game Engine";
1465         ot->description = "Start game engine";
1466         ot->idname = "VIEW3D_OT_game_start";
1467         
1468         /* api callbacks */
1469         ot->exec = game_engine_exec;
1470         
1471         ot->poll = game_engine_poll;
1472 }
1473
1474 /* ************************************** */
1475
1476 static void UNUSED_FUNCTION(view3d_align_axis_to_vector)(View3D *v3d, RegionView3D *rv3d, int axisidx, float vec[3])
1477 {
1478         float alignaxis[3] = {0.0, 0.0, 0.0};
1479         float norm[3], axis[3], angle, new_quat[4];
1480         
1481         if (axisidx > 0) alignaxis[axisidx - 1] = 1.0;
1482         else alignaxis[-axisidx - 1] = -1.0;
1483
1484         normalize_v3_v3(norm, vec);
1485
1486         angle = (float)acos(dot_v3v3(alignaxis, norm));
1487         cross_v3_v3v3(axis, alignaxis, norm);
1488         axis_angle_to_quat(new_quat, axis, -angle);
1489         
1490         rv3d->view = RV3D_VIEW_USER;
1491         
1492         if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
1493                 /* switch out of camera view */
1494                 float orig_ofs[3];
1495                 float orig_dist = rv3d->dist;
1496                 float orig_lens = v3d->lens;
1497                 
1498                 copy_v3_v3(orig_ofs, rv3d->ofs);
1499                 rv3d->persp = RV3D_PERSP;
1500                 rv3d->dist = 0.0;
1501                 ED_view3d_from_object(v3d->camera, rv3d->ofs, NULL, NULL, &v3d->lens);
1502                 view3d_smooth_view(NULL, NULL, NULL, NULL, NULL, orig_ofs, new_quat, &orig_dist, &orig_lens); /* XXX */
1503         }
1504         else {
1505                 if (rv3d->persp == RV3D_CAMOB) rv3d->persp = RV3D_PERSP;  /* switch out of camera mode */
1506                 view3d_smooth_view(NULL, NULL, NULL, NULL, NULL, NULL, new_quat, NULL, NULL); /* XXX */
1507         }
1508 }
1509
1510 float ED_view3d_pixel_size(struct RegionView3D *rv3d, const float co[3])
1511 {
1512         return (rv3d->persmat[3][3] + (
1513                     rv3d->persmat[0][3] * co[0] +
1514                     rv3d->persmat[1][3] * co[1] +
1515                     rv3d->persmat[2][3] * co[2])
1516                 ) * rv3d->pixsize;
1517 }
1518
1519 /* view matrix properties utilities */
1520
1521 /* unused */
1522 #if 0
1523 void ED_view3d_operator_properties_viewmat(wmOperatorType *ot)
1524 {
1525         PropertyRNA *prop;
1526
1527         prop = RNA_def_int(ot->srna, "region_width", 0, 0, INT_MAX, "Region Width", "", 0, INT_MAX);
1528         RNA_def_property_flag(prop, PROP_HIDDEN);
1529
1530         prop = RNA_def_int(ot->srna, "region_height", 0, 0, INT_MAX, "Region height", "", 0, INT_MAX);
1531         RNA_def_property_flag(prop, PROP_HIDDEN);
1532
1533         prop = RNA_def_float_matrix(ot->srna, "perspective_matrix", 4, 4, NULL, 0.0f, 0.0f, "", "Perspective Matrix", 0.0f, 0.0f);
1534         RNA_def_property_flag(prop, PROP_HIDDEN);
1535 }
1536
1537 void ED_view3d_operator_properties_viewmat_set(bContext *C, wmOperator *op)
1538 {
1539         ARegion *ar = CTX_wm_region(C);
1540         RegionView3D *rv3d = ED_view3d_context_rv3d(C);
1541
1542         if (!RNA_struct_property_is_set(op->ptr, "region_width"))
1543                 RNA_int_set(op->ptr, "region_width", ar->winx);
1544
1545         if (!RNA_struct_property_is_set(op->ptr, "region_height"))
1546                 RNA_int_set(op->ptr, "region_height", ar->winy);
1547
1548         if (!RNA_struct_property_is_set(op->ptr, "perspective_matrix"))
1549                 RNA_float_set_array(op->ptr, "perspective_matrix", (float *)rv3d->persmat);
1550 }
1551
1552 void ED_view3d_operator_properties_viewmat_get(wmOperator *op, int *winx, int *winy, float persmat[4][4])
1553 {
1554         *winx = RNA_int_get(op->ptr, "region_width");
1555         *winy = RNA_int_get(op->ptr, "region_height");
1556
1557         RNA_float_get_array(op->ptr, "perspective_matrix", (float *)persmat);
1558 }
1559 #endif