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