Blender V2.61 - r43446

view3d_view.c

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