Blender  V2.59
view3d_view.c
Go to the documentation of this file.
00001 /*
00002  * $Id: view3d_view.c 38964 2011-08-03 05:32:07Z campbellbarton $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version. 
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * The Original Code is Copyright (C) 2008 Blender Foundation.
00021  * All rights reserved.
00022  *
00023  * 
00024  * Contributor(s): Blender Foundation
00025  *
00026  * ***** END GPL LICENSE BLOCK *****
00027  */
00028 
00034 #include "DNA_camera_types.h"
00035 #include "DNA_scene_types.h"
00036 #include "DNA_object_types.h"
00037 #include "DNA_lamp_types.h"
00038 
00039 #include "MEM_guardedalloc.h"
00040 
00041 #include "BLI_math.h"
00042 #include "BLI_rect.h"
00043 #include "BLI_listbase.h"
00044 #include "BLI_utildefines.h"
00045 
00046 #include "BKE_anim.h"
00047 #include "BKE_action.h"
00048 #include "BKE_context.h"
00049 #include "BKE_depsgraph.h"
00050 #include "BKE_object.h"
00051 #include "BKE_global.h"
00052 #include "BKE_main.h"
00053 #include "BKE_report.h"
00054 #include "BKE_scene.h"
00055 #include "BKE_screen.h"
00056 
00057 #include "BIF_gl.h"
00058 #include "BIF_glutil.h"
00059 
00060 #include "GPU_draw.h"
00061 
00062 #include "WM_api.h"
00063 #include "WM_types.h"
00064 
00065 #include "ED_screen.h"
00066 #include "ED_armature.h"
00067 
00068 #ifdef WITH_GAMEENGINE
00069 #include "BL_System.h"
00070 #endif
00071 
00072 #include "view3d_intern.h"      // own include
00073 
00074 /* use this call when executing an operator,
00075    event system doesn't set for each event the
00076    opengl drawing context */
00077 void view3d_operator_needs_opengl(const bContext *C)
00078 {
00079         wmWindow *win = CTX_wm_window(C);
00080         ARegion *ar= CTX_wm_region(C);
00081         
00082         view3d_region_operator_needs_opengl(win, ar);
00083 }
00084 
00085 void view3d_region_operator_needs_opengl(wmWindow *win, ARegion *ar)
00086 {
00087         /* for debugging purpose, context should always be OK */
00088         if ((ar == NULL) || (ar->regiontype!=RGN_TYPE_WINDOW))
00089                 printf("view3d_region_operator_needs_opengl error, wrong region\n");
00090         else {
00091                 RegionView3D *rv3d= ar->regiondata;
00092                 
00093                 wmSubWindowSet(win, ar->swinid);
00094                 glMatrixMode(GL_PROJECTION);
00095                 glLoadMatrixf(rv3d->winmat);
00096                 glMatrixMode(GL_MODELVIEW);
00097                 glLoadMatrixf(rv3d->viewmat);
00098         }
00099 }
00100 
00101 float *give_cursor(Scene *scene, View3D *v3d)
00102 {
00103         if(v3d && v3d->localvd) return v3d->cursor;
00104         else return scene->cursor;
00105 }
00106 
00107 
00108 /* Gets the lens and clipping values from a camera of lamp type object */
00109 void ED_view3d_ob_clip_range_get(Object *ob, float *lens, float *clipsta, float *clipend)
00110 {
00111         if(ob->type==OB_LAMP ) {
00112                 Lamp *la = ob->data;
00113                 if (lens) {
00114                         float x1, fac;
00115                         fac= cosf((float)M_PI*la->spotsize/360.0f);
00116                         x1= saacos(fac);
00117                         *lens= 16.0f*fac/sinf(x1);
00118                 }
00119                 if (clipsta)    *clipsta= la->clipsta;
00120                 if (clipend)    *clipend= la->clipend;
00121         }
00122         else if(ob->type==OB_CAMERA) {
00123                 Camera *cam= ob->data;
00124                 if (lens)               *lens= cam->lens;
00125                 if (clipsta)    *clipsta= cam->clipsta;
00126                 if (clipend)    *clipend= cam->clipend;
00127         }
00128         else {
00129                 if (lens)               *lens= 35.0f;
00130         }
00131 }
00132 
00133 /* ****************** smooth view operator ****************** */
00134 /* This operator is one of the 'timer refresh' ones like animation playback */
00135 
00136 struct SmoothViewStore {
00137         float orig_dist, new_dist;
00138         float orig_lens, new_lens;
00139         float orig_quat[4], new_quat[4];
00140         float orig_ofs[3], new_ofs[3];
00141         
00142         int to_camera, orig_view;
00143         
00144         double time_allowed;
00145 };
00146 
00147 /* will start timer if appropriate */
00148 /* the arguments are the desired situation */
00149 void smooth_view(bContext *C, View3D *v3d, ARegion *ar, Object *oldcamera, Object *camera, float *ofs, float *quat, float *dist, float *lens)
00150 {
00151         wmWindowManager *wm= CTX_wm_manager(C);
00152         wmWindow *win= CTX_wm_window(C);
00153         ScrArea *sa= CTX_wm_area(C);
00154 
00155         RegionView3D *rv3d= ar->regiondata;
00156         struct SmoothViewStore sms= {0};
00157         short ok= FALSE;
00158         
00159         /* initialize sms */
00160         copy_v3_v3(sms.new_ofs, rv3d->ofs);
00161         copy_qt_qt(sms.new_quat, rv3d->viewquat);
00162         sms.new_dist= rv3d->dist;
00163         sms.new_lens= v3d->lens;
00164         sms.to_camera= 0;
00165 
00166         /* note on camera locking, this is a little confusing but works ok.
00167          * we may be changing the view 'as if' there is no active camera, but infact
00168          * there is an active camera which is locked to the view.
00169          *
00170          * In the case where smooth view is moving _to_ a camera we dont want that
00171          * camera to be moved or changed, so only when the camera is not being set should
00172          * we allow camera option locking to initialize the view settings from the camera.
00173          */
00174         if(camera == NULL && oldcamera == NULL) {
00175                 ED_view3d_camera_lock_init(v3d, rv3d);
00176         }
00177 
00178         /* store the options we want to end with */
00179         if(ofs) copy_v3_v3(sms.new_ofs, ofs);
00180         if(quat) copy_qt_qt(sms.new_quat, quat);
00181         if(dist) sms.new_dist= *dist;
00182         if(lens) sms.new_lens= *lens;
00183 
00184         if (camera) {
00185                 ED_view3d_from_object(camera, sms.new_ofs, sms.new_quat, &sms.new_dist, &sms.new_lens);
00186                 sms.to_camera= 1; /* restore view3d values in end */
00187         }
00188         
00189         if (C && U.smooth_viewtx) {
00190                 int changed = 0; /* zero means no difference */
00191                 
00192                 if (oldcamera != camera)
00193                         changed = 1;
00194                 else if (sms.new_dist != rv3d->dist)
00195                         changed = 1;
00196                 else if (sms.new_lens != v3d->lens)
00197                         changed = 1;
00198                 else if (!equals_v3v3(sms.new_ofs, rv3d->ofs))
00199                         changed = 1;
00200                 else if (!equals_v4v4(sms.new_quat, rv3d->viewquat))
00201                         changed = 1;
00202                 
00203                 /* The new view is different from the old one
00204                         * so animate the view */
00205                 if (changed) {
00206 
00207                         /* original values */
00208                         if (oldcamera) {
00209                                 sms.orig_dist= rv3d->dist; // below function does weird stuff with it...
00210                                 ED_view3d_from_object(oldcamera, sms.orig_ofs, sms.orig_quat, &sms.orig_dist, &sms.orig_lens);
00211                         }
00212                         else {
00213                                 copy_v3_v3(sms.orig_ofs, rv3d->ofs);
00214                                 copy_qt_qt(sms.orig_quat, rv3d->viewquat);
00215                                 sms.orig_dist= rv3d->dist;
00216                                 sms.orig_lens= v3d->lens;
00217                         }
00218                         /* grid draw as floor */
00219                         if((rv3d->viewlock & RV3D_LOCKED)==0) {
00220                                 /* use existing if exists, means multiple calls to smooth view wont loose the original 'view' setting */
00221                                 sms.orig_view= rv3d->sms ? rv3d->sms->orig_view : rv3d->view;
00222                                 rv3d->view= RV3D_VIEW_USER;
00223                         }
00224 
00225                         sms.time_allowed= (double)U.smooth_viewtx / 1000.0;
00226                         
00227                         /* if this is view rotation only
00228                                 * we can decrease the time allowed by
00229                                 * the angle between quats 
00230                                 * this means small rotations wont lag */
00231                         if (quat && !ofs && !dist) {
00232                                 float vec1[3]={0,0,1}, vec2[3]= {0,0,1};
00233                                 float q1[4], q2[4];
00234 
00235                                 invert_qt_qt(q1, sms.new_quat);
00236                                 invert_qt_qt(q2, sms.orig_quat);
00237 
00238                                 mul_qt_v3(q1, vec1);
00239                                 mul_qt_v3(q2, vec2);
00240 
00241                                 /* scale the time allowed by the rotation */
00242                                 sms.time_allowed *= (double)angle_v3v3(vec1, vec2) / M_PI; /* 180deg == 1.0 */
00243                         }
00244 
00245                         /* ensure it shows correct */
00246                         if(sms.to_camera) rv3d->persp= RV3D_PERSP;
00247 
00248                         rv3d->rflag |= RV3D_NAVIGATING;
00249                         
00250                         /* keep track of running timer! */
00251                         if(rv3d->sms==NULL)
00252                                 rv3d->sms= MEM_mallocN(sizeof(struct SmoothViewStore), "smoothview v3d");
00253                         *rv3d->sms= sms;
00254                         if(rv3d->smooth_timer)
00255                                 WM_event_remove_timer(wm, win, rv3d->smooth_timer);
00256                         /* TIMER1 is hardcoded in keymap */
00257                         rv3d->smooth_timer= WM_event_add_timer(wm, win, TIMER1, 1.0/100.0);     /* max 30 frs/sec */
00258                         
00259                         ok= TRUE;
00260                 }
00261         }
00262         
00263         /* if we get here nothing happens */
00264         if(ok == FALSE) {
00265                 if(sms.to_camera==0) {
00266                         copy_v3_v3(rv3d->ofs, sms.new_ofs);
00267                         copy_qt_qt(rv3d->viewquat, sms.new_quat);
00268                         rv3d->dist = sms.new_dist;
00269                         v3d->lens = sms.new_lens;
00270                 }
00271 
00272                 if(rv3d->viewlock & RV3D_BOXVIEW)
00273                         view3d_boxview_copy(sa, ar);
00274 
00275                 ED_region_tag_redraw(ar);
00276         }
00277 }
00278 
00279 /* only meant for timer usage */
00280 static int view3d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
00281 {
00282         View3D *v3d = CTX_wm_view3d(C);
00283         RegionView3D *rv3d= CTX_wm_region_view3d(C);
00284         struct SmoothViewStore *sms= rv3d->sms;
00285         float step, step_inv;
00286         
00287         /* escape if not our timer */
00288         if(rv3d->smooth_timer==NULL || rv3d->smooth_timer!=event->customdata)
00289                 return OPERATOR_PASS_THROUGH;
00290         
00291         if(sms->time_allowed != 0.0)
00292                 step = (float)((rv3d->smooth_timer->duration)/sms->time_allowed);
00293         else
00294                 step = 1.0f;
00295         
00296         /* end timer */
00297         if(step >= 1.0f) {
00298                 
00299                 /* if we went to camera, store the original */
00300                 if(sms->to_camera) {
00301                         rv3d->persp= RV3D_CAMOB;
00302                         copy_v3_v3(rv3d->ofs, sms->orig_ofs);
00303                         copy_qt_qt(rv3d->viewquat, sms->orig_quat);
00304                         rv3d->dist = sms->orig_dist;
00305                         v3d->lens = sms->orig_lens;
00306                 }
00307                 else {
00308                         copy_v3_v3(rv3d->ofs, sms->new_ofs);
00309                         copy_qt_qt(rv3d->viewquat, sms->new_quat);
00310                         rv3d->dist = sms->new_dist;
00311                         v3d->lens = sms->new_lens;
00312 
00313                         ED_view3d_camera_lock_sync(v3d, rv3d);
00314                 }
00315                 
00316                 if((rv3d->viewlock & RV3D_LOCKED)==0) {
00317                         rv3d->view= sms->orig_view;
00318                 }
00319 
00320                 MEM_freeN(rv3d->sms);
00321                 rv3d->sms= NULL;
00322                 
00323                 WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), rv3d->smooth_timer);
00324                 rv3d->smooth_timer= NULL;
00325                 rv3d->rflag &= ~RV3D_NAVIGATING;
00326         }
00327         else {
00328                 int i;
00329                 
00330                 /* ease in/out */
00331                 if (step < 0.5f)        step = (float)pow(step*2.0f, 2.0)/2.0f;
00332                 else                            step = (float)1.0f-(powf(2.0f*(1.0f-step),2.0f)/2.0f);
00333 
00334                 step_inv = 1.0f-step;
00335 
00336                 for (i=0; i<3; i++)
00337                         rv3d->ofs[i] = sms->new_ofs[i] * step + sms->orig_ofs[i]*step_inv;
00338 
00339                 interp_qt_qtqt(rv3d->viewquat, sms->orig_quat, sms->new_quat, step);
00340                 
00341                 rv3d->dist = sms->new_dist * step + sms->orig_dist*step_inv;
00342                 v3d->lens = sms->new_lens * step + sms->orig_lens*step_inv;
00343 
00344                 ED_view3d_camera_lock_sync(v3d, rv3d);
00345         }
00346         
00347         if(rv3d->viewlock & RV3D_BOXVIEW)
00348                 view3d_boxview_copy(CTX_wm_area(C), CTX_wm_region(C));
00349         
00350         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, v3d);
00351         
00352         return OPERATOR_FINISHED;
00353 }
00354 
00355 void VIEW3D_OT_smoothview(wmOperatorType *ot)
00356 {
00357         
00358         /* identifiers */
00359         ot->name= "Smooth View";
00360         ot->idname= "VIEW3D_OT_smoothview";
00361         ot->description="The time to animate the change of view (in milliseconds)";
00362         
00363         /* api callbacks */
00364         ot->invoke= view3d_smoothview_invoke;
00365         
00366         ot->poll= ED_operator_view3d_active;
00367 }
00368 
00369 /* ****************** change view operators ****************** */
00370 
00371 static int view3d_setcameratoview_exec(bContext *C, wmOperator *UNUSED(op))
00372 {
00373         View3D *v3d = CTX_wm_view3d(C);
00374         RegionView3D *rv3d= CTX_wm_region_view3d(C);
00375 
00376         copy_qt_qt(rv3d->lviewquat, rv3d->viewquat);
00377         rv3d->lview= rv3d->view;
00378         if(rv3d->persp != RV3D_CAMOB) {
00379                 rv3d->lpersp= rv3d->persp;
00380         }
00381 
00382         ED_view3d_to_object(v3d->camera, rv3d->ofs, rv3d->viewquat, rv3d->dist);
00383         DAG_id_tag_update(&v3d->camera->id, OB_RECALC_OB);
00384         rv3d->persp = RV3D_CAMOB;
00385         
00386         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, v3d->camera);
00387         
00388         return OPERATOR_FINISHED;
00389 
00390 }
00391 
00392 static int view3d_setcameratoview_poll(bContext *C)
00393 {
00394         View3D *v3d= CTX_wm_view3d(C);
00395         if(v3d && v3d->camera && v3d->camera->id.lib==NULL) {
00396                 RegionView3D *rv3d= CTX_wm_region_view3d(C);
00397                 if(rv3d && !rv3d->viewlock) {
00398                         return 1;
00399                 }
00400         }
00401 
00402         return 0;
00403 }
00404 
00405 void VIEW3D_OT_setcameratoview(wmOperatorType *ot)
00406 {
00407         
00408         /* identifiers */
00409         ot->name= "Align Camera To View";
00410         ot->description= "Set camera view to active view";
00411         ot->idname= "VIEW3D_OT_camera_to_view";
00412         
00413         /* api callbacks */
00414         ot->exec= view3d_setcameratoview_exec;  
00415         ot->poll= view3d_setcameratoview_poll;
00416         
00417         /* flags */
00418         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00419 }
00420 
00421 
00422 static int view3d_setobjectascamera_exec(bContext *C, wmOperator *UNUSED(op))
00423 {
00424         View3D *v3d = CTX_wm_view3d(C);
00425         ARegion *ar= ED_view3d_context_region_unlock(C);
00426         RegionView3D *rv3d= ar->regiondata; /* no NULL check is needed, poll checks */
00427         Scene *scene= CTX_data_scene(C);
00428         Object *ob = CTX_data_active_object(C);
00429 
00430         if(ob) {
00431                 Object *camera_old= (rv3d->persp == RV3D_CAMOB) ? V3D_CAMERA_SCENE(scene, v3d) : NULL;
00432                 rv3d->persp= RV3D_CAMOB;
00433                 v3d->camera= ob;
00434                 if(v3d->scenelock)
00435                         scene->camera= ob;
00436 
00437                 if(camera_old != ob) /* unlikely but looks like a glitch when set to the same */
00438                         smooth_view(C, v3d, ar, camera_old, v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, &v3d->lens);
00439 
00440                 WM_event_add_notifier(C, NC_SCENE|ND_RENDER_OPTIONS|NC_OBJECT|ND_DRAW, CTX_data_scene(C));
00441         }
00442         
00443         return OPERATOR_FINISHED;
00444 }
00445 
00446 int ED_operator_rv3d_unlock_poll(bContext *C)
00447 {
00448         return ED_view3d_context_region_unlock(C) != NULL;
00449 }
00450 
00451 void VIEW3D_OT_object_as_camera(wmOperatorType *ot)
00452 {
00453         
00454         /* identifiers */
00455         ot->name= "Set Active Object as Camera";
00456         ot->description= "Set the active object as the active camera for this view or scene";
00457         ot->idname= "VIEW3D_OT_object_as_camera";
00458         
00459         /* api callbacks */
00460         ot->exec= view3d_setobjectascamera_exec;        
00461         ot->poll= ED_operator_rv3d_unlock_poll;
00462         
00463         /* flags */
00464         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00465 }
00466 
00467 /* ********************************** */
00468 
00469 void ED_view3d_calc_clipping(BoundBox *bb, float planes[4][4], bglMats *mats, rcti *rect)
00470 {
00471         float modelview[4][4];
00472         double xs, ys, p[3];
00473         int val, flip_sign, a;
00474 
00475         /* near zero floating point values can give issues with gluUnProject
00476                 in side view on some implementations */
00477         if(fabs(mats->modelview[0]) < 1e-6) mats->modelview[0]= 0.0;
00478         if(fabs(mats->modelview[5]) < 1e-6) mats->modelview[5]= 0.0;
00479 
00480         /* Set up viewport so that gluUnProject will give correct values */
00481         mats->viewport[0] = 0;
00482         mats->viewport[1] = 0;
00483 
00484         /* four clipping planes and bounding volume */
00485         /* first do the bounding volume */
00486         for(val=0; val<4; val++) {
00487                 xs= (val==0||val==3)?rect->xmin:rect->xmax;
00488                 ys= (val==0||val==1)?rect->ymin:rect->ymax;
00489 
00490                 gluUnProject(xs, ys, 0.0, mats->modelview, mats->projection, mats->viewport, &p[0], &p[1], &p[2]);
00491                 VECCOPY(bb->vec[val], p);
00492 
00493                 gluUnProject(xs, ys, 1.0, mats->modelview, mats->projection, mats->viewport, &p[0], &p[1], &p[2]);
00494                 VECCOPY(bb->vec[4+val], p);
00495         }
00496 
00497         /* verify if we have negative scale. doing the transform before cross
00498            product flips the sign of the vector compared to doing cross product
00499            before transform then, so we correct for that. */
00500         for(a=0; a<16; a++)
00501                 ((float*)modelview)[a] = mats->modelview[a];
00502         flip_sign = is_negative_m4(modelview);
00503 
00504         /* then plane equations */
00505         for(val=0; val<4; val++) {
00506 
00507                 normal_tri_v3(planes[val], bb->vec[val], bb->vec[val==3?0:val+1], bb->vec[val+4]);
00508 
00509                 if(flip_sign)
00510                         negate_v3(planes[val]);
00511 
00512                 planes[val][3]= - planes[val][0]*bb->vec[val][0]
00513                         - planes[val][1]*bb->vec[val][1]
00514                         - planes[val][2]*bb->vec[val][2];
00515         }
00516 }
00517 
00518 /* create intersection coordinates in view Z direction at mouse coordinates */
00519 void ED_view3d_win_to_segment_clip(ARegion *ar, View3D *v3d, const float mval[2], float ray_start[3], float ray_end[3])
00520 {
00521         RegionView3D *rv3d= ar->regiondata;
00522         
00523         if(rv3d->is_persp) {
00524                 float vec[3];
00525                 ED_view3d_win_to_vector(ar, mval, vec);
00526 
00527                 copy_v3_v3(ray_start, rv3d->viewinv[3]);
00528                 VECADDFAC(ray_start, rv3d->viewinv[3], vec, v3d->near);
00529                 VECADDFAC(ray_end, rv3d->viewinv[3], vec, v3d->far);
00530         }
00531         else {
00532                 float vec[4];
00533                 vec[0] = 2.0f * mval[0] / ar->winx - 1;
00534                 vec[1] = 2.0f * mval[1] / ar->winy - 1;
00535                 vec[2] = 0.0f;
00536                 vec[3] = 1.0f;
00537                 
00538                 mul_m4_v4(rv3d->persinv, vec);
00539                 
00540                 VECADDFAC(ray_start, vec, rv3d->viewinv[2],  1000.0f);
00541                 VECADDFAC(ray_end, vec, rv3d->viewinv[2], -1000.0f);
00542         }
00543 
00544         /* clipping */
00545         if(rv3d->rflag & RV3D_CLIPPING) {
00546                 int a;
00547                 for(a=0; a<4; a++) {
00548                         clip_line_plane(ray_start, ray_end, rv3d->clip[a]);
00549                 }
00550         }
00551 }
00552 
00553 /* create intersection ray in view Z direction at mouse coordinates */
00554 void ED_view3d_win_to_ray(ARegion *ar, View3D *v3d, const float mval[2], float ray_start[3], float ray_normal[3])
00555 {
00556         float ray_end[3];
00557         
00558         ED_view3d_win_to_segment_clip(ar, v3d, mval, ray_start, ray_end);
00559         sub_v3_v3v3(ray_normal, ray_end, ray_start);
00560         normalize_v3(ray_normal);
00561 }
00562 
00563 void ED_view3d_global_to_vector(RegionView3D *rv3d, const float coord[3], float vec[3])
00564 {
00565         if (rv3d->is_persp) {
00566                 float p1[4], p2[4];
00567 
00568                 copy_v3_v3(p1, coord);
00569                 p1[3] = 1.0f;
00570                 copy_v3_v3(p2, p1);
00571                 p2[3] = 1.0f;
00572                 mul_m4_v4(rv3d->viewmat, p2);
00573 
00574                 mul_v3_fl(p2, 2.0f);
00575 
00576                 mul_m4_v4(rv3d->viewinv, p2);
00577 
00578                 sub_v3_v3v3(vec, p1, p2);
00579         }
00580         else {
00581                 copy_v3_v3(vec, rv3d->viewinv[2]);
00582         }
00583         normalize_v3(vec);
00584 }
00585 
00586 int initgrabz(RegionView3D *rv3d, float x, float y, float z)
00587 {
00588         int flip= FALSE;
00589         if(rv3d==NULL) return flip;
00590         rv3d->zfac= rv3d->persmat[0][3]*x+ rv3d->persmat[1][3]*y+ rv3d->persmat[2][3]*z+ rv3d->persmat[3][3];
00591         if (rv3d->zfac < 0.0f)
00592                 flip= TRUE;
00593         /* if x,y,z is exactly the viewport offset, zfac is 0 and we don't want that 
00594                 * (accounting for near zero values)
00595                 * */
00596         if (rv3d->zfac < 1.e-6f && rv3d->zfac > -1.e-6f) rv3d->zfac = 1.0f;
00597         
00598         /* Negative zfac means x, y, z was behind the camera (in perspective).
00599                 * This gives flipped directions, so revert back to ok default case.
00600         */
00601         // NOTE: I've changed this to flip zfac to be positive again for now so that GPencil draws ok
00602         //      -- Aligorith, 2009Aug31
00603         //if (rv3d->zfac < 0.0f) rv3d->zfac = 1.0f;
00604         if (rv3d->zfac < 0.0f) rv3d->zfac= -rv3d->zfac;
00605         
00606         return flip;
00607 }
00608 
00609 void ED_view3d_win_to_3d(ARegion *ar, const float depth_pt[3], const float mval[2], float out[3])
00610 {
00611         RegionView3D *rv3d= ar->regiondata;
00612         
00613         float line_sta[3];
00614         float line_end[3];
00615 
00616         if(rv3d->is_persp) {
00617                 float mousevec[3];
00618                 copy_v3_v3(line_sta, rv3d->viewinv[3]);
00619                 ED_view3d_win_to_vector(ar, mval, mousevec);
00620                 add_v3_v3v3(line_end, line_sta, mousevec);
00621 
00622                 if(isect_line_plane_v3(out, line_sta, line_end, depth_pt, rv3d->viewinv[2], TRUE) == 0) {
00623                         /* highly unlikely to ever happen, mouse vec paralelle with view plane */
00624                         zero_v3(out);
00625                 }
00626         }
00627         else {
00628         const float dx= (2.0f * mval[0] / (float)ar->winx) - 1.0f;
00629         const float dy= (2.0f * mval[1] / (float)ar->winy) - 1.0f;
00630                 line_sta[0]= (rv3d->persinv[0][0] * dx) + (rv3d->persinv[1][0] * dy) + rv3d->viewinv[3][0];
00631                 line_sta[1]= (rv3d->persinv[0][1] * dx) + (rv3d->persinv[1][1] * dy) + rv3d->viewinv[3][1];
00632                 line_sta[2]= (rv3d->persinv[0][2] * dx) + (rv3d->persinv[1][2] * dy) + rv3d->viewinv[3][2];
00633 
00634                 add_v3_v3v3(line_end, line_sta, rv3d->viewinv[2]);
00635                 closest_to_line_v3(out, depth_pt, line_sta, line_end);
00636         }
00637 }
00638 
00639 /* always call initgrabz */
00640 /* only to detect delta motion */
00641 void ED_view3d_win_to_delta(ARegion *ar, const float mval[2], float out[3])
00642 {
00643         RegionView3D *rv3d= ar->regiondata;
00644         float dx, dy;
00645         
00646         dx= 2.0f*mval[0]*rv3d->zfac/ar->winx;
00647         dy= 2.0f*mval[1]*rv3d->zfac/ar->winy;
00648         
00649         out[0]= (rv3d->persinv[0][0]*dx + rv3d->persinv[1][0]*dy);
00650         out[1]= (rv3d->persinv[0][1]*dx + rv3d->persinv[1][1]*dy);
00651         out[2]= (rv3d->persinv[0][2]*dx + rv3d->persinv[1][2]*dy);
00652 }
00653 
00654 /* doesn't rely on initgrabz */
00655 /* for perspective view, get the vector direction to
00656  * the mouse cursor as a normalized vector */
00657 void ED_view3d_win_to_vector(ARegion *ar, const float mval[2], float out[3])
00658 {
00659         RegionView3D *rv3d= ar->regiondata;
00660 
00661         if(rv3d->is_persp) {
00662                 out[0]= 2.0f * (mval[0] / ar->winx) - 1.0f;
00663                 out[1]= 2.0f * (mval[1] / ar->winy) - 1.0f;
00664                 out[2]= -0.5f;
00665                 mul_project_m4_v3(rv3d->persinv, out);
00666                 sub_v3_v3(out, rv3d->viewinv[3]);
00667         }
00668         else {
00669                 copy_v3_v3(out, rv3d->viewinv[2]);
00670         }
00671         normalize_v3(out);
00672 }
00673 
00674 float ED_view3d_depth_read_cached(ViewContext *vc, int x, int y)
00675 {
00676         ViewDepths *vd = vc->rv3d->depths;
00677                 
00678         x -= vc->ar->winrct.xmin;
00679         y -= vc->ar->winrct.ymin;
00680 
00681         if(vd && vd->depths && x > 0 && y > 0 && x < vd->w && y < vd->h)
00682                 return vd->depths[y * vd->w + x];
00683         else
00684                 return 1;
00685 }
00686 
00687 void ED_view3d_depth_tag_update(RegionView3D *rv3d)
00688 {
00689         if(rv3d->depths)
00690                 rv3d->depths->damaged= 1;
00691 }
00692 
00693 void ED_view3d_ob_project_mat_get(RegionView3D *rv3d, Object *ob, float pmat[4][4])
00694 {
00695         float vmat[4][4];
00696         
00697         mul_m4_m4m4(vmat, ob->obmat, rv3d->viewmat);
00698         mul_m4_m4m4(pmat, vmat, rv3d->winmat);
00699 }
00700 
00701 #if 0
00702 /* Uses window coordinates (x,y) and depth component z to find a point in
00703    modelspace */
00704 void view3d_unproject(bglMats *mats, float out[3], const short x, const short y, const float z)
00705 {
00706         double ux, uy, uz;
00707 
00708                 gluUnProject(x,y,z, mats->modelview, mats->projection,
00709                          (GLint *)mats->viewport, &ux, &uy, &uz );
00710         out[0] = ux;
00711         out[1] = uy;
00712         out[2] = uz;
00713 }
00714 #endif
00715 
00716 /* use above call to get projecting mat */
00717 void ED_view3d_project_float(ARegion *ar, const float vec[3], float adr[2], float mat[4][4])
00718 {
00719         float vec4[4];
00720         
00721         adr[0]= IS_CLIPPED;
00722         copy_v3_v3(vec4, vec);
00723         vec4[3]= 1.0;
00724         
00725         mul_m4_v4(mat, vec4);
00726         
00727         if( vec4[3]>FLT_EPSILON ) {
00728                 adr[0] = (float)(ar->winx/2.0f)+(ar->winx/2.0f)*vec4[0]/vec4[3];        
00729                 adr[1] = (float)(ar->winy/2.0f)+(ar->winy/2.0f)*vec4[1]/vec4[3];
00730         } else {
00731                 adr[0] = adr[1] = 0.0f;
00732         }
00733 }
00734 
00735 int ED_view3d_boundbox_clip(RegionView3D *rv3d, float obmat[][4], BoundBox *bb)
00736 {
00737         /* return 1: draw */
00738         
00739         float mat[4][4];
00740         float vec[4], min, max;
00741         int a, flag= -1, fl;
00742         
00743         if(bb==NULL) return 1;
00744         if(bb->flag & OB_BB_DISABLED) return 1;
00745         
00746         mul_m4_m4m4(mat, obmat, rv3d->persmat);
00747         
00748         for(a=0; a<8; a++) {
00749                 copy_v3_v3(vec, bb->vec[a]);
00750                 vec[3]= 1.0;
00751                 mul_m4_v4(mat, vec);
00752                 max= vec[3];
00753                 min= -vec[3];
00754                 
00755                 fl= 0;
00756                 if(vec[0] < min) fl+= 1;
00757                 if(vec[0] > max) fl+= 2;
00758                 if(vec[1] < min) fl+= 4;
00759                 if(vec[1] > max) fl+= 8;
00760                 if(vec[2] < min) fl+= 16;
00761                 if(vec[2] > max) fl+= 32;
00762                 
00763                 flag &= fl;
00764                 if(flag==0) return 1;
00765         }
00766         
00767         return 0;
00768 }
00769 
00770 void project_short(ARegion *ar, const float vec[3], short adr[2])       /* clips */
00771 {
00772         RegionView3D *rv3d= ar->regiondata;
00773         float fx, fy, vec4[4];
00774         
00775         adr[0]= IS_CLIPPED;
00776         
00777         if(rv3d->rflag & RV3D_CLIPPING) {
00778                 if(ED_view3d_test_clipping(rv3d, vec, 0))
00779                         return;
00780         }
00781         
00782         copy_v3_v3(vec4, vec);
00783         vec4[3]= 1.0;
00784         mul_m4_v4(rv3d->persmat, vec4);
00785         
00786         if( vec4[3] > (float)BL_NEAR_CLIP ) {   /* 0.001 is the NEAR clipping cutoff for picking */
00787                 fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]);
00788                 
00789                 if( fx>0 && fx<ar->winx) {
00790                         
00791                         fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]);
00792                         
00793                         if(fy > 0.0f && fy < (float)ar->winy) {
00794                                 adr[0]= (short)floor(fx); 
00795                                 adr[1]= (short)floor(fy);
00796                         }
00797                 }
00798         }
00799 }
00800 
00801 void project_int(ARegion *ar, const float vec[3], int adr[2])
00802 {
00803         RegionView3D *rv3d= ar->regiondata;
00804         float fx, fy, vec4[4];
00805         
00806         adr[0]= (int)2140000000.0f;
00807         copy_v3_v3(vec4, vec);
00808         vec4[3]= 1.0;
00809         
00810         mul_m4_v4(rv3d->persmat, vec4);
00811         
00812         if( vec4[3] > (float)BL_NEAR_CLIP ) {   /* 0.001 is the NEAR clipping cutoff for picking */
00813                 fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]);
00814                 
00815                 if( fx>-2140000000.0f && fx<2140000000.0f) {
00816                         fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]);
00817                         
00818                         if(fy>-2140000000.0f && fy<2140000000.0f) {
00819                                 adr[0]= (int)floor(fx); 
00820                                 adr[1]= (int)floor(fy);
00821                         }
00822                 }
00823         }
00824 }
00825 
00826 void project_int_noclip(ARegion *ar, const float vec[3], int adr[2])
00827 {
00828         RegionView3D *rv3d= ar->regiondata;
00829         float fx, fy, vec4[4];
00830         
00831         copy_v3_v3(vec4, vec);
00832         vec4[3]= 1.0;
00833         
00834         mul_m4_v4(rv3d->persmat, vec4);
00835         
00836         if( fabs(vec4[3]) > BL_NEAR_CLIP ) {
00837                 fx = (ar->winx/2)*(1 + vec4[0]/vec4[3]);
00838                 fy = (ar->winy/2)*(1 + vec4[1]/vec4[3]);
00839                 
00840                 adr[0] = (int)floor(fx); 
00841                 adr[1] = (int)floor(fy);
00842         }
00843         else
00844         {
00845                 adr[0] = ar->winx / 2;
00846                 adr[1] = ar->winy / 2;
00847         }
00848 }
00849 
00850 void project_short_noclip(ARegion *ar, const float vec[3], short adr[2])
00851 {
00852         RegionView3D *rv3d= ar->regiondata;
00853         float fx, fy, vec4[4];
00854         
00855         adr[0]= IS_CLIPPED;
00856         copy_v3_v3(vec4, vec);
00857         vec4[3]= 1.0;
00858         
00859         mul_m4_v4(rv3d->persmat, vec4);
00860         
00861         if( vec4[3] > (float)BL_NEAR_CLIP ) {   /* 0.001 is the NEAR clipping cutoff for picking */
00862                 fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]);
00863                 
00864                 if( fx>-32700 && fx<32700) {
00865                         
00866                         fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]);
00867                         
00868                         if(fy > -32700.0f && fy < 32700.0f) {
00869                                 adr[0]= (short)floor(fx); 
00870                                 adr[1]= (short)floor(fy);
00871                         }
00872                 }
00873         }
00874 }
00875 
00876 void project_float(ARegion *ar, const float vec[3], float adr[2])
00877 {
00878         RegionView3D *rv3d= ar->regiondata;
00879         float vec4[4];
00880         
00881         adr[0]= IS_CLIPPED;
00882         copy_v3_v3(vec4, vec);
00883         vec4[3]= 1.0;
00884         
00885         mul_m4_v4(rv3d->persmat, vec4);
00886         
00887         if(vec4[3] > (float)BL_NEAR_CLIP) {
00888                 adr[0] = (float)(ar->winx/2.0f)+(ar->winx/2.0f)*vec4[0]/vec4[3];
00889                 adr[1] = (float)(ar->winy/2.0f)+(ar->winy/2.0f)*vec4[1]/vec4[3];
00890         }
00891 }
00892 
00893 void project_float_noclip(ARegion *ar, const float vec[3], float adr[2])
00894 {
00895         RegionView3D *rv3d= ar->regiondata;
00896         float vec4[4];
00897         
00898         copy_v3_v3(vec4, vec);
00899         vec4[3]= 1.0;
00900         
00901         mul_m4_v4(rv3d->persmat, vec4);
00902         
00903         if( fabs(vec4[3]) > BL_NEAR_CLIP ) {
00904                 adr[0] = (float)(ar->winx/2.0f)+(ar->winx/2.0f)*vec4[0]/vec4[3];
00905                 adr[1] = (float)(ar->winy/2.0f)+(ar->winy/2.0f)*vec4[1]/vec4[3];
00906         }
00907         else
00908         {
00909                 adr[0] = ar->winx / 2.0f;
00910                 adr[1] = ar->winy / 2.0f;
00911         }
00912 }
00913 
00914 /* copies logic of get_view3d_viewplane(), keep in sync */
00915 int ED_view3d_clip_range_get(View3D *v3d, RegionView3D *rv3d, float *clipsta, float *clipend)
00916 {
00917         int orth= 0;
00918 
00919         *clipsta= v3d->near;
00920         *clipend= v3d->far;
00921 
00922         if(rv3d->persp==RV3D_CAMOB) {
00923                 if(v3d->camera) {
00924                         if(v3d->camera->type==OB_LAMP ) {
00925                                 Lamp *la= v3d->camera->data;
00926                                 *clipsta= la->clipsta;
00927                                 *clipend= la->clipend;
00928                         }
00929                         else if(v3d->camera->type==OB_CAMERA) {
00930                                 Camera *cam= v3d->camera->data;
00931                                 *clipsta= cam->clipsta;
00932                                 *clipend= cam->clipend;
00933 
00934                                 if(cam->type==CAM_ORTHO)
00935                                         orth= 1;
00936                         }
00937                 }
00938         }
00939 
00940         if(rv3d->persp==RV3D_ORTHO) {
00941                 *clipend *= 0.5f;       // otherwise too extreme low zbuffer quality
00942                 *clipsta= - *clipend;
00943                 orth= 1;
00944         }
00945 
00946         return orth;
00947 }
00948 
00949 /* also exposed in previewrender.c */
00950 int ED_view3d_viewplane_get(View3D *v3d, RegionView3D *rv3d, int winxi, int winyi, rctf *viewplane, float *clipsta, float *clipend, float *pixsize)
00951 {
00952         Camera *cam=NULL;
00953         float lens, fac, x1, y1, x2, y2;
00954         float winx= (float)winxi, winy= (float)winyi;
00955         int orth= 0;
00956         
00957         lens= v3d->lens;        
00958         
00959         *clipsta= v3d->near;
00960         *clipend= v3d->far;
00961         
00962         if(rv3d->persp==RV3D_CAMOB) {
00963                 if(v3d->camera) {
00964                         if(v3d->camera->type==OB_LAMP ) {
00965                                 Lamp *la;
00966                                 
00967                                 la= v3d->camera->data;
00968                                 fac= cosf(((float)M_PI)*la->spotsize/360.0f);
00969                                 
00970                                 x1= saacos(fac);
00971                                 lens= 16.0f*fac/sinf(x1);
00972                                 
00973                                 *clipsta= la->clipsta;
00974                                 *clipend= la->clipend;
00975                         }
00976                         else if(v3d->camera->type==OB_CAMERA) {
00977                                 cam= v3d->camera->data;
00978                                 lens= cam->lens;
00979                                 *clipsta= cam->clipsta;
00980                                 *clipend= cam->clipend;
00981                         }
00982                 }
00983         }
00984         
00985         if(rv3d->persp==RV3D_ORTHO) {
00986                 if(winx>winy) x1= -rv3d->dist;
00987                 else x1= -winx*rv3d->dist/winy;
00988                 x2= -x1;
00989                 
00990                 if(winx>winy) y1= -winy*rv3d->dist/winx;
00991                 else y1= -rv3d->dist;
00992                 y2= -y1;
00993                 
00994                 *clipend *= 0.5f;       // otherwise too extreme low zbuffer quality
00995                 *clipsta= - *clipend;
00996                 orth= 1;
00997         }
00998         else {
00999                 /* fac for zoom, also used for camdx */
01000                 if(rv3d->persp==RV3D_CAMOB) {
01001                         fac= BKE_screen_view3d_zoom_to_fac((float)rv3d->camzoom) * 4.0f;
01002                 }
01003                 else {
01004                         fac= 2.0;
01005                 }
01006                 
01007                 /* viewplane size depends... */
01008                 if(cam && cam->type==CAM_ORTHO) {
01009                         /* ortho_scale == 1 means exact 1 to 1 mapping */
01010                         float dfac= 2.0f*cam->ortho_scale/fac;
01011                         
01012                         if(winx>winy) x1= -dfac;
01013                         else x1= -winx*dfac/winy;
01014                         x2= -x1;
01015                         
01016                         if(winx>winy) y1= -winy*dfac/winx;
01017                         else y1= -dfac;
01018                         y2= -y1;
01019                         orth= 1;
01020                 }
01021                 else {
01022                         float dfac;
01023                         
01024                         if(winx>winy) dfac= 64.0f/(fac*winx*lens);
01025                         else dfac= 64.0f/(fac*winy*lens);
01026                         
01027                         x1= - *clipsta * winx*dfac;
01028                         x2= -x1;
01029                         y1= - *clipsta * winy*dfac;
01030                         y2= -y1;
01031                         orth= 0;
01032                 }
01033                 /* cam view offset */
01034                 if(cam) {
01035                         float dx= 0.5f*fac*rv3d->camdx*(x2-x1);
01036                         float dy= 0.5f*fac*rv3d->camdy*(y2-y1);
01037 
01038                         /* shift offset */              
01039                         if(cam->type==CAM_ORTHO) {
01040                                 dx += cam->shiftx * cam->ortho_scale;
01041                                 dy += cam->shifty * cam->ortho_scale;
01042                         }
01043                         else {
01044                                 dx += cam->shiftx * (cam->clipsta / cam->lens) * 32.0f;
01045                                 dy += cam->shifty * (cam->clipsta / cam->lens) * 32.0f;
01046                         }
01047 
01048                         x1+= dx;
01049                         x2+= dx;
01050                         y1+= dy;
01051                         y2+= dy;
01052                 }
01053         }
01054         
01055         if(pixsize) {
01056                 float viewfac;
01057                 
01058                 if(orth) {
01059                         viewfac= (winx >= winy)? winx: winy;
01060                         *pixsize= 1.0f/viewfac;
01061                 }
01062                 else {
01063                         viewfac= (((winx >= winy)? winx: winy)*lens)/32.0f;
01064                         *pixsize= *clipsta/viewfac;
01065                 }
01066         }
01067         
01068         viewplane->xmin= x1;
01069         viewplane->ymin= y1;
01070         viewplane->xmax= x2;
01071         viewplane->ymax= y2;
01072         
01073         return orth;
01074 }
01075 
01076 void setwinmatrixview3d(ARegion *ar, View3D *v3d, rctf *rect)           /* rect: for picking */
01077 {
01078         RegionView3D *rv3d= ar->regiondata;
01079         rctf viewplane;
01080         float clipsta, clipend, x1, y1, x2, y2;
01081         int orth;
01082         
01083         orth= ED_view3d_viewplane_get(v3d, rv3d, ar->winx, ar->winy, &viewplane, &clipsta, &clipend, NULL);
01084         rv3d->is_persp= !orth;
01085 
01086         //      printf("%d %d %f %f %f %f %f %f\n", winx, winy, viewplane.xmin, viewplane.ymin, viewplane.xmax, viewplane.ymax, clipsta, clipend);
01087         x1= viewplane.xmin;
01088         y1= viewplane.ymin;
01089         x2= viewplane.xmax;
01090         y2= viewplane.ymax;
01091         
01092         if(rect) {              /* picking */
01093                 rect->xmin/= (float)ar->winx;
01094                 rect->xmin= x1+rect->xmin*(x2-x1);
01095                 rect->ymin/= (float)ar->winy;
01096                 rect->ymin= y1+rect->ymin*(y2-y1);
01097                 rect->xmax/= (float)ar->winx;
01098                 rect->xmax= x1+rect->xmax*(x2-x1);
01099                 rect->ymax/= (float)ar->winy;
01100                 rect->ymax= y1+rect->ymax*(y2-y1);
01101                 
01102                 if(orth) wmOrtho(rect->xmin, rect->xmax, rect->ymin, rect->ymax, -clipend, clipend);
01103                 else wmFrustum(rect->xmin, rect->xmax, rect->ymin, rect->ymax, clipsta, clipend);
01104                 
01105         }
01106         else {
01107                 if(orth) wmOrtho(x1, x2, y1, y2, clipsta, clipend);
01108                 else wmFrustum(x1, x2, y1, y2, clipsta, clipend);
01109         }
01110 
01111         /* update matrix in 3d view region */
01112         glGetFloatv(GL_PROJECTION_MATRIX, (float*)rv3d->winmat);
01113 }
01114 
01115 static void obmat_to_viewmat(View3D *v3d, RegionView3D *rv3d, Object *ob, short smooth)
01116 {
01117         float bmat[4][4];
01118         float tmat[3][3];
01119         
01120         rv3d->view= RV3D_VIEW_USER; /* dont show the grid */
01121         
01122         copy_m4_m4(bmat, ob->obmat);
01123         normalize_m4(bmat);
01124         invert_m4_m4(rv3d->viewmat, bmat);
01125         
01126         /* view quat calculation, needed for add object */
01127         copy_m3_m4(tmat, rv3d->viewmat);
01128         if (smooth) {
01129                 float new_quat[4];
01130                 if (rv3d->persp==RV3D_CAMOB && v3d->camera) {
01131                         /* were from a camera view */
01132                         
01133                         float orig_ofs[3];
01134                         float orig_dist= rv3d->dist;
01135                         float orig_lens= v3d->lens;
01136                         copy_v3_v3(orig_ofs, rv3d->ofs);
01137                         
01138                         /* Switch from camera view */
01139                         mat3_to_quat( new_quat,tmat);
01140                         
01141                         rv3d->persp=RV3D_PERSP;
01142                         rv3d->dist= 0.0;
01143                         
01144                         ED_view3d_from_object(v3d->camera, rv3d->ofs, NULL, NULL, &v3d->lens);
01145                         smooth_view(NULL, NULL, NULL, NULL, NULL, orig_ofs, new_quat, &orig_dist, &orig_lens); // XXX
01146                         
01147                         rv3d->persp=RV3D_CAMOB; /* just to be polite, not needed */
01148                         
01149                 } else {
01150                         mat3_to_quat( new_quat,tmat);
01151                         smooth_view(NULL, NULL, NULL, NULL, NULL, NULL, new_quat, NULL, NULL); // XXX
01152                 }
01153         } else {
01154                 mat3_to_quat( rv3d->viewquat,tmat);
01155         }
01156 }
01157 
01158 #define QUATSET(a, b, c, d, e)  a[0]=b; a[1]=c; a[2]=d; a[3]=e; 
01159 
01160 int ED_view3d_lock(RegionView3D *rv3d)
01161 {
01162         switch(rv3d->view) {
01163         case RV3D_VIEW_BOTTOM :
01164                 QUATSET(rv3d->viewquat,0.0, -1.0, 0.0, 0.0);
01165                 break;
01166 
01167         case RV3D_VIEW_BACK:
01168                 QUATSET(rv3d->viewquat,0.0, 0.0, (float)-cos(M_PI/4.0), (float)-cos(M_PI/4.0));
01169                 break;
01170 
01171         case RV3D_VIEW_LEFT:
01172                 QUATSET(rv3d->viewquat,0.5, -0.5, 0.5, 0.5);
01173                 break;
01174 
01175         case RV3D_VIEW_TOP:
01176                 QUATSET(rv3d->viewquat,1.0, 0.0, 0.0, 0.0);
01177                 break;
01178 
01179         case RV3D_VIEW_FRONT:
01180                 QUATSET(rv3d->viewquat,(float)cos(M_PI/4.0), (float)-sin(M_PI/4.0), 0.0, 0.0);
01181                 break;
01182 
01183         case RV3D_VIEW_RIGHT:
01184                 QUATSET(rv3d->viewquat, 0.5, -0.5, -0.5, -0.5);
01185                 break;
01186         default:
01187                 return FALSE;
01188         }
01189 
01190         return TRUE;
01191 }
01192 
01193 /* dont set windows active in here, is used by renderwin too */
01194 void setviewmatrixview3d(Scene *scene, View3D *v3d, RegionView3D *rv3d)
01195 {
01196         if(rv3d->persp==RV3D_CAMOB) {       /* obs/camera */
01197                 if(v3d->camera) {
01198                         where_is_object(scene, v3d->camera);    
01199                         obmat_to_viewmat(v3d, rv3d, v3d->camera, 0);
01200                 }
01201                 else {
01202                         quat_to_mat4( rv3d->viewmat,rv3d->viewquat);
01203                         rv3d->viewmat[3][2]-= rv3d->dist;
01204                 }
01205         }
01206         else {
01207                 /* should be moved to better initialize later on XXX */
01208                 if(rv3d->viewlock)
01209                         ED_view3d_lock(rv3d);
01210                 
01211                 quat_to_mat4( rv3d->viewmat,rv3d->viewquat);
01212                 if(rv3d->persp==RV3D_PERSP) rv3d->viewmat[3][2]-= rv3d->dist;
01213                 if(v3d->ob_centre) {
01214                         Object *ob= v3d->ob_centre;
01215                         float vec[3];
01216                         
01217                         copy_v3_v3(vec, ob->obmat[3]);
01218                         if(ob->type==OB_ARMATURE && v3d->ob_centre_bone[0]) {
01219                                 bPoseChannel *pchan= get_pose_channel(ob->pose, v3d->ob_centre_bone);
01220                                 if(pchan) {
01221                                         copy_v3_v3(vec, pchan->pose_mat[3]);
01222                                         mul_m4_v3(ob->obmat, vec);
01223                                 }
01224                         }
01225                         translate_m4( rv3d->viewmat,-vec[0], -vec[1], -vec[2]);
01226                 }
01227                 else if (v3d->ob_centre_cursor) {
01228                         float vec[3];
01229                         copy_v3_v3(vec, give_cursor(scene, v3d));
01230                         translate_m4(rv3d->viewmat, -vec[0], -vec[1], -vec[2]);
01231                 }
01232                 else translate_m4( rv3d->viewmat,rv3d->ofs[0], rv3d->ofs[1], rv3d->ofs[2]);
01233         }
01234 }
01235 
01236 /* IGLuint-> GLuint*/
01237 /* Warning: be sure to account for a negative return value
01238 *   This is an error, "Too many objects in select buffer"
01239 *   and no action should be taken (can crash blender) if this happens
01240 */
01241 short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int bufsize, rcti *input)
01242 {
01243         Scene *scene= vc->scene;
01244         View3D *v3d= vc->v3d;
01245         ARegion *ar= vc->ar;
01246         rctf rect;
01247         short code, hits;
01248         char dt, dtx;
01249         
01250         G.f |= G_PICKSEL;
01251         
01252         /* case not a border select */
01253         if(input->xmin==input->xmax) {
01254                 rect.xmin= input->xmin-12;      // seems to be default value for bones only now
01255                 rect.xmax= input->xmin+12;
01256                 rect.ymin= input->ymin-12;
01257                 rect.ymax= input->ymin+12;
01258         }
01259         else {
01260                 rect.xmin= input->xmin;
01261                 rect.xmax= input->xmax;
01262                 rect.ymin= input->ymin;
01263                 rect.ymax= input->ymax;
01264         }
01265         
01266         setwinmatrixview3d(ar, v3d, &rect);
01267         mul_m4_m4m4(vc->rv3d->persmat, vc->rv3d->viewmat, vc->rv3d->winmat);
01268         
01269         if(v3d->drawtype > OB_WIRE) {
01270                 v3d->zbuf= TRUE;
01271                 glEnable(GL_DEPTH_TEST);
01272         }
01273         
01274         if(vc->rv3d->rflag & RV3D_CLIPPING)
01275                 view3d_set_clipping(vc->rv3d);
01276         
01277         glSelectBuffer( bufsize, (GLuint *)buffer);
01278         glRenderMode(GL_SELECT);
01279         glInitNames();  /* these two calls whatfor? It doesnt work otherwise */
01280         glPushName(-1);
01281         code= 1;
01282         
01283         if(vc->obedit && vc->obedit->type==OB_MBALL) {
01284                 draw_object(scene, ar, v3d, BASACT, DRAW_PICKING|DRAW_CONSTCOLOR);
01285         }
01286         else if((vc->obedit && vc->obedit->type==OB_ARMATURE)) {
01287                 /* if not drawing sketch, draw bones */
01288                 if(!BDR_drawSketchNames(vc)) {
01289                         draw_object(scene, ar, v3d, BASACT, DRAW_PICKING|DRAW_CONSTCOLOR);
01290                 }
01291         }
01292         else {
01293                 Base *base;
01294                 
01295                 v3d->xray= TRUE;        // otherwise it postpones drawing
01296                 for(base= scene->base.first; base; base= base->next) {
01297                         if(base->lay & v3d->lay) {
01298                                 
01299                                 if (base->object->restrictflag & OB_RESTRICT_SELECT)
01300                                         base->selcol= 0;
01301                                 else {
01302                                         base->selcol= code;
01303                                         glLoadName(code);
01304                                         draw_object(scene, ar, v3d, base, DRAW_PICKING|DRAW_CONSTCOLOR);
01305                                         
01306                                         /* we draw group-duplicators for selection too */
01307                                         if((base->object->transflag & OB_DUPLI) && base->object->dup_group) {
01308                                                 ListBase *lb;
01309                                                 DupliObject *dob;
01310                                                 Base tbase;
01311                                                 
01312                                                 tbase.flag= OB_FROMDUPLI;
01313                                                 lb= object_duplilist(scene, base->object);
01314                                                 
01315                                                 for(dob= lb->first; dob; dob= dob->next) {
01316                                                         tbase.object= dob->ob;
01317                                                         copy_m4_m4(dob->ob->obmat, dob->mat);
01318                                                         
01319                                                         /* extra service: draw the duplicator in drawtype of parent */
01320                                                         /* MIN2 for the drawtype to allow bounding box objects in groups for lods */
01321                                                         dt= tbase.object->dt;   tbase.object->dt= MIN2(tbase.object->dt, base->object->dt);
01322                                                         dtx= tbase.object->dtx; tbase.object->dtx= base->object->dtx;
01323 
01324                                                         draw_object(scene, ar, v3d, &tbase, DRAW_PICKING|DRAW_CONSTCOLOR);
01325                                                         
01326                                                         tbase.object->dt= dt;
01327                                                         tbase.object->dtx= dtx;
01328 
01329                                                         copy_m4_m4(dob->ob->obmat, dob->omat);
01330                                                 }
01331                                                 free_object_duplilist(lb);
01332                                         }
01333                                         code++;
01334                                 }                               
01335                         }
01336                 }
01337                 v3d->xray= FALSE;       // restore
01338         }
01339         
01340         glPopName();    /* see above (pushname) */
01341         hits= glRenderMode(GL_RENDER);
01342         
01343         G.f &= ~G_PICKSEL;
01344         setwinmatrixview3d(ar, v3d, NULL);
01345         mul_m4_m4m4(vc->rv3d->persmat, vc->rv3d->viewmat, vc->rv3d->winmat);
01346         
01347         if(v3d->drawtype > OB_WIRE) {
01348                 v3d->zbuf= 0;
01349                 glDisable(GL_DEPTH_TEST);
01350         }
01351 // XXX  persp(PERSP_WIN);
01352         
01353         if(vc->rv3d->rflag & RV3D_CLIPPING)
01354                 view3d_clr_clipping();
01355         
01356         if(hits<0) printf("Too many objects in select buffer\n");       // XXX make error message
01357         
01358         return hits;
01359 }
01360 
01361 /* ********************** local view operator ******************** */
01362 
01363 static unsigned int free_localbit(Main *bmain)
01364 {
01365         unsigned int lay;
01366         ScrArea *sa;
01367         bScreen *sc;
01368         
01369         lay= 0;
01370         
01371         /* sometimes we loose a localview: when an area is closed */
01372         /* check all areas: which localviews are in use? */
01373         for(sc= bmain->screen.first; sc; sc= sc->id.next) {
01374                 for(sa= sc->areabase.first; sa; sa= sa->next) {
01375                         SpaceLink *sl= sa->spacedata.first;
01376                         for(; sl; sl= sl->next) {
01377                                 if(sl->spacetype==SPACE_VIEW3D) {
01378                                         View3D *v3d= (View3D*) sl;
01379                                         lay |= v3d->lay;
01380                                 }
01381                         }
01382                 }
01383         }
01384         
01385         if( (lay & 0x01000000)==0) return 0x01000000;
01386         if( (lay & 0x02000000)==0) return 0x02000000;
01387         if( (lay & 0x04000000)==0) return 0x04000000;
01388         if( (lay & 0x08000000)==0) return 0x08000000;
01389         if( (lay & 0x10000000)==0) return 0x10000000;
01390         if( (lay & 0x20000000)==0) return 0x20000000;
01391         if( (lay & 0x40000000)==0) return 0x40000000;
01392         if( (lay & 0x80000000)==0) return 0x80000000;
01393         
01394         return 0;
01395 }
01396 
01397 int ED_view3d_scene_layer_set(int lay, const int *values, int *active)
01398 {
01399         int i, tot= 0;
01400         
01401         /* ensure we always have some layer selected */
01402         for(i=0; i<20; i++)
01403                 if(values[i])
01404                         tot++;
01405         
01406         if(tot==0)
01407                 return lay;
01408         
01409         for(i=0; i<20; i++) {
01410                 
01411                 if (active) {
01412                         /* if this value has just been switched on, make that layer active */
01413                         if (values[i] && (lay & (1<<i))==0) {
01414                                 *active = (1<<i);
01415                         }
01416                 }
01417                         
01418                 if (values[i]) lay |= (1<<i);
01419                 else lay &= ~(1<<i);
01420         }
01421         
01422         /* ensure always an active layer */
01423         if (active && (lay & *active)==0) {
01424                 for(i=0; i<20; i++) {
01425                         if(lay & (1<<i)) {
01426                                 *active= 1<<i;
01427                                 break;
01428                         }
01429                 }
01430         }
01431         
01432         return lay;
01433 }
01434 
01435 static void initlocalview(Main *bmain, Scene *scene, ScrArea *sa)
01436 {
01437         View3D *v3d= sa->spacedata.first;
01438         Base *base;
01439         float size = 0.0, min[3], max[3], box[3];
01440         unsigned int locallay;
01441         int ok=0;
01442 
01443         if(v3d->localvd) return;
01444 
01445         INIT_MINMAX(min, max);
01446 
01447         locallay= free_localbit(bmain);
01448 
01449         if(locallay==0) {
01450                 printf("Sorry, no more than 8 localviews\n");   // XXX error 
01451                 ok= 0;
01452         }
01453         else {
01454                 if(scene->obedit) {
01455                         minmax_object(scene->obedit, min, max);
01456                         
01457                         ok= 1;
01458                 
01459                         BASACT->lay |= locallay;
01460                         scene->obedit->lay= BASACT->lay;
01461                 }
01462                 else {
01463                         for(base= FIRSTBASE; base; base= base->next) {
01464                                 if(TESTBASE(v3d, base))  {
01465                                         minmax_object(base->object, min, max);
01466                                         base->lay |= locallay;
01467                                         base->object->lay= base->lay;
01468                                         ok= 1;
01469                                 }
01470                         }
01471                 }
01472                 
01473                 box[0]= (max[0]-min[0]);
01474                 box[1]= (max[1]-min[1]);
01475                 box[2]= (max[2]-min[2]);
01476                 size= MAX3(box[0], box[1], box[2]);
01477                 if(size <= 0.01f) size= 0.01f;
01478         }
01479         
01480         if(ok) {
01481                 ARegion *ar;
01482                 
01483                 v3d->localvd= MEM_mallocN(sizeof(View3D), "localview");
01484                 
01485                 memcpy(v3d->localvd, v3d, sizeof(View3D));
01486 
01487                 for(ar= sa->regionbase.first; ar; ar= ar->next) {
01488                         if(ar->regiontype == RGN_TYPE_WINDOW) {
01489                                 RegionView3D *rv3d= ar->regiondata;
01490 
01491                                 rv3d->localvd= MEM_mallocN(sizeof(RegionView3D), "localview region");
01492                                 memcpy(rv3d->localvd, rv3d, sizeof(RegionView3D));
01493                                 
01494                                 rv3d->ofs[0]= -(min[0]+max[0])/2.0f;
01495                                 rv3d->ofs[1]= -(min[1]+max[1])/2.0f;
01496                                 rv3d->ofs[2]= -(min[2]+max[2])/2.0f;
01497 
01498                                 rv3d->dist= size;
01499                                 /* perspective should be a bit farther away to look nice */
01500                                 if(rv3d->persp==RV3D_ORTHO)
01501                                         rv3d->dist*= 0.7f;
01502 
01503                                 // correction for window aspect ratio
01504                                 if(ar->winy>2 && ar->winx>2) {
01505                                         float asp= (float)ar->winx/(float)ar->winy;
01506                                         if(asp < 1.0f) asp= 1.0f/asp;
01507                                         rv3d->dist*= asp;
01508                                 }
01509                                 
01510                                 if (rv3d->persp==RV3D_CAMOB) rv3d->persp= RV3D_PERSP;
01511                                 
01512                                 v3d->cursor[0]= -rv3d->ofs[0];
01513                                 v3d->cursor[1]= -rv3d->ofs[1];
01514                                 v3d->cursor[2]= -rv3d->ofs[2];
01515                         }
01516                 }
01517                 
01518                 v3d->lay= locallay;
01519         }
01520         else {
01521                 /* clear flags */ 
01522                 for(base= FIRSTBASE; base; base= base->next) {
01523                         if( base->lay & locallay ) {
01524                                 base->lay-= locallay;
01525                                 if(base->lay==0) base->lay= v3d->layact;
01526                                 if(base->object != scene->obedit) base->flag |= SELECT;
01527                                 base->object->lay= base->lay;
01528                         }
01529                 }               
01530         }
01531 
01532 }
01533 
01534 static void restore_localviewdata(ScrArea *sa, int free)
01535 {
01536         ARegion *ar;
01537         View3D *v3d= sa->spacedata.first;
01538         
01539         if(v3d->localvd==NULL) return;
01540         
01541         v3d->near= v3d->localvd->near;
01542         v3d->far= v3d->localvd->far;
01543         v3d->lay= v3d->localvd->lay;
01544         v3d->layact= v3d->localvd->layact;
01545         v3d->drawtype= v3d->localvd->drawtype;
01546         v3d->camera= v3d->localvd->camera;
01547         
01548         if(free) {
01549                 MEM_freeN(v3d->localvd);
01550                 v3d->localvd= NULL;
01551         }
01552         
01553         for(ar= sa->regionbase.first; ar; ar= ar->next) {
01554                 if(ar->regiontype == RGN_TYPE_WINDOW) {
01555                         RegionView3D *rv3d= ar->regiondata;
01556                         
01557                         if(rv3d->localvd) {
01558                                 rv3d->dist= rv3d->localvd->dist;
01559                                 copy_v3_v3(rv3d->ofs, rv3d->localvd->ofs);
01560                                 copy_qt_qt(rv3d->viewquat, rv3d->localvd->viewquat);
01561                                 rv3d->view= rv3d->localvd->view;
01562                                 rv3d->persp= rv3d->localvd->persp;
01563                                 rv3d->camzoom= rv3d->localvd->camzoom;
01564 
01565                                 if(free) {
01566                                         MEM_freeN(rv3d->localvd);
01567                                         rv3d->localvd= NULL;
01568                                 }
01569                         }
01570                 }
01571         }
01572 }
01573 
01574 static void endlocalview(Main *bmain, Scene *scene, ScrArea *sa)
01575 {
01576         View3D *v3d= sa->spacedata.first;
01577         struct Base *base;
01578         unsigned int locallay;
01579         
01580         if(v3d->localvd) {
01581                 
01582                 locallay= v3d->lay & 0xFF000000;
01583                 
01584                 restore_localviewdata(sa, 1); // 1 = free
01585 
01586                 /* for when in other window the layers have changed */
01587                 if(v3d->scenelock) v3d->lay= scene->lay;
01588                 
01589                 for(base= FIRSTBASE; base; base= base->next) {
01590                         if( base->lay & locallay ) {
01591                                 base->lay-= locallay;
01592                                 if(base->lay==0) base->lay= v3d->layact;
01593                                 if(base->object != scene->obedit) {
01594                                         base->flag |= SELECT;
01595                                         base->object->flag |= SELECT;
01596                                 }
01597                                 base->object->lay= base->lay;
01598                         }
01599                 }
01600                 
01601                 DAG_on_visible_update(bmain, FALSE);
01602         } 
01603 }
01604 
01605 static int localview_exec(bContext *C, wmOperator *UNUSED(unused))
01606 {
01607         View3D *v3d= CTX_wm_view3d(C);
01608         
01609         if(v3d->localvd)
01610                 endlocalview(CTX_data_main(C), CTX_data_scene(C), CTX_wm_area(C));
01611         else
01612                 initlocalview(CTX_data_main(C), CTX_data_scene(C), CTX_wm_area(C));
01613         
01614         ED_area_tag_redraw(CTX_wm_area(C));
01615         
01616         return OPERATOR_FINISHED;
01617 }
01618 
01619 void VIEW3D_OT_localview(wmOperatorType *ot)
01620 {
01621         
01622         /* identifiers */
01623         ot->name= "Local View";
01624         ot->description= "Toggle display of selected object(s) separately and centered in view";
01625         ot->idname= "VIEW3D_OT_localview";
01626         
01627         /* api callbacks */
01628         ot->exec= localview_exec;
01629         ot->flag= OPTYPE_UNDO; /* localview changes object layer bitflags */
01630         
01631         ot->poll= ED_operator_view3d_active;
01632 }
01633 
01634 #ifdef WITH_GAMEENGINE
01635 
01636 static ListBase queue_back;
01637 static void SaveState(bContext *C, wmWindow *win)
01638 {
01639         Object *obact = CTX_data_active_object(C);
01640         
01641         glPushAttrib(GL_ALL_ATTRIB_BITS);
01642 
01643         if(obact && obact->mode & OB_MODE_TEXTURE_PAINT)
01644                 GPU_paint_set_mipmap(1);
01645         
01646         queue_back= win->queue;
01647         
01648         win->queue.first= win->queue.last= NULL;
01649         
01650         //XXX waitcursor(1);
01651 }
01652 
01653 static void RestoreState(bContext *C, wmWindow *win)
01654 {
01655         Object *obact = CTX_data_active_object(C);
01656         
01657         if(obact && obact->mode & OB_MODE_TEXTURE_PAINT)
01658                 GPU_paint_set_mipmap(0);
01659 
01660         //XXX curarea->win_swap = 0;
01661         //XXX curarea->head_swap=0;
01662         //XXX allqueue(REDRAWVIEW3D, 1);
01663         //XXX allqueue(REDRAWBUTSALL, 0);
01664         //XXX reset_slowparents();
01665         //XXX waitcursor(0);
01666         //XXX G.qual= 0;
01667         
01668         if(win) /* check because closing win can set to NULL */
01669                 win->queue= queue_back;
01670         
01671         GPU_state_init();
01672         GPU_set_tpage(NULL, 0);
01673 
01674         glPopAttrib();
01675 }
01676 
01677 /* was space_set_commmandline_options in 2.4x */
01678 static void game_set_commmandline_options(GameData *gm)
01679 {
01680         SYS_SystemHandle syshandle;
01681         int test;
01682 
01683         if ( (syshandle = SYS_GetSystem()) ) {
01684                 /* User defined settings */
01685                 test= (U.gameflags & USER_DISABLE_MIPMAP);
01686                 GPU_set_mipmap(!test);
01687                 SYS_WriteCommandLineInt(syshandle, "nomipmap", test);
01688 
01689                 /* File specific settings: */
01690                 /* Only test the first one. These two are switched
01691                  * simultaneously. */
01692                 test= (gm->flag & GAME_SHOW_FRAMERATE);
01693                 SYS_WriteCommandLineInt(syshandle, "show_framerate", test);
01694                 SYS_WriteCommandLineInt(syshandle, "show_profile", test);
01695 
01696                 test = (gm->flag & GAME_SHOW_DEBUG_PROPS);
01697                 SYS_WriteCommandLineInt(syshandle, "show_properties", test);
01698 
01699                 test= (gm->flag & GAME_SHOW_PHYSICS);
01700                 SYS_WriteCommandLineInt(syshandle, "show_physics", test);
01701 
01702                 test= (gm->flag & GAME_ENABLE_ALL_FRAMES);
01703                 SYS_WriteCommandLineInt(syshandle, "fixedtime", test);
01704 
01705                 test= (gm->flag & GAME_ENABLE_ANIMATION_RECORD);
01706                 SYS_WriteCommandLineInt(syshandle, "animation_record", test);
01707 
01708                 test= (gm->flag & GAME_IGNORE_DEPRECATION_WARNINGS);
01709                 SYS_WriteCommandLineInt(syshandle, "ignore_deprecation_warnings", test);
01710 
01711                 test= (gm->matmode == GAME_MAT_MULTITEX);
01712                 SYS_WriteCommandLineInt(syshandle, "blender_material", test);
01713                 test= (gm->matmode == GAME_MAT_GLSL);
01714                 SYS_WriteCommandLineInt(syshandle, "blender_glsl_material", test);
01715                 test= (gm->flag & GAME_DISPLAY_LISTS);
01716                 SYS_WriteCommandLineInt(syshandle, "displaylists", test);
01717 
01718 
01719         }
01720 }
01721 
01722 #endif // WITH_GAMEENGINE
01723 
01724 static int game_engine_poll(bContext *C)
01725 {
01726         /* we need a context and area to launch BGE
01727         it's a temporary solution to avoid crash at load time
01728         if we try to auto run the BGE. Ideally we want the
01729         context to be set as soon as we load the file. */
01730 
01731         if(CTX_wm_window(C)==NULL) return 0;
01732         if(CTX_wm_screen(C)==NULL) return 0;
01733         if(CTX_wm_area(C)==NULL) return 0;
01734 
01735         if(CTX_data_mode_enum(C)!=CTX_MODE_OBJECT)
01736                 return 0;
01737 
01738         return 1;
01739 }
01740 
01741 int ED_view3d_context_activate(bContext *C)
01742 {
01743         bScreen *sc= CTX_wm_screen(C);
01744         ScrArea *sa= CTX_wm_area(C);
01745         ARegion *ar;
01746 
01747         /* sa can be NULL when called from python */
01748         if(sa==NULL || sa->spacetype != SPACE_VIEW3D)
01749                 for(sa=sc->areabase.first; sa; sa= sa->next)
01750                         if(sa->spacetype==SPACE_VIEW3D)
01751                                 break;
01752 
01753         if(!sa)
01754                 return 0;
01755         
01756         for(ar=sa->regionbase.first; ar; ar=ar->next)
01757                 if(ar->regiontype == RGN_TYPE_WINDOW)
01758                         break;
01759         
01760         if(!ar)
01761                 return 0;
01762         
01763         // bad context switch ..
01764         CTX_wm_area_set(C, sa);
01765         CTX_wm_region_set(C, ar);
01766 
01767         return 1;
01768 }
01769 
01770 static int game_engine_exec(bContext *C, wmOperator *op)
01771 {
01772 #ifdef WITH_GAMEENGINE
01773         Scene *startscene = CTX_data_scene(C);
01774         ScrArea *sa, *prevsa= CTX_wm_area(C);
01775         ARegion *ar, *prevar= CTX_wm_region(C);
01776         wmWindow *prevwin= CTX_wm_window(C);
01777         RegionView3D *rv3d;
01778         rcti cam_frame;
01779 
01780         (void)op; /* unused */
01781         
01782         // bad context switch ..
01783         if(!ED_view3d_context_activate(C))
01784                 return OPERATOR_CANCELLED;
01785         
01786         rv3d= CTX_wm_region_view3d(C);
01787         sa= CTX_wm_area(C);
01788         ar= CTX_wm_region(C);
01789 
01790         view3d_operator_needs_opengl(C);
01791         
01792         game_set_commmandline_options(&startscene->gm);
01793 
01794         if(rv3d->persp==RV3D_CAMOB && startscene->gm.framing.type == SCE_GAMEFRAMING_BARS && startscene->gm.stereoflag != STEREO_DOME) { /* Letterbox */
01795                 rctf cam_framef;
01796                 ED_view3d_calc_camera_border(startscene, ar, CTX_wm_view3d(C), rv3d, &cam_framef, FALSE);
01797                 cam_frame.xmin = cam_framef.xmin + ar->winrct.xmin;
01798                 cam_frame.xmax = cam_framef.xmax + ar->winrct.xmin;
01799                 cam_frame.ymin = cam_framef.ymin + ar->winrct.ymin;
01800                 cam_frame.ymax = cam_framef.ymax + ar->winrct.ymin;
01801                 BLI_isect_rcti(&ar->winrct, &cam_frame, &cam_frame);
01802         }
01803         else {
01804                 cam_frame.xmin = ar->winrct.xmin;
01805                 cam_frame.xmax = ar->winrct.xmax;
01806                 cam_frame.ymin = ar->winrct.ymin;
01807                 cam_frame.ymax = ar->winrct.ymax;
01808         }
01809 
01810 
01811         SaveState(C, prevwin);
01812 
01813         StartKetsjiShell(C, ar, &cam_frame, 1);
01814 
01815         /* window wasnt closed while the BGE was running */
01816         if(BLI_findindex(&CTX_wm_manager(C)->windows, prevwin) == -1) {
01817                 prevwin= NULL;
01818                 CTX_wm_window_set(C, NULL);
01819         }
01820         
01821         if(prevwin) {
01822                 /* restore context, in case it changed in the meantime, for
01823                    example by working in another window or closing it */
01824                 CTX_wm_region_set(C, prevar);
01825                 CTX_wm_window_set(C, prevwin);
01826                 CTX_wm_area_set(C, prevsa);
01827         }
01828 
01829         RestoreState(C, prevwin);
01830 
01831         //XXX restore_all_scene_cfra(scene_cfra_store);
01832         set_scene_bg(CTX_data_main(C), startscene);
01833         //XXX scene_update_for_newframe(bmain, scene, scene->lay);
01834         
01835         ED_area_tag_redraw(CTX_wm_area(C));
01836 
01837         return OPERATOR_FINISHED;
01838 #else
01839         (void)C; /* unused */
01840         BKE_report(op->reports, RPT_ERROR, "Game engine is disabled in this build.");
01841         return OPERATOR_CANCELLED;
01842 #endif
01843 }
01844 
01845 void VIEW3D_OT_game_start(wmOperatorType *ot)
01846 {
01847         
01848         /* identifiers */
01849         ot->name= "Start Game Engine";
01850         ot->description= "Start game engine";
01851         ot->idname= "VIEW3D_OT_game_start";
01852         
01853         /* api callbacks */
01854         ot->exec= game_engine_exec;
01855         
01856         ot->poll= game_engine_poll;
01857 }
01858 
01859 /* ************************************** */
01860 
01861 void view3d_align_axis_to_vector(View3D *v3d, RegionView3D *rv3d, int axisidx, float vec[3])
01862 {
01863         float alignaxis[3] = {0.0, 0.0, 0.0};
01864         float norm[3], axis[3], angle, new_quat[4];
01865         
01866         if(axisidx > 0) alignaxis[axisidx-1]= 1.0;
01867         else alignaxis[-axisidx-1]= -1.0;
01868 
01869         normalize_v3_v3(norm, vec);
01870 
01871         angle= (float)acos(dot_v3v3(alignaxis, norm));
01872         cross_v3_v3v3(axis, alignaxis, norm);
01873         axis_angle_to_quat( new_quat,axis, -angle);
01874         
01875         rv3d->view= RV3D_VIEW_USER;
01876         
01877         if (rv3d->persp==RV3D_CAMOB && v3d->camera) {
01878                 /* switch out of camera view */
01879                 float orig_ofs[3];
01880                 float orig_dist= rv3d->dist;
01881                 float orig_lens= v3d->lens;
01882                 
01883                 copy_v3_v3(orig_ofs, rv3d->ofs);
01884                 rv3d->persp= RV3D_PERSP;
01885                 rv3d->dist= 0.0;
01886                 ED_view3d_from_object(v3d->camera, rv3d->ofs, NULL, NULL, &v3d->lens);
01887                 smooth_view(NULL, NULL, NULL, NULL, NULL, orig_ofs, new_quat, &orig_dist, &orig_lens); // XXX
01888         } else {
01889                 if (rv3d->persp==RV3D_CAMOB) rv3d->persp= RV3D_PERSP; /* switch out of camera mode */
01890                 smooth_view(NULL, NULL, NULL, NULL, NULL, NULL, new_quat, NULL, NULL); // XXX
01891         }
01892 }
01893 
01894 float ED_view3d_pixel_size(struct RegionView3D *rv3d, const float co[3])
01895 {
01896         return  (rv3d->persmat[3][3] + (
01897                                 rv3d->persmat[0][3]*co[0] +
01898                                 rv3d->persmat[1][3]*co[1] +
01899                                 rv3d->persmat[2][3]*co[2])
01900                         ) * rv3d->pixsize;
01901 }