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