6bdb6930fda75d6f90a4a9e1cda1cca8cd1bd861
[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  * Calculate a 3d segment from 2d window coordinates.
576  * This ray_start is located at the viewpoint, ray_end is a far point.
577  * ray_start and ray_end are clipped by the view near and far limits
578  * so points along this line are always in view.
579  * In orthographic view all resulting segments will be parallel.
580  * \param ar The region (used for the window width and height).
581  * \param v3d The 3d viewport (used for near and far clipping range).
582  * \param mval The area relative 2d location (such as event->mval, converted into float[2]).
583  * \param ray_start The world-space starting point of the segment.
584  * \param ray_end The world-space end point of the segment.
585  */
586 void ED_view3d_win_to_segment_clip(ARegion *ar, View3D *v3d, const float mval[2], float ray_start[3], float ray_end[3])
587 {
588         RegionView3D *rv3d = ar->regiondata;
589         
590         if (rv3d->is_persp) {
591                 float vec[3];
592                 ED_view3d_win_to_vector(ar, mval, vec);
593
594                 copy_v3_v3(ray_start, rv3d->viewinv[3]);
595                 madd_v3_v3v3fl(ray_start, rv3d->viewinv[3], vec, v3d->near);
596                 madd_v3_v3v3fl(ray_end, rv3d->viewinv[3], vec, v3d->far);
597         }
598         else {
599                 float vec[4];
600                 vec[0] = 2.0f * mval[0] / ar->winx - 1;
601                 vec[1] = 2.0f * mval[1] / ar->winy - 1;
602                 vec[2] = 0.0f;
603                 vec[3] = 1.0f;
604                 
605                 mul_m4_v4(rv3d->persinv, vec);
606                 
607                 madd_v3_v3v3fl(ray_start, vec, rv3d->viewinv[2],  1000.0f);
608                 madd_v3_v3v3fl(ray_end, vec, rv3d->viewinv[2], -1000.0f);
609         }
610
611         /* clipping */
612         if (rv3d->rflag & RV3D_CLIPPING) {
613                 int a;
614                 for (a = 0; a < 4; a++) {
615                         clip_line_plane(ray_start, ray_end, rv3d->clip[a]);
616                 }
617         }
618 }
619
620 /**
621  * Calculate a 3d viewpoint and direction vector from 2d window coordinates.
622  * This ray_start is located at the viewpoint, ray_normal is the direction towards mval.
623  * ray_start is clipped by the view near limit so points in front of it are always in view.
624  * In orthographic view the resulting ray_normal will match the view vector.
625  * \param ar The region (used for the window width and height).
626  * \param v3d The 3d viewport (used for near clipping value).
627  * \param mval The area relative 2d location (such as event->mval, converted into float[2]).
628  * \param ray_start The world-space starting point of the segment.
629  * \param ray_normal The normalized world-space direction of towards mval.
630  */
631 void ED_view3d_win_to_ray(ARegion *ar, View3D *v3d, const float mval[2], float ray_start[3], float ray_normal[3])
632 {
633         float ray_end[3];
634         
635         ED_view3d_win_to_segment_clip(ar, v3d, mval, ray_start, ray_end);
636         sub_v3_v3v3(ray_normal, ray_end, ray_start);
637         normalize_v3(ray_normal);
638 }
639
640 /**
641  * Calculate a normalized 3d direction vector from the viewpoint towards a global location.
642  * In orthographic view the resulting vector will match the view vector.
643  * \param rv3d The region (used for the window width and height).
644  * \param coord The world-space location.
645  * \param vec The resulting normalized vector.
646  */
647 void ED_view3d_global_to_vector(RegionView3D *rv3d, const float coord[3], float vec[3])
648 {
649         if (rv3d->is_persp) {
650                 float p1[4], p2[4];
651
652                 copy_v3_v3(p1, coord);
653                 p1[3] = 1.0f;
654                 copy_v3_v3(p2, p1);
655                 p2[3] = 1.0f;
656                 mul_m4_v4(rv3d->viewmat, p2);
657
658                 mul_v3_fl(p2, 2.0f);
659
660                 mul_m4_v4(rv3d->viewinv, p2);
661
662                 sub_v3_v3v3(vec, p1, p2);
663         }
664         else {
665                 copy_v3_v3(vec, rv3d->viewinv[2]);
666         }
667         normalize_v3(vec);
668 }
669
670 int initgrabz(RegionView3D *rv3d, float x, float y, float z)
671 {
672         int flip = FALSE;
673         if (rv3d == NULL) return flip;
674         rv3d->zfac = rv3d->persmat[0][3] * x + rv3d->persmat[1][3] * y + rv3d->persmat[2][3] * z + rv3d->persmat[3][3];
675         if (rv3d->zfac < 0.0f)
676                 flip = TRUE;
677         /* if x,y,z is exactly the viewport offset, zfac is 0 and we don't want that 
678          * (accounting for near zero values)
679          */
680         if (rv3d->zfac < 1.e-6f && rv3d->zfac > -1.e-6f) rv3d->zfac = 1.0f;
681         
682         /* Negative zfac means x, y, z was behind the camera (in perspective).
683          * This gives flipped directions, so revert back to ok default case.
684          */
685         /* NOTE: I've changed this to flip zfac to be positive again for now so that GPencil draws ok
686          * Aligorith, 2009Aug31 */
687         //if (rv3d->zfac < 0.0f) rv3d->zfac = 1.0f;
688         if (rv3d->zfac < 0.0f) rv3d->zfac = -rv3d->zfac;
689         
690         return flip;
691 }
692
693 /**
694  * Calculate a 3d location from 2d window coordinates.
695  * \param ar The region (used for the window width and height).
696  * \param depth_pt The reference location used to calculate the Z depth.
697  * \param mval The area relative location (such as event->mval converted to floats).
698  * \param out The resulting world-space location.
699  */
700 void ED_view3d_win_to_3d(ARegion *ar, const float depth_pt[3], const float mval[2], float out[3])
701 {
702         RegionView3D *rv3d = ar->regiondata;
703         
704         float line_sta[3];
705         float line_end[3];
706
707         if (rv3d->is_persp) {
708                 float mousevec[3];
709                 copy_v3_v3(line_sta, rv3d->viewinv[3]);
710                 ED_view3d_win_to_vector(ar, mval, mousevec);
711                 add_v3_v3v3(line_end, line_sta, mousevec);
712
713                 if (isect_line_plane_v3(out, line_sta, line_end, depth_pt, rv3d->viewinv[2], TRUE) == 0) {
714                         /* highly unlikely to ever happen, mouse vec paralelle with view plane */
715                         zero_v3(out);
716                 }
717         }
718         else {
719                 const float dx = (2.0f * mval[0] / (float)ar->winx) - 1.0f;
720                 const float dy = (2.0f * mval[1] / (float)ar->winy) - 1.0f;
721                 line_sta[0] = (rv3d->persinv[0][0] * dx) + (rv3d->persinv[1][0] * dy) + rv3d->viewinv[3][0];
722                 line_sta[1] = (rv3d->persinv[0][1] * dx) + (rv3d->persinv[1][1] * dy) + rv3d->viewinv[3][1];
723                 line_sta[2] = (rv3d->persinv[0][2] * dx) + (rv3d->persinv[1][2] * dy) + rv3d->viewinv[3][2];
724
725                 add_v3_v3v3(line_end, line_sta, rv3d->viewinv[2]);
726                 closest_to_line_v3(out, depth_pt, line_sta, line_end);
727         }
728 }
729
730 /**
731  * Calculate a 3d difference vector from 2d window offset.
732  * note that initgrabz() must be called first to determine
733  * the depth used to calculate the delta.
734  * \param ar The region (used for the window width and height).
735  * \param mval The area relative 2d difference (such as event->mval[0] - other_x).
736  * \param out The resulting world-space delta.
737  */
738 void ED_view3d_win_to_delta(ARegion *ar, const float mval[2], float out[3])
739 {
740         RegionView3D *rv3d = ar->regiondata;
741         float dx, dy;
742         
743         dx = 2.0f * mval[0] * rv3d->zfac / ar->winx;
744         dy = 2.0f * mval[1] * rv3d->zfac / ar->winy;
745         
746         out[0] = (rv3d->persinv[0][0] * dx + rv3d->persinv[1][0] * dy);
747         out[1] = (rv3d->persinv[0][1] * dx + rv3d->persinv[1][1] * dy);
748         out[2] = (rv3d->persinv[0][2] * dx + rv3d->persinv[1][2] * dy);
749 }
750
751 /**
752  * Calculate a 3d direction vector from 2d window coordinates.
753  * This direction vector starts and the view in the direction of the 2d window coordinates.
754  * In orthographic view all window coordinates yield the same vector.
755  *
756  * \note doesn't rely on initgrabz
757  * for perspective view, get the vector direction to
758  * the mouse cursor as a normalized vector.
759  *
760  * \param ar The region (used for the window width and height).
761  * \param mval The area relative 2d location (such as event->mval converted to floats).
762  * \param out The resulting normalized world-space direction vector.
763  */
764 void ED_view3d_win_to_vector(ARegion *ar, const float mval[2], float out[3])
765 {
766         RegionView3D *rv3d = ar->regiondata;
767
768         if (rv3d->is_persp) {
769                 out[0] = 2.0f * (mval[0] / ar->winx) - 1.0f;
770                 out[1] = 2.0f * (mval[1] / ar->winy) - 1.0f;
771                 out[2] = -0.5f;
772                 mul_project_m4_v3(rv3d->persinv, out);
773                 sub_v3_v3(out, rv3d->viewinv[3]);
774         }
775         else {
776                 copy_v3_v3(out, rv3d->viewinv[2]);
777         }
778         normalize_v3(out);
779 }
780
781 float ED_view3d_depth_read_cached(ViewContext *vc, int x, int y)
782 {
783         ViewDepths *vd = vc->rv3d->depths;
784                 
785         x -= vc->ar->winrct.xmin;
786         y -= vc->ar->winrct.ymin;
787
788         if (vd && vd->depths && x > 0 && y > 0 && x < vd->w && y < vd->h)
789                 return vd->depths[y * vd->w + x];
790         else
791                 return 1;
792 }
793
794 void ED_view3d_depth_tag_update(RegionView3D *rv3d)
795 {
796         if (rv3d->depths)
797                 rv3d->depths->damaged = 1;
798 }
799
800 void ED_view3d_ob_project_mat_get(RegionView3D *rv3d, Object *ob, float pmat[4][4])
801 {
802         float vmat[4][4];
803         
804         mult_m4_m4m4(vmat, rv3d->viewmat, ob->obmat);
805         mult_m4_m4m4(pmat, rv3d->winmat, vmat);
806 }
807
808 /* Uses window coordinates (x,y) and depth component z to find a point in
809  * modelspace */
810 void ED_view3d_unproject(bglMats *mats, float out[3], const float x, const float y, const float z)
811 {
812         double ux, uy, uz;
813
814         gluUnProject(x, y, z, mats->modelview, mats->projection,
815                      (GLint *)mats->viewport, &ux, &uy, &uz);
816
817         out[0] = ux;
818         out[1] = uy;
819         out[2] = uz;
820 }
821
822 /* use #ED_view3d_ob_project_mat_get to get projecting mat */
823 void ED_view3d_project_float_v2_m4(const ARegion *ar, const float co[3], float r_co[2], float mat[4][4])
824 {
825         float vec4[4];
826         
827         copy_v3_v3(vec4, co);
828         vec4[3] = 1.0;
829         /* r_co[0] = IS_CLIPPED; */ /* always overwritten */
830         
831         mul_m4_v4(mat, vec4);
832         
833         if (vec4[3] > FLT_EPSILON) {
834                 r_co[0] = (float)(ar->winx / 2.0f) + (ar->winx / 2.0f) * vec4[0] / vec4[3];
835                 r_co[1] = (float)(ar->winy / 2.0f) + (ar->winy / 2.0f) * vec4[1] / vec4[3];
836         }
837         else {
838                 zero_v2(r_co);
839         }
840 }
841
842 /* use #ED_view3d_ob_project_mat_get to get projecting mat */
843 void ED_view3d_project_float_v3_m4(ARegion *ar, const float vec[3], float r_co[3], float mat[4][4])
844 {
845         float vec4[4];
846         
847         copy_v3_v3(vec4, vec);
848         vec4[3] = 1.0;
849         /* r_co[0] = IS_CLIPPED; */ /* always overwritten */
850         
851         mul_m4_v4(mat, vec4);
852         
853         if (vec4[3] > FLT_EPSILON) {
854                 r_co[0] = (float)(ar->winx / 2.0f) + (ar->winx / 2.0f) * vec4[0] / vec4[3];
855                 r_co[1] = (float)(ar->winy / 2.0f) + (ar->winy / 2.0f) * vec4[1] / vec4[3];
856                 r_co[2] = vec4[2] / vec4[3];
857         }
858         else {
859                 zero_v3(r_co);
860         }
861 }
862
863 eV3DProjStatus ED_view3d_project_base(struct ARegion *ar, struct Base *base)
864 {
865         eV3DProjStatus ret = ED_view3d_project_short_global(ar, base->object->obmat[3], &base->sx, V3D_PROJ_TEST_CLIP_DEFAULT);
866
867         if (ret != V3D_PROJ_RET_OK) {
868                 base->sx = IS_CLIPPED;
869                 base->sy = 0;
870         }
871
872         return ret;
873 }
874
875 int ED_view3d_boundbox_clip(RegionView3D *rv3d, float obmat[][4], BoundBox *bb)
876 {
877         /* return 1: draw */
878         
879         float mat[4][4];
880         float vec[4], min, max;
881         int a, flag = -1, fl;
882         
883         if (bb == NULL) return 1;
884         if (bb->flag & OB_BB_DISABLED) return 1;
885         
886         mult_m4_m4m4(mat, rv3d->persmat, obmat);
887         
888         for (a = 0; a < 8; a++) {
889                 copy_v3_v3(vec, bb->vec[a]);
890                 vec[3] = 1.0;
891                 mul_m4_v4(mat, vec);
892                 max = vec[3];
893                 min = -vec[3];
894                 
895                 fl = 0;
896                 if (vec[0] < min) fl += 1;
897                 if (vec[0] > max) fl += 2;
898                 if (vec[1] < min) fl += 4;
899                 if (vec[1] > max) fl += 8;
900                 if (vec[2] < min) fl += 16;
901                 if (vec[2] > max) fl += 32;
902                 
903                 flag &= fl;
904                 if (flag == 0) return 1;
905         }
906         
907         return 0;
908 }
909
910 /* perspmat is typically...
911  * - 'rv3d->perspmat',   is_local == FALSE
912  * - 'rv3d->perspmatob', is_local == TRUE
913  */
914 static eV3DProjStatus ed_view3d_project__internal(ARegion *ar,
915                                                   float perspmat[4][4], const int is_local,  /* normally hidden */
916                                                   const float co[3], float r_co[2], const eV3DProjTest flag)
917 {
918         float fx, fy, vec4[4];
919
920         /* check for bad flags */
921         BLI_assert((flag & V3D_PROJ_TEST_ALL) == flag);
922
923         if (flag & V3D_PROJ_TEST_CLIP_BB) {
924                 RegionView3D *rv3d = ar->regiondata;
925                 if (rv3d->rflag & RV3D_CLIPPING) {
926                         if (ED_view3d_clipping_test(rv3d, co, is_local)) {
927                                 return V3D_PROJ_RET_CLIP_BB;
928                         }
929                 }
930         }
931
932         copy_v3_v3(vec4, co);
933         vec4[3] = 1.0;
934         mul_m4_v4(perspmat, vec4);
935
936         if (vec4[3] > (float)BL_NEAR_CLIP) {
937                 fx = ((float)ar->winx / 2.0f) * (1.0f + vec4[0] / vec4[3]);
938                 if (((flag & V3D_PROJ_TEST_CLIP_WIN) == 0) || (fx > 0 && fx < ar->winx)) {
939                         fy = ((float)ar->winy / 2.0f) * (1.0f + vec4[1] / vec4[3]);
940                         if (((flag & V3D_PROJ_TEST_CLIP_WIN) == 0) || (fy > 0.0f && fy < (float)ar->winy)) {
941                                 r_co[0] = (short)floor(fx);
942                                 r_co[1] = (short)floor(fy);
943                         }
944                         else {
945                                 return V3D_PROJ_RET_CLIP_WIN;
946                         }
947                 }
948                 else {
949                         return V3D_PROJ_RET_CLIP_WIN;
950                 }
951         }
952         else {
953                 return V3D_PROJ_RET_CLIP_NEAR;
954         }
955
956         return V3D_PROJ_RET_OK;
957 }
958
959 eV3DProjStatus ED_view3d_project_short_ex(ARegion *ar, float perspmat[4][4], const int is_local,
960                                           const float co[3], short r_co[2], const eV3DProjTest flag)
961 {
962         float tvec[2];
963         eV3DProjStatus ret = ed_view3d_project__internal(ar, perspmat, is_local, co, tvec, flag);
964         if (ret == V3D_PROJ_RET_OK) {
965                 if ((tvec[0] > -32700.0 && tvec[0] < 32700.0f) &&
966                     (tvec[1] > -32700.0 && tvec[1] < 32700.0f))
967                 {
968                         r_co[0] = (short)floor(tvec[0]);
969                         r_co[1] = (short)floor(tvec[1]);
970                 }
971                 else {
972                         ret = V3D_PROJ_RET_OVERFLOW;
973                 }
974         }
975         return ret;
976 }
977
978 eV3DProjStatus ED_view3d_project_int_ex(ARegion *ar, float perspmat[4][4], const int is_local,
979                                         const float co[3], int r_co[2], const eV3DProjTest flag)
980 {
981         float tvec[2];
982         eV3DProjStatus ret = ed_view3d_project__internal(ar, perspmat, is_local, co, tvec, flag);
983         if (ret == V3D_PROJ_RET_OK) {
984                 if ((tvec[0] > -2140000000.0 && tvec[0] < 2140000000.0f) &&
985                     (tvec[1] > -2140000000.0 && tvec[1] < 2140000000.0f))
986                 {
987                         r_co[0] = (int)floor(tvec[0]);
988                         r_co[1] = (int)floor(tvec[1]);
989                 }
990                 else {
991                         ret = V3D_PROJ_RET_OVERFLOW;
992                 }
993         }
994         return ret;
995 }
996
997 eV3DProjStatus ED_view3d_project_float_ex(ARegion *ar, float perspmat[4][4], const int is_local,
998                                         const float co[3], float r_co[2], const eV3DProjTest flag)
999 {
1000         float tvec[2];
1001         eV3DProjStatus ret = ed_view3d_project__internal(ar, perspmat, is_local, co, tvec, flag);
1002         if (ret == V3D_PROJ_RET_OK) {
1003                 if (finite(tvec[0]) &&
1004                     finite(tvec[1]))
1005                 {
1006                         copy_v2_v2(r_co, tvec);
1007                 }
1008                 else {
1009                         ret = V3D_PROJ_RET_OVERFLOW;
1010                 }
1011         }
1012         return ret;
1013 }
1014
1015 /* --- short --- */
1016 eV3DProjStatus ED_view3d_project_short_global(ARegion *ar, const float co[3], short r_co[2], const eV3DProjTest flag)
1017 {
1018         RegionView3D *rv3d = ar->regiondata;
1019         return ED_view3d_project_short_ex(ar, rv3d->persmat, FALSE, co, r_co, flag);
1020 }
1021 /* object space, use ED_view3d_init_mats_rv3d before calling */
1022 eV3DProjStatus ED_view3d_project_short_object(ARegion *ar, const float co[3], short r_co[2], const eV3DProjTest flag)
1023 {
1024         RegionView3D *rv3d = ar->regiondata;
1025         return ED_view3d_project_short_ex(ar, rv3d->persmatob, TRUE, co, r_co, flag);
1026 }
1027
1028 /* --- int --- */
1029 eV3DProjStatus ED_view3d_project_int_global(ARegion *ar, const float co[3], int r_co[2], const eV3DProjTest flag)
1030 {
1031         RegionView3D *rv3d = ar->regiondata;
1032         return ED_view3d_project_int_ex(ar, rv3d->persmat, FALSE, co, r_co, flag);
1033 }
1034 /* object space, use ED_view3d_init_mats_rv3d before calling */
1035 eV3DProjStatus ED_view3d_project_int_object(ARegion *ar, const float co[3], int r_co[2], const eV3DProjTest flag)
1036 {
1037         RegionView3D *rv3d = ar->regiondata;
1038         return ED_view3d_project_int_ex(ar, rv3d->persmatob, TRUE, co, r_co, flag);
1039 }
1040
1041 /* --- float --- */
1042 eV3DProjStatus ED_view3d_project_float_global(ARegion *ar, const float co[3], float r_co[2], const eV3DProjTest flag)
1043 {
1044         RegionView3D *rv3d = ar->regiondata;
1045         return ED_view3d_project_float_ex(ar, rv3d->persmat, FALSE, co, r_co, flag);
1046 }
1047 /* object space, use ED_view3d_init_mats_rv3d before calling */
1048 eV3DProjStatus ED_view3d_project_float_object(ARegion *ar, const float co[3], float r_co[2], const eV3DProjTest flag)
1049 {
1050         RegionView3D *rv3d = ar->regiondata;
1051         return ED_view3d_project_float_ex(ar, rv3d->persmatob, TRUE, co, r_co, flag);
1052 }
1053
1054 /* copies logic of get_view3d_viewplane(), keep in sync */
1055 int ED_view3d_clip_range_get(View3D *v3d, RegionView3D *rv3d, float *clipsta, float *clipend)
1056 {
1057         CameraParams params;
1058
1059         BKE_camera_params_init(&params);
1060         BKE_camera_params_from_view3d(&params, v3d, rv3d);
1061
1062         if (clipsta) *clipsta = params.clipsta;
1063         if (clipend) *clipend = params.clipend;
1064
1065         return params.is_ortho;
1066 }
1067
1068 /* also exposed in previewrender.c */
1069 int ED_view3d_viewplane_get(View3D *v3d, RegionView3D *rv3d, int winx, int winy,
1070                             rctf *viewplane, float *clipsta, float *clipend)
1071 {
1072         CameraParams params;
1073
1074         BKE_camera_params_init(&params);
1075         BKE_camera_params_from_view3d(&params, v3d, rv3d);
1076         BKE_camera_params_compute_viewplane(&params, winx, winy, 1.0f, 1.0f);
1077
1078         if (viewplane) *viewplane = params.viewplane;
1079         if (clipsta) *clipsta = params.clipsta;
1080         if (clipend) *clipend = params.clipend;
1081         
1082         return params.is_ortho;
1083 }
1084
1085 void setwinmatrixview3d(ARegion *ar, View3D *v3d, rctf *rect)       /* rect: for picking */
1086 {
1087         RegionView3D *rv3d = ar->regiondata;
1088         rctf viewplane;
1089         float clipsta, clipend, x1, y1, x2, y2;
1090         int orth;
1091         
1092         orth = ED_view3d_viewplane_get(v3d, rv3d, ar->winx, ar->winy, &viewplane, &clipsta, &clipend);
1093         rv3d->is_persp = !orth;
1094
1095 #if 0
1096         printf("%s: %d %d %f %f %f %f %f %f\n", __func__, winx, winy,
1097                viewplane.xmin, viewplane.ymin, viewplane.xmax, viewplane.ymax,
1098                clipsta, clipend);
1099 #endif
1100
1101         x1 = viewplane.xmin;
1102         y1 = viewplane.ymin;
1103         x2 = viewplane.xmax;
1104         y2 = viewplane.ymax;
1105
1106         if (rect) {  /* picking */
1107                 rect->xmin /= (float)ar->winx;
1108                 rect->xmin = x1 + rect->xmin * (x2 - x1);
1109                 rect->ymin /= (float)ar->winy;
1110                 rect->ymin = y1 + rect->ymin * (y2 - y1);
1111                 rect->xmax /= (float)ar->winx;
1112                 rect->xmax = x1 + rect->xmax * (x2 - x1);
1113                 rect->ymax /= (float)ar->winy;
1114                 rect->ymax = y1 + rect->ymax * (y2 - y1);
1115                 
1116                 if (orth) wmOrtho(rect->xmin, rect->xmax, rect->ymin, rect->ymax, -clipend, clipend);
1117                 else wmFrustum(rect->xmin, rect->xmax, rect->ymin, rect->ymax, clipsta, clipend);
1118                 
1119         }
1120         else {
1121                 if (orth) wmOrtho(x1, x2, y1, y2, clipsta, clipend);
1122                 else wmFrustum(x1, x2, y1, y2, clipsta, clipend);
1123         }
1124
1125         /* update matrix in 3d view region */
1126         glGetFloatv(GL_PROJECTION_MATRIX, (float *)rv3d->winmat);
1127 }
1128
1129 static void obmat_to_viewmat(View3D *v3d, RegionView3D *rv3d, Object *ob, short smooth)
1130 {
1131         float bmat[4][4];
1132         float tmat[3][3];
1133         
1134         rv3d->view = RV3D_VIEW_USER; /* don't show the grid */
1135         
1136         copy_m4_m4(bmat, ob->obmat);
1137         normalize_m4(bmat);
1138         invert_m4_m4(rv3d->viewmat, bmat);
1139         
1140         /* view quat calculation, needed for add object */
1141         copy_m3_m4(tmat, rv3d->viewmat);
1142         if (smooth) {
1143                 float new_quat[4];
1144                 if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
1145                         /* were from a camera view */
1146                         
1147                         float orig_ofs[3];
1148                         float orig_dist = rv3d->dist;
1149                         float orig_lens = v3d->lens;
1150                         copy_v3_v3(orig_ofs, rv3d->ofs);
1151                         
1152                         /* Switch from camera view */
1153                         mat3_to_quat(new_quat, tmat);
1154                         
1155                         rv3d->persp = RV3D_PERSP;
1156                         rv3d->dist = 0.0;
1157                         
1158                         ED_view3d_from_object(v3d->camera, rv3d->ofs, NULL, NULL, &v3d->lens);
1159                         view3d_smooth_view(NULL, NULL, NULL, NULL, NULL, orig_ofs, new_quat, &orig_dist, &orig_lens); /* XXX */
1160
1161                         rv3d->persp = RV3D_CAMOB; /* just to be polite, not needed */
1162                         
1163                 }
1164                 else {
1165                         mat3_to_quat(new_quat, tmat);
1166                         view3d_smooth_view(NULL, NULL, NULL, NULL, NULL, NULL, new_quat, NULL, NULL); /* XXX */
1167                 }
1168         }
1169         else {
1170                 mat3_to_quat(rv3d->viewquat, tmat);
1171         }
1172 }
1173
1174 #define QUATSET(a, b, c, d, e) { a[0] = b; a[1] = c; a[2] = d; a[3] = e; } (void)0
1175
1176 int ED_view3d_lock(RegionView3D *rv3d)
1177 {
1178         switch (rv3d->view) {
1179                 case RV3D_VIEW_BOTTOM:
1180                         QUATSET(rv3d->viewquat, 0.0, -1.0, 0.0, 0.0);
1181                         break;
1182
1183                 case RV3D_VIEW_BACK:
1184                         QUATSET(rv3d->viewquat, 0.0, 0.0, -M_SQRT1_2, -M_SQRT1_2);
1185                         break;
1186
1187                 case RV3D_VIEW_LEFT:
1188                         QUATSET(rv3d->viewquat, 0.5, -0.5, 0.5, 0.5);
1189                         break;
1190
1191                 case RV3D_VIEW_TOP:
1192                         QUATSET(rv3d->viewquat, 1.0, 0.0, 0.0, 0.0);
1193                         break;
1194
1195                 case RV3D_VIEW_FRONT:
1196                         QUATSET(rv3d->viewquat, M_SQRT1_2, -M_SQRT1_2, 0.0, 0.0);
1197                         break;
1198
1199                 case RV3D_VIEW_RIGHT:
1200                         QUATSET(rv3d->viewquat, 0.5, -0.5, -0.5, -0.5);
1201                         break;
1202                 default:
1203                         return FALSE;
1204         }
1205
1206         return TRUE;
1207 }
1208
1209 /* don't set windows active in here, is used by renderwin too */
1210 void setviewmatrixview3d(Scene *scene, View3D *v3d, RegionView3D *rv3d)
1211 {
1212         if (rv3d->persp == RV3D_CAMOB) {      /* obs/camera */
1213                 if (v3d->camera) {
1214                         BKE_object_where_is_calc(scene, v3d->camera);   
1215                         obmat_to_viewmat(v3d, rv3d, v3d->camera, 0);
1216                 }
1217                 else {
1218                         quat_to_mat4(rv3d->viewmat, rv3d->viewquat);
1219                         rv3d->viewmat[3][2] -= rv3d->dist;
1220                 }
1221         }
1222         else {
1223                 /* should be moved to better initialize later on XXX */
1224                 if (rv3d->viewlock)
1225                         ED_view3d_lock(rv3d);
1226                 
1227                 quat_to_mat4(rv3d->viewmat, rv3d->viewquat);
1228                 if (rv3d->persp == RV3D_PERSP) rv3d->viewmat[3][2] -= rv3d->dist;
1229                 if (v3d->ob_centre) {
1230                         Object *ob = v3d->ob_centre;
1231                         float vec[3];
1232                         
1233                         copy_v3_v3(vec, ob->obmat[3]);
1234                         if (ob->type == OB_ARMATURE && v3d->ob_centre_bone[0]) {
1235                                 bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, v3d->ob_centre_bone);
1236                                 if (pchan) {
1237                                         copy_v3_v3(vec, pchan->pose_mat[3]);
1238                                         mul_m4_v3(ob->obmat, vec);
1239                                 }
1240                         }
1241                         translate_m4(rv3d->viewmat, -vec[0], -vec[1], -vec[2]);
1242                 }
1243                 else if (v3d->ob_centre_cursor) {
1244                         float vec[3];
1245                         copy_v3_v3(vec, give_cursor(scene, v3d));
1246                         translate_m4(rv3d->viewmat, -vec[0], -vec[1], -vec[2]);
1247                 }
1248                 else translate_m4(rv3d->viewmat, rv3d->ofs[0], rv3d->ofs[1], rv3d->ofs[2]);
1249         }
1250 }
1251
1252 /* IGLuint-> GLuint */
1253 /* Warning: be sure to account for a negative return value
1254  *   This is an error, "Too many objects in select buffer"
1255  *   and no action should be taken (can crash blender) if this happens
1256  */
1257 short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int bufsize, rcti *input)
1258 {
1259         Scene *scene = vc->scene;
1260         View3D *v3d = vc->v3d;
1261         ARegion *ar = vc->ar;
1262         rctf rect;
1263         short code, hits;
1264         char dt, dtx;
1265         
1266         G.f |= G_PICKSEL;
1267         
1268         /* case not a border select */
1269         if (input->xmin == input->xmax) {
1270                 rect.xmin = input->xmin - 12;  /* seems to be default value for bones only now */
1271                 rect.xmax = input->xmin + 12;
1272                 rect.ymin = input->ymin - 12;
1273                 rect.ymax = input->ymin + 12;
1274         }
1275         else {
1276                 BLI_rctf_rcti_copy(&rect, input);
1277         }
1278         
1279         setwinmatrixview3d(ar, v3d, &rect);
1280         mult_m4_m4m4(vc->rv3d->persmat, vc->rv3d->winmat, vc->rv3d->viewmat);
1281         
1282         if (v3d->drawtype > OB_WIRE) {
1283                 v3d->zbuf = TRUE;
1284                 glEnable(GL_DEPTH_TEST);
1285         }
1286         
1287         if (vc->rv3d->rflag & RV3D_CLIPPING)
1288                 ED_view3d_clipping_set(vc->rv3d);
1289         
1290         glSelectBuffer(bufsize, (GLuint *)buffer);
1291         glRenderMode(GL_SELECT);
1292         glInitNames();  /* these two calls whatfor? It doesnt work otherwise */
1293         glPushName(-1);
1294         code = 1;
1295         
1296         if (vc->obedit && vc->obedit->type == OB_MBALL) {
1297                 draw_object(scene, ar, v3d, BASACT, DRAW_PICKING | DRAW_CONSTCOLOR);
1298         }
1299         else if ((vc->obedit && vc->obedit->type == OB_ARMATURE)) {
1300                 /* if not drawing sketch, draw bones */
1301                 if (!BDR_drawSketchNames(vc)) {
1302                         draw_object(scene, ar, v3d, BASACT, DRAW_PICKING | DRAW_CONSTCOLOR);
1303                 }
1304         }
1305         else {
1306                 Base *base;
1307                 
1308                 v3d->xray = TRUE;  /* otherwise it postpones drawing */
1309                 for (base = scene->base.first; base; base = base->next) {
1310                         if (base->lay & v3d->lay) {
1311                                 
1312                                 if (base->object->restrictflag & OB_RESTRICT_SELECT)
1313                                         base->selcol = 0;
1314                                 else {
1315                                         base->selcol = code;
1316                                         glLoadName(code);
1317                                         draw_object(scene, ar, v3d, base, DRAW_PICKING | DRAW_CONSTCOLOR);
1318                                         
1319                                         /* we draw group-duplicators for selection too */
1320                                         if ((base->object->transflag & OB_DUPLI) && base->object->dup_group) {
1321                                                 ListBase *lb;
1322                                                 DupliObject *dob;
1323                                                 Base tbase;
1324                                                 
1325                                                 tbase.flag = OB_FROMDUPLI;
1326                                                 lb = object_duplilist(scene, base->object, FALSE);
1327                                                 
1328                                                 for (dob = lb->first; dob; dob = dob->next) {
1329                                                         tbase.object = dob->ob;
1330                                                         copy_m4_m4(dob->ob->obmat, dob->mat);
1331                                                         
1332                                                         /* extra service: draw the duplicator in drawtype of parent */
1333                                                         /* MIN2 for the drawtype to allow bounding box objects in groups for lods */
1334                                                         dt = tbase.object->dt;   tbase.object->dt = MIN2(tbase.object->dt, base->object->dt);
1335                                                         dtx = tbase.object->dtx; tbase.object->dtx = base->object->dtx;
1336
1337                                                         draw_object(scene, ar, v3d, &tbase, DRAW_PICKING | DRAW_CONSTCOLOR);
1338                                                         
1339                                                         tbase.object->dt = dt;
1340                                                         tbase.object->dtx = dtx;
1341
1342                                                         copy_m4_m4(dob->ob->obmat, dob->omat);
1343                                                 }
1344                                                 free_object_duplilist(lb);
1345                                         }
1346                                         code++;
1347                                 }                               
1348                         }
1349                 }
1350                 v3d->xray = FALSE;  /* restore */
1351         }
1352         
1353         glPopName();    /* see above (pushname) */
1354         hits = glRenderMode(GL_RENDER);
1355         
1356         G.f &= ~G_PICKSEL;
1357         setwinmatrixview3d(ar, v3d, NULL);
1358         mult_m4_m4m4(vc->rv3d->persmat, vc->rv3d->winmat, vc->rv3d->viewmat);
1359         
1360         if (v3d->drawtype > OB_WIRE) {
1361                 v3d->zbuf = 0;
1362                 glDisable(GL_DEPTH_TEST);
1363         }
1364 // XXX  persp(PERSP_WIN);
1365         
1366         if (vc->rv3d->rflag & RV3D_CLIPPING)
1367                 ED_view3d_clipping_disable();
1368         
1369         if (hits < 0) printf("Too many objects in select buffer\n");  /* XXX make error message */
1370
1371         return hits;
1372 }
1373
1374 /* ********************** local view operator ******************** */
1375
1376 static unsigned int free_localbit(Main *bmain)
1377 {
1378         unsigned int lay;
1379         ScrArea *sa;
1380         bScreen *sc;
1381         
1382         lay = 0;
1383         
1384         /* sometimes we loose a localview: when an area is closed */
1385         /* check all areas: which localviews are in use? */
1386         for (sc = bmain->screen.first; sc; sc = sc->id.next) {
1387                 for (sa = sc->areabase.first; sa; sa = sa->next) {
1388                         SpaceLink *sl = sa->spacedata.first;
1389                         for (; sl; sl = sl->next) {
1390                                 if (sl->spacetype == SPACE_VIEW3D) {
1391                                         View3D *v3d = (View3D *) sl;
1392                                         lay |= v3d->lay;
1393                                 }
1394                         }
1395                 }
1396         }
1397         
1398         if ((lay & 0x01000000) == 0) return 0x01000000;
1399         if ((lay & 0x02000000) == 0) return 0x02000000;
1400         if ((lay & 0x04000000) == 0) return 0x04000000;
1401         if ((lay & 0x08000000) == 0) return 0x08000000;
1402         if ((lay & 0x10000000) == 0) return 0x10000000;
1403         if ((lay & 0x20000000) == 0) return 0x20000000;
1404         if ((lay & 0x40000000) == 0) return 0x40000000;
1405         if ((lay & 0x80000000) == 0) return 0x80000000;
1406         
1407         return 0;
1408 }
1409
1410 int ED_view3d_scene_layer_set(int lay, const int *values, int *active)
1411 {
1412         int i, tot = 0;
1413         
1414         /* ensure we always have some layer selected */
1415         for (i = 0; i < 20; i++)
1416                 if (values[i])
1417                         tot++;
1418         
1419         if (tot == 0)
1420                 return lay;
1421         
1422         for (i = 0; i < 20; i++) {
1423                 
1424                 if (active) {
1425                         /* if this value has just been switched on, make that layer active */
1426                         if (values[i] && (lay & (1 << i)) == 0) {
1427                                 *active = (1 << i);
1428                         }
1429                 }
1430                         
1431                 if (values[i]) lay |= (1 << i);
1432                 else lay &= ~(1 << i);
1433         }
1434         
1435         /* ensure always an active layer */
1436         if (active && (lay & *active) == 0) {
1437                 for (i = 0; i < 20; i++) {
1438                         if (lay & (1 << i)) {
1439                                 *active = 1 << i;
1440                                 break;
1441                         }
1442                 }
1443         }
1444         
1445         return lay;
1446 }
1447
1448 static int view3d_localview_init(Main *bmain, Scene *scene, ScrArea *sa, ReportList *reports)
1449 {
1450         View3D *v3d = sa->spacedata.first;
1451         Base *base;
1452         float size = 0.0, min[3], max[3], box[3];
1453         unsigned int locallay;
1454         int ok = FALSE;
1455
1456         if (v3d->localvd) {
1457                 return ok;
1458         }
1459
1460         INIT_MINMAX(min, max);
1461
1462         locallay = free_localbit(bmain);
1463
1464         if (locallay == 0) {
1465                 BKE_reportf(reports, RPT_ERROR, "No more than 8 local views");
1466                 ok = FALSE;
1467         }
1468         else {
1469                 if (scene->obedit) {
1470                         BKE_object_minmax(scene->obedit, min, max, FALSE);
1471                         
1472                         ok = TRUE;
1473                 
1474                         BASACT->lay |= locallay;
1475                         scene->obedit->lay = BASACT->lay;
1476                 }
1477                 else {
1478                         for (base = FIRSTBASE; base; base = base->next) {
1479                                 if (TESTBASE(v3d, base)) {
1480                                         BKE_object_minmax(base->object, min, max, FALSE);
1481                                         base->lay |= locallay;
1482                                         base->object->lay = base->lay;
1483                                         ok = TRUE;
1484                                 }
1485                         }
1486                 }
1487                 
1488                 box[0] = (max[0] - min[0]);
1489                 box[1] = (max[1] - min[1]);
1490                 box[2] = (max[2] - min[2]);
1491                 size = MAX3(box[0], box[1], box[2]);
1492                 if (size <= 0.01f) size = 0.01f;
1493         }
1494         
1495         if (ok == TRUE) {
1496                 ARegion *ar;
1497                 
1498                 v3d->localvd = MEM_mallocN(sizeof(View3D), "localview");
1499                 
1500                 memcpy(v3d->localvd, v3d, sizeof(View3D));
1501
1502                 for (ar = sa->regionbase.first; ar; ar = ar->next) {
1503                         if (ar->regiontype == RGN_TYPE_WINDOW) {
1504                                 RegionView3D *rv3d = ar->regiondata;
1505
1506                                 rv3d->localvd = MEM_mallocN(sizeof(RegionView3D), "localview region");
1507                                 memcpy(rv3d->localvd, rv3d, sizeof(RegionView3D));
1508                                 
1509                                 rv3d->ofs[0] = -(min[0] + max[0]) / 2.0f;
1510                                 rv3d->ofs[1] = -(min[1] + max[1]) / 2.0f;
1511                                 rv3d->ofs[2] = -(min[2] + max[2]) / 2.0f;
1512
1513                                 rv3d->dist = size;
1514                                 /* perspective should be a bit farther away to look nice */
1515                                 if (rv3d->persp == RV3D_ORTHO)
1516                                         rv3d->dist *= 0.7f;
1517
1518                                 /* correction for window aspect ratio */
1519                                 if (ar->winy > 2 && ar->winx > 2) {
1520                                         float asp = (float)ar->winx / (float)ar->winy;
1521                                         if (asp < 1.0f) asp = 1.0f / asp;
1522                                         rv3d->dist *= asp;
1523                                 }
1524                                 
1525                                 if (rv3d->persp == RV3D_CAMOB) rv3d->persp = RV3D_PERSP;
1526                                 
1527                                 v3d->cursor[0] = -rv3d->ofs[0];
1528                                 v3d->cursor[1] = -rv3d->ofs[1];
1529                                 v3d->cursor[2] = -rv3d->ofs[2];
1530                         }
1531                 }
1532                 
1533                 v3d->lay = locallay;
1534         }
1535         else {
1536                 /* clear flags */ 
1537                 for (base = FIRSTBASE; base; base = base->next) {
1538                         if (base->lay & locallay) {
1539                                 base->lay -= locallay;
1540                                 if (base->lay == 0) base->lay = v3d->layact;
1541                                 if (base->object != scene->obedit) base->flag |= SELECT;
1542                                 base->object->lay = base->lay;
1543                         }
1544                 }
1545         }
1546
1547         return ok;
1548 }
1549
1550 static void restore_localviewdata(ScrArea *sa, int free)
1551 {
1552         ARegion *ar;
1553         View3D *v3d = sa->spacedata.first;
1554         
1555         if (v3d->localvd == NULL) return;
1556         
1557         v3d->near = v3d->localvd->near;
1558         v3d->far = v3d->localvd->far;
1559         v3d->lay = v3d->localvd->lay;
1560         v3d->layact = v3d->localvd->layact;
1561         v3d->drawtype = v3d->localvd->drawtype;
1562         v3d->camera = v3d->localvd->camera;
1563         
1564         if (free) {
1565                 MEM_freeN(v3d->localvd);
1566                 v3d->localvd = NULL;
1567         }
1568         
1569         for (ar = sa->regionbase.first; ar; ar = ar->next) {
1570                 if (ar->regiontype == RGN_TYPE_WINDOW) {
1571                         RegionView3D *rv3d = ar->regiondata;
1572                         
1573                         if (rv3d->localvd) {
1574                                 rv3d->dist = rv3d->localvd->dist;
1575                                 copy_v3_v3(rv3d->ofs, rv3d->localvd->ofs);
1576                                 copy_qt_qt(rv3d->viewquat, rv3d->localvd->viewquat);
1577                                 rv3d->view = rv3d->localvd->view;
1578                                 rv3d->persp = rv3d->localvd->persp;
1579                                 rv3d->camzoom = rv3d->localvd->camzoom;
1580
1581                                 if (free) {
1582                                         MEM_freeN(rv3d->localvd);
1583                                         rv3d->localvd = NULL;
1584                                 }
1585                         }
1586                 }
1587         }
1588 }
1589
1590 static int view3d_localview_exit(Main *bmain, Scene *scene, ScrArea *sa)
1591 {
1592         View3D *v3d = sa->spacedata.first;
1593         struct Base *base;
1594         unsigned int locallay;
1595         
1596         if (v3d->localvd) {
1597                 
1598                 locallay = v3d->lay & 0xFF000000;
1599                 
1600                 restore_localviewdata(sa, 1); /* 1 = free */
1601
1602                 /* for when in other window the layers have changed */
1603                 if (v3d->scenelock) v3d->lay = scene->lay;
1604                 
1605                 for (base = FIRSTBASE; base; base = base->next) {
1606                         if (base->lay & locallay) {
1607                                 base->lay -= locallay;
1608                                 if (base->lay == 0) base->lay = v3d->layact;
1609                                 if (base->object != scene->obedit) {
1610                                         base->flag |= SELECT;
1611                                         base->object->flag |= SELECT;
1612                                 }
1613                                 base->object->lay = base->lay;
1614                         }
1615                 }
1616                 
1617                 DAG_on_visible_update(bmain, FALSE);
1618
1619                 return TRUE;
1620         } 
1621         else {
1622                 return FALSE;
1623         }
1624 }
1625
1626 static int localview_exec(bContext *C, wmOperator *op)
1627 {
1628         Main *bmain = CTX_data_main(C);
1629         Scene *scene = CTX_data_scene(C);
1630         ScrArea *sa = CTX_wm_area(C);
1631         View3D *v3d = CTX_wm_view3d(C);
1632         int change;
1633         
1634         if (v3d->localvd) {
1635                 change = view3d_localview_exit(bmain, scene, sa);
1636         }
1637         else {
1638                 change = view3d_localview_init(bmain, scene, sa, op->reports);
1639         }
1640
1641         if (change) {
1642                 DAG_id_type_tag(bmain, ID_OB);
1643                 ED_area_tag_redraw(CTX_wm_area(C));
1644
1645                 return OPERATOR_FINISHED;
1646         }
1647         else {
1648                 return OPERATOR_CANCELLED;
1649         }
1650 }
1651
1652 void VIEW3D_OT_localview(wmOperatorType *ot)
1653 {
1654         /* identifiers */
1655         ot->name = "Local View";
1656         ot->description = "Toggle display of selected object(s) separately and centered in view";
1657         ot->idname = "VIEW3D_OT_localview";
1658         
1659         /* api callbacks */
1660         ot->exec = localview_exec;
1661         ot->flag = OPTYPE_UNDO; /* localview changes object layer bitflags */
1662         
1663         ot->poll = ED_operator_view3d_active;
1664 }
1665
1666 #ifdef WITH_GAMEENGINE
1667
1668 static ListBase queue_back;
1669 static void SaveState(bContext *C, wmWindow *win)
1670 {
1671         Object *obact = CTX_data_active_object(C);
1672         
1673         glPushAttrib(GL_ALL_ATTRIB_BITS);
1674
1675         if (obact && obact->mode & OB_MODE_TEXTURE_PAINT)
1676                 GPU_paint_set_mipmap(1);
1677         
1678         queue_back = win->queue;
1679         
1680         win->queue.first = win->queue.last = NULL;
1681         
1682         //XXX waitcursor(1);
1683 }
1684
1685 static void RestoreState(bContext *C, wmWindow *win)
1686 {
1687         Object *obact = CTX_data_active_object(C);
1688         
1689         if (obact && obact->mode & OB_MODE_TEXTURE_PAINT)
1690                 GPU_paint_set_mipmap(0);
1691
1692         //XXX curarea->win_swap = 0;
1693         //XXX curarea->head_swap=0;
1694         //XXX allqueue(REDRAWVIEW3D, 1);
1695         //XXX allqueue(REDRAWBUTSALL, 0);
1696         //XXX reset_slowparents();
1697         //XXX waitcursor(0);
1698         //XXX G.qual= 0;
1699         
1700         if (win) /* check because closing win can set to NULL */
1701                 win->queue = queue_back;
1702         
1703         GPU_state_init();
1704         GPU_set_tpage(NULL, 0, 0);
1705
1706         glPopAttrib();
1707 }
1708
1709 /* was space_set_commmandline_options in 2.4x */
1710 static void game_set_commmandline_options(GameData *gm)
1711 {
1712         SYS_SystemHandle syshandle;
1713         int test;
1714
1715         if ((syshandle = SYS_GetSystem())) {
1716                 /* User defined settings */
1717                 test = (U.gameflags & USER_DISABLE_MIPMAP);
1718                 GPU_set_mipmap(!test);
1719                 SYS_WriteCommandLineInt(syshandle, "nomipmap", test);
1720
1721                 /* File specific settings: */
1722                 /* Only test the first one. These two are switched
1723                  * simultaneously. */
1724                 test = (gm->flag & GAME_SHOW_FRAMERATE);
1725                 SYS_WriteCommandLineInt(syshandle, "show_framerate", test);
1726                 SYS_WriteCommandLineInt(syshandle, "show_profile", test);
1727
1728                 test = (gm->flag & GAME_SHOW_DEBUG_PROPS);
1729                 SYS_WriteCommandLineInt(syshandle, "show_properties", test);
1730
1731                 test = (gm->flag & GAME_SHOW_PHYSICS);
1732                 SYS_WriteCommandLineInt(syshandle, "show_physics", test);
1733
1734                 test = (gm->flag & GAME_ENABLE_ALL_FRAMES);
1735                 SYS_WriteCommandLineInt(syshandle, "fixedtime", test);
1736
1737                 test = (gm->flag & GAME_ENABLE_ANIMATION_RECORD);
1738                 SYS_WriteCommandLineInt(syshandle, "animation_record", test);
1739
1740                 test = (gm->flag & GAME_IGNORE_DEPRECATION_WARNINGS);
1741                 SYS_WriteCommandLineInt(syshandle, "ignore_deprecation_warnings", test);
1742
1743                 test = (gm->matmode == GAME_MAT_MULTITEX);
1744                 SYS_WriteCommandLineInt(syshandle, "blender_material", test);
1745                 test = (gm->matmode == GAME_MAT_GLSL);
1746                 SYS_WriteCommandLineInt(syshandle, "blender_glsl_material", test);
1747                 test = (gm->flag & GAME_DISPLAY_LISTS);
1748                 SYS_WriteCommandLineInt(syshandle, "displaylists", test);
1749
1750
1751         }
1752 }
1753
1754 #endif /* WITH_GAMEENGINE */
1755
1756 static int game_engine_poll(bContext *C)
1757 {
1758         /* we need a context and area to launch BGE
1759          * it's a temporary solution to avoid crash at load time
1760          * if we try to auto run the BGE. Ideally we want the
1761          * context to be set as soon as we load the file. */
1762
1763         if (CTX_wm_window(C) == NULL) return 0;
1764         if (CTX_wm_screen(C) == NULL) return 0;
1765         if (CTX_wm_area(C) == NULL) return 0;
1766
1767         if (CTX_data_mode_enum(C) != CTX_MODE_OBJECT)
1768                 return 0;
1769
1770         return 1;
1771 }
1772
1773 int ED_view3d_context_activate(bContext *C)
1774 {
1775         bScreen *sc = CTX_wm_screen(C);
1776         ScrArea *sa = CTX_wm_area(C);
1777         ARegion *ar;
1778
1779         /* sa can be NULL when called from python */
1780         if (sa == NULL || sa->spacetype != SPACE_VIEW3D)
1781                 for (sa = sc->areabase.first; sa; sa = sa->next)
1782                         if (sa->spacetype == SPACE_VIEW3D)
1783                                 break;
1784
1785         if (!sa)
1786                 return 0;
1787         
1788         for (ar = sa->regionbase.first; ar; ar = ar->next)
1789                 if (ar->regiontype == RGN_TYPE_WINDOW)
1790                         break;
1791         
1792         if (!ar)
1793                 return 0;
1794         
1795         /* bad context switch .. */
1796         CTX_wm_area_set(C, sa);
1797         CTX_wm_region_set(C, ar);
1798
1799         return 1;
1800 }
1801
1802 static int game_engine_exec(bContext *C, wmOperator *op)
1803 {
1804 #ifdef WITH_GAMEENGINE
1805         Scene *startscene = CTX_data_scene(C);
1806         ScrArea /* *sa, */ /* UNUSED */ *prevsa = CTX_wm_area(C);
1807         ARegion *ar, *prevar = CTX_wm_region(C);
1808         wmWindow *prevwin = CTX_wm_window(C);
1809         RegionView3D *rv3d;
1810         rcti cam_frame;
1811
1812         (void)op; /* unused */
1813         
1814         /* bad context switch .. */
1815         if (!ED_view3d_context_activate(C))
1816                 return OPERATOR_CANCELLED;
1817         
1818         /* redraw to hide any menus/popups, we don't go back to
1819          * the window manager until after this operator exits */
1820         WM_redraw_windows(C);
1821
1822         rv3d = CTX_wm_region_view3d(C);
1823         /* sa= CTX_wm_area(C); */ /* UNUSED */
1824         ar = CTX_wm_region(C);
1825
1826         view3d_operator_needs_opengl(C);
1827         
1828         game_set_commmandline_options(&startscene->gm);
1829
1830         if ((rv3d->persp == RV3D_CAMOB) &&
1831             (startscene->gm.framing.type == SCE_GAMEFRAMING_BARS) &&
1832             (startscene->gm.stereoflag != STEREO_DOME))
1833         {
1834                 /* Letterbox */
1835                 rctf cam_framef;
1836                 ED_view3d_calc_camera_border(startscene, ar, CTX_wm_view3d(C), rv3d, &cam_framef, FALSE);
1837                 cam_frame.xmin = cam_framef.xmin + ar->winrct.xmin;
1838                 cam_frame.xmax = cam_framef.xmax + ar->winrct.xmin;
1839                 cam_frame.ymin = cam_framef.ymin + ar->winrct.ymin;
1840                 cam_frame.ymax = cam_framef.ymax + ar->winrct.ymin;
1841                 BLI_rcti_isect(&ar->winrct, &cam_frame, &cam_frame);
1842         }
1843         else {
1844                 cam_frame.xmin = ar->winrct.xmin;
1845                 cam_frame.xmax = ar->winrct.xmax;
1846                 cam_frame.ymin = ar->winrct.ymin;
1847                 cam_frame.ymax = ar->winrct.ymax;
1848         }
1849
1850
1851         SaveState(C, prevwin);
1852
1853         StartKetsjiShell(C, ar, &cam_frame, 1);
1854
1855         /* window wasnt closed while the BGE was running */
1856         if (BLI_findindex(&CTX_wm_manager(C)->windows, prevwin) == -1) {
1857                 prevwin = NULL;
1858                 CTX_wm_window_set(C, NULL);
1859         }
1860         
1861         ED_area_tag_redraw(CTX_wm_area(C));
1862
1863         if (prevwin) {
1864                 /* restore context, in case it changed in the meantime, for
1865                  * example by working in another window or closing it */
1866                 CTX_wm_region_set(C, prevar);
1867                 CTX_wm_window_set(C, prevwin);
1868                 CTX_wm_area_set(C, prevsa);
1869         }
1870
1871         RestoreState(C, prevwin);
1872
1873         //XXX restore_all_scene_cfra(scene_cfra_store);
1874         BKE_scene_set_background(CTX_data_main(C), startscene);
1875         //XXX BKE_scene_update_for_newframe(bmain, scene, scene->lay);
1876
1877         return OPERATOR_FINISHED;
1878 #else
1879         (void)C; /* unused */
1880         BKE_report(op->reports, RPT_ERROR, "Game engine is disabled in this build");
1881         return OPERATOR_CANCELLED;
1882 #endif
1883 }
1884
1885 void VIEW3D_OT_game_start(wmOperatorType *ot)
1886 {
1887         
1888         /* identifiers */
1889         ot->name = "Start Game Engine";
1890         ot->description = "Start game engine";
1891         ot->idname = "VIEW3D_OT_game_start";
1892         
1893         /* api callbacks */
1894         ot->exec = game_engine_exec;
1895         
1896         ot->poll = game_engine_poll;
1897 }
1898
1899 /* ************************************** */
1900
1901 static void UNUSED_FUNCTION(view3d_align_axis_to_vector)(View3D *v3d, RegionView3D *rv3d, int axisidx, float vec[3])
1902 {
1903         float alignaxis[3] = {0.0, 0.0, 0.0};
1904         float norm[3], axis[3], angle, new_quat[4];
1905         
1906         if (axisidx > 0) alignaxis[axisidx - 1] = 1.0;
1907         else alignaxis[-axisidx - 1] = -1.0;
1908
1909         normalize_v3_v3(norm, vec);
1910
1911         angle = (float)acos(dot_v3v3(alignaxis, norm));
1912         cross_v3_v3v3(axis, alignaxis, norm);
1913         axis_angle_to_quat(new_quat, axis, -angle);
1914         
1915         rv3d->view = RV3D_VIEW_USER;
1916         
1917         if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
1918                 /* switch out of camera view */
1919                 float orig_ofs[3];
1920                 float orig_dist = rv3d->dist;
1921                 float orig_lens = v3d->lens;
1922                 
1923                 copy_v3_v3(orig_ofs, rv3d->ofs);
1924                 rv3d->persp = RV3D_PERSP;
1925                 rv3d->dist = 0.0;
1926                 ED_view3d_from_object(v3d->camera, rv3d->ofs, NULL, NULL, &v3d->lens);
1927                 view3d_smooth_view(NULL, NULL, NULL, NULL, NULL, orig_ofs, new_quat, &orig_dist, &orig_lens); /* XXX */
1928         }
1929         else {
1930                 if (rv3d->persp == RV3D_CAMOB) rv3d->persp = RV3D_PERSP;  /* switch out of camera mode */
1931                 view3d_smooth_view(NULL, NULL, NULL, NULL, NULL, NULL, new_quat, NULL, NULL); /* XXX */
1932         }
1933 }
1934
1935 float ED_view3d_pixel_size(struct RegionView3D *rv3d, const float co[3])
1936 {
1937         return (rv3d->persmat[3][3] + (
1938                     rv3d->persmat[0][3] * co[0] +
1939                     rv3d->persmat[1][3] * co[1] +
1940                     rv3d->persmat[2][3] * co[2])
1941                 ) * rv3d->pixsize;
1942 }
1943
1944 /* view matrix properties utilities */
1945
1946 /* unused */
1947 #if 0
1948 void ED_view3d_operator_properties_viewmat(wmOperatorType *ot)
1949 {
1950         PropertyRNA *prop;
1951
1952         prop = RNA_def_int(ot->srna, "region_width", 0, 0, INT_MAX, "Region Width", "", 0, INT_MAX);
1953         RNA_def_property_flag(prop, PROP_HIDDEN);
1954
1955         prop = RNA_def_int(ot->srna, "region_height", 0, 0, INT_MAX, "Region height", "", 0, INT_MAX);
1956         RNA_def_property_flag(prop, PROP_HIDDEN);
1957
1958         prop = RNA_def_float_matrix(ot->srna, "perspective_matrix", 4, 4, NULL, 0.0f, 0.0f, "", "Perspective Matrix", 0.0f, 0.0f);
1959         RNA_def_property_flag(prop, PROP_HIDDEN);
1960 }
1961
1962 void ED_view3d_operator_properties_viewmat_set(bContext *C, wmOperator *op)
1963 {
1964         ARegion *ar = CTX_wm_region(C);
1965         RegionView3D *rv3d = ED_view3d_context_rv3d(C);
1966
1967         if (!RNA_struct_property_is_set(op->ptr, "region_width"))
1968                 RNA_int_set(op->ptr, "region_width", ar->winx);
1969
1970         if (!RNA_struct_property_is_set(op->ptr, "region_height"))
1971                 RNA_int_set(op->ptr, "region_height", ar->winy);
1972
1973         if (!RNA_struct_property_is_set(op->ptr, "perspective_matrix"))
1974                 RNA_float_set_array(op->ptr, "perspective_matrix", (float *)rv3d->persmat);
1975 }
1976
1977 void ED_view3d_operator_properties_viewmat_get(wmOperator *op, int *winx, int *winy, float persmat[4][4])
1978 {
1979         *winx = RNA_int_get(op->ptr, "region_width");
1980         *winy = RNA_int_get(op->ptr, "region_height");
1981
1982         RNA_float_get_array(op->ptr, "perspective_matrix", (float *)persmat);
1983 }
1984 #endif