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