Blender V2.61 - r43446
|
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 * Contributor(s): Campbell Barton 00019 * 00020 * ***** END GPL LICENSE BLOCK ***** 00021 */ 00022 00028 /* defines VIEW3D_OT_fly modal operator */ 00029 00030 //#define NDOF_FLY_DEBUG 00031 //#define NDOF_FLY_DRAW_TOOMUCH // is this needed for ndof? - commented so redraw doesnt thrash - campbell 00032 00033 #include "DNA_anim_types.h" 00034 #include "DNA_scene_types.h" 00035 #include "DNA_object_types.h" 00036 #include "DNA_camera_types.h" 00037 00038 #include "MEM_guardedalloc.h" 00039 00040 #include "BLI_math.h" 00041 #include "BLI_blenlib.h" 00042 #include "BLI_utildefines.h" 00043 00044 #include "BKE_context.h" 00045 #include "BKE_object.h" 00046 #include "BKE_report.h" 00047 00048 #include "BKE_depsgraph.h" /* for fly mode updating */ 00049 00050 #include "BIF_gl.h" 00051 00052 #include "WM_api.h" 00053 #include "WM_types.h" 00054 00055 #include "ED_keyframing.h" 00056 #include "ED_screen.h" 00057 #include "ED_space_api.h" 00058 00059 #include "PIL_time.h" /* smoothview */ 00060 00061 #include "view3d_intern.h" // own include 00062 00063 /* NOTE: these defines are saved in keymap files, do not change values but just add new ones */ 00064 enum { 00065 FLY_MODAL_CANCEL= 1, 00066 FLY_MODAL_CONFIRM, 00067 FLY_MODAL_ACCELERATE, 00068 FLY_MODAL_DECELERATE, 00069 FLY_MODAL_PAN_ENABLE, 00070 FLY_MODAL_PAN_DISABLE, 00071 FLY_MODAL_DIR_FORWARD, 00072 FLY_MODAL_DIR_BACKWARD, 00073 FLY_MODAL_DIR_LEFT, 00074 FLY_MODAL_DIR_RIGHT, 00075 FLY_MODAL_DIR_UP, 00076 FLY_MODAL_DIR_DOWN, 00077 FLY_MODAL_AXIS_LOCK_X, 00078 FLY_MODAL_AXIS_LOCK_Z, 00079 FLY_MODAL_PRECISION_ENABLE, 00080 FLY_MODAL_PRECISION_DISABLE, 00081 FLY_MODAL_FREELOOK_ENABLE, 00082 FLY_MODAL_FREELOOK_DISABLE 00083 00084 }; 00085 00086 /* called in transform_ops.c, on each regeneration of keymaps */ 00087 void fly_modal_keymap(wmKeyConfig *keyconf) 00088 { 00089 static EnumPropertyItem modal_items[] = { 00090 {FLY_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""}, 00091 {FLY_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""}, 00092 {FLY_MODAL_ACCELERATE, "ACCELERATE", 0, "Accelerate", ""}, 00093 {FLY_MODAL_DECELERATE, "DECELERATE", 0, "Decelerate", ""}, 00094 00095 {FLY_MODAL_PAN_ENABLE, "PAN_ENABLE", 0, "Pan Enable", ""}, 00096 {FLY_MODAL_PAN_DISABLE, "PAN_DISABLE", 0, "Pan Disable", ""}, 00097 00098 {FLY_MODAL_DIR_FORWARD, "FORWARD", 0, "Fly Forward", ""}, 00099 {FLY_MODAL_DIR_BACKWARD,"BACKWARD", 0, "Fly Backward", ""}, 00100 {FLY_MODAL_DIR_LEFT, "LEFT", 0, "Fly Left", ""}, 00101 {FLY_MODAL_DIR_RIGHT, "RIGHT", 0, "Fly Right", ""}, 00102 {FLY_MODAL_DIR_UP, "UP", 0, "Fly Up", ""}, 00103 {FLY_MODAL_DIR_DOWN, "DOWN", 0, "Fly Down", ""}, 00104 00105 {FLY_MODAL_AXIS_LOCK_X, "AXIS_LOCK_X", 0, "X Axis Correction", "X axis correction (toggle)"}, 00106 {FLY_MODAL_AXIS_LOCK_Z, "AXIS_LOCK_Z", 0, "X Axis Correction", "Z axis correction (toggle)"}, 00107 00108 {FLY_MODAL_PRECISION_ENABLE, "PRECISION_ENABLE", 0, "Precision Enable", ""}, 00109 {FLY_MODAL_PRECISION_DISABLE, "PRECISION_DISABLE", 0, "Precision Disable", ""}, 00110 00111 {FLY_MODAL_FREELOOK_ENABLE, "FREELOOK_ENABLE", 0, "Rotation Enable", ""}, 00112 {FLY_MODAL_FREELOOK_DISABLE, "FREELOOK_DISABLE", 0, "Rotation Disable", ""}, 00113 00114 {0, NULL, 0, NULL, NULL}}; 00115 00116 wmKeyMap *keymap= WM_modalkeymap_get(keyconf, "View3D Fly Modal"); 00117 00118 /* this function is called for each spacetype, only needs to add map once */ 00119 if (keymap) return; 00120 00121 keymap= WM_modalkeymap_add(keyconf, "View3D Fly Modal", modal_items); 00122 00123 /* items for modal map */ 00124 WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, FLY_MODAL_CANCEL); 00125 WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_ANY, KM_ANY, 0, FLY_MODAL_CANCEL); 00126 00127 WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_ANY, KM_ANY, 0, FLY_MODAL_CONFIRM); 00128 WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, FLY_MODAL_CONFIRM); 00129 WM_modalkeymap_add_item(keymap, SPACEKEY, KM_PRESS, KM_ANY, 0, FLY_MODAL_CONFIRM); 00130 WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, KM_ANY, 0, FLY_MODAL_CONFIRM); 00131 00132 WM_modalkeymap_add_item(keymap, PADPLUSKEY, KM_PRESS, KM_ANY, 0, FLY_MODAL_ACCELERATE); 00133 WM_modalkeymap_add_item(keymap, PADMINUS, KM_PRESS, KM_ANY, 0, FLY_MODAL_DECELERATE); 00134 WM_modalkeymap_add_item(keymap, WHEELUPMOUSE, KM_PRESS, KM_ANY, 0, FLY_MODAL_ACCELERATE); 00135 WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, KM_ANY, 0, FLY_MODAL_DECELERATE); 00136 00137 WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_PRESS, KM_ANY, 0, FLY_MODAL_PAN_ENABLE); 00138 WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, FLY_MODAL_PAN_DISABLE); /* XXX - Bug in the event system, middle mouse release doesnt work */ 00139 00140 /* WASD */ 00141 WM_modalkeymap_add_item(keymap, WKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_FORWARD); 00142 WM_modalkeymap_add_item(keymap, SKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_BACKWARD); 00143 WM_modalkeymap_add_item(keymap, AKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_LEFT); 00144 WM_modalkeymap_add_item(keymap, DKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_RIGHT); 00145 WM_modalkeymap_add_item(keymap, RKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_UP); 00146 WM_modalkeymap_add_item(keymap, FKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_DOWN); 00147 00148 WM_modalkeymap_add_item(keymap, XKEY, KM_PRESS, 0, 0, FLY_MODAL_AXIS_LOCK_X); 00149 WM_modalkeymap_add_item(keymap, ZKEY, KM_PRESS, 0, 0, FLY_MODAL_AXIS_LOCK_Z); 00150 00151 WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, FLY_MODAL_PRECISION_ENABLE); 00152 WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_RELEASE, KM_ANY, 0, FLY_MODAL_PRECISION_DISABLE); 00153 00154 WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, FLY_MODAL_FREELOOK_ENABLE); 00155 WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, FLY_MODAL_FREELOOK_DISABLE); 00156 00157 /* assign map to operators */ 00158 WM_modalkeymap_assign(keymap, "VIEW3D_OT_fly"); 00159 } 00160 00161 typedef struct FlyInfo { 00162 /* context stuff */ 00163 RegionView3D *rv3d; 00164 View3D *v3d; 00165 ARegion *ar; 00166 Scene *scene; 00167 00168 wmTimer *timer; /* needed for redraws */ 00169 00170 short state; 00171 short redraw; 00172 unsigned char use_precision; 00173 unsigned char use_freelook; /* if the user presses shift they can look about without movinf the direction there looking */ 00174 00175 int mval[2]; /* latest 2D mouse values */ 00176 wmNDOFMotionData* ndof; /* latest 3D mouse values */ 00177 00178 /* fly state state */ 00179 float speed; /* the speed the view is moving per redraw */ 00180 short axis; /* Axis index to move along by default Z to move along the view */ 00181 short pan_view; /* when true, pan the view instead of rotating */ 00182 00183 /* relative view axis locking - xlock, zlock 00184 0; disabled 00185 1; enabled but not checking because mouse hasnt moved outside the margin since locking was checked an not needed 00186 when the mouse moves, locking is set to 2 so checks are done. 00187 2; mouse moved and checking needed, if no view altering is donem its changed back to 1 */ 00188 short xlock, zlock; 00189 float xlock_momentum, zlock_momentum; /* nicer dynamics */ 00190 float grid; /* world scale 1.0 default */ 00191 00192 /* root most parent */ 00193 Object *root_parent; 00194 00195 /* backup values */ 00196 float dist_backup; /* backup the views distance since we use a zero dist for fly mode */ 00197 float ofs_backup[3]; /* backup the views offset incase the user cancels flying in non camera mode */ 00198 float rot_backup[4]; /* backup the views quat incase the user cancels flying in non camera mode. (quat for view, eul for camera) */ 00199 short persp_backup; /* remember if were ortho or not, only used for restoring the view if it was a ortho view */ 00200 00201 short is_ortho_cam; /* are we flying an ortho camera in perspective view, 00202 * which was originall in ortho view? 00203 * could probably figure it out but better be explicit */ 00204 00205 void *obtfm; /* backup the objects transform */ 00206 00207 /* compare between last state */ 00208 double time_lastwheel; /* used to accelerate when using the mousewheel a lot */ 00209 double time_lastdraw; /* time between draws */ 00210 00211 void *draw_handle_pixel; 00212 00213 /* use for some lag */ 00214 float dvec_prev[3]; /* old for some lag */ 00215 00216 } FlyInfo; 00217 00218 static void drawFlyPixel(const struct bContext *UNUSED(C), struct ARegion *UNUSED(ar), void *arg) 00219 { 00220 FlyInfo *fly = arg; 00221 00222 /* draws 4 edge brackets that frame the safe area where the 00223 mouse can move during fly mode without spinning the view */ 00224 float x1, x2, y1, y2; 00225 00226 x1= 0.45f * (float)fly->ar->winx; 00227 y1= 0.45f * (float)fly->ar->winy; 00228 x2= 0.55f * (float)fly->ar->winx; 00229 y2= 0.55f * (float)fly->ar->winy; 00230 cpack(0); 00231 00232 00233 glBegin(GL_LINES); 00234 /* bottom left */ 00235 glVertex2f(x1,y1); 00236 glVertex2f(x1,y1+5); 00237 00238 glVertex2f(x1,y1); 00239 glVertex2f(x1+5,y1); 00240 00241 /* top right */ 00242 glVertex2f(x2,y2); 00243 glVertex2f(x2,y2-5); 00244 00245 glVertex2f(x2,y2); 00246 glVertex2f(x2-5,y2); 00247 00248 /* top left */ 00249 glVertex2f(x1,y2); 00250 glVertex2f(x1,y2-5); 00251 00252 glVertex2f(x1,y2); 00253 glVertex2f(x1+5,y2); 00254 00255 /* bottom right */ 00256 glVertex2f(x2,y1); 00257 glVertex2f(x2,y1+5); 00258 00259 glVertex2f(x2,y1); 00260 glVertex2f(x2-5,y1); 00261 glEnd(); 00262 } 00263 00264 /* FlyInfo->state */ 00265 #define FLY_RUNNING 0 00266 #define FLY_CANCEL 1 00267 #define FLY_CONFIRM 2 00268 00269 static int initFlyInfo (bContext *C, FlyInfo *fly, wmOperator *op, wmEvent *event) 00270 { 00271 float upvec[3]; // tmp 00272 float mat[3][3]; 00273 00274 fly->rv3d= CTX_wm_region_view3d(C); 00275 fly->v3d = CTX_wm_view3d(C); 00276 fly->ar = CTX_wm_region(C); 00277 fly->scene= CTX_data_scene(C); 00278 00279 #ifdef NDOF_FLY_DEBUG 00280 puts("\n-- fly begin --"); 00281 #endif 00282 00283 if (fly->rv3d->persp==RV3D_CAMOB && fly->v3d->camera->id.lib) { 00284 BKE_report(op->reports, RPT_ERROR, "Cannot fly a camera from an external library"); 00285 return FALSE; 00286 } 00287 00288 if (fly->v3d->ob_centre) { 00289 BKE_report(op->reports, RPT_ERROR, "Cannot fly when the view is locked to an object"); 00290 return FALSE; 00291 } 00292 00293 if (fly->rv3d->persp==RV3D_CAMOB && fly->v3d->camera->constraints.first) { 00294 BKE_report(op->reports, RPT_ERROR, "Cannot fly an object with constraints"); 00295 return FALSE; 00296 } 00297 00298 fly->state= FLY_RUNNING; 00299 fly->speed= 0.0f; 00300 fly->axis= 2; 00301 fly->pan_view= FALSE; 00302 fly->xlock= FALSE; 00303 fly->zlock= FALSE; 00304 fly->xlock_momentum=0.0f; 00305 fly->zlock_momentum=0.0f; 00306 fly->grid= 1.0f; 00307 fly->use_precision= FALSE; 00308 fly->use_freelook= FALSE; 00309 00310 #ifdef NDOF_FLY_DRAW_TOOMUCH 00311 fly->redraw= 1; 00312 #endif 00313 fly->dvec_prev[0]= fly->dvec_prev[1]= fly->dvec_prev[2]= 0.0f; 00314 00315 fly->timer= WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f); 00316 00317 copy_v2_v2_int(fly->mval, event->mval); 00318 fly->ndof = NULL; 00319 00320 fly->time_lastdraw= fly->time_lastwheel= PIL_check_seconds_timer(); 00321 00322 fly->draw_handle_pixel = ED_region_draw_cb_activate(fly->ar->type, drawFlyPixel, fly, REGION_DRAW_POST_PIXEL); 00323 00324 fly->rv3d->rflag |= RV3D_NAVIGATING; /* so we draw the corner margins */ 00325 00326 /* detect weather to start with Z locking */ 00327 upvec[0]=1.0f; upvec[1]=0.0f; upvec[2]=0.0f; 00328 copy_m3_m4(mat, fly->rv3d->viewinv); 00329 mul_m3_v3(mat, upvec); 00330 if (fabs(upvec[2]) < 0.1) 00331 fly->zlock = 1; 00332 upvec[0]=0; upvec[1]=0; upvec[2]=0; 00333 00334 fly->persp_backup= fly->rv3d->persp; 00335 fly->dist_backup= fly->rv3d->dist; 00336 00337 /* check for flying ortho camera - which we cant support well 00338 * we _could_ also check for an ortho camera but this is easier */ 00339 if( (fly->rv3d->persp == RV3D_CAMOB) && 00340 (fly->v3d->camera != NULL) && 00341 (fly->rv3d->is_persp == FALSE)) 00342 { 00343 ((Camera *)fly->v3d->camera->data)->type= CAM_PERSP; 00344 fly->is_ortho_cam= TRUE; 00345 } 00346 00347 if (fly->rv3d->persp==RV3D_CAMOB) { 00348 Object *ob_back; 00349 if ((U.uiflag & USER_CAM_LOCK_NO_PARENT)==0 && (fly->root_parent=fly->v3d->camera->parent)) { 00350 while(fly->root_parent->parent) 00351 fly->root_parent= fly->root_parent->parent; 00352 ob_back= fly->root_parent; 00353 } 00354 else { 00355 ob_back= fly->v3d->camera; 00356 } 00357 00358 /* store the original camera loc and rot */ 00359 /* TODO. axis angle etc */ 00360 00361 fly->obtfm= object_tfm_backup(ob_back); 00362 00363 where_is_object(fly->scene, fly->v3d->camera); 00364 negate_v3_v3(fly->rv3d->ofs, fly->v3d->camera->obmat[3]); 00365 00366 fly->rv3d->dist=0.0; 00367 } 00368 else { 00369 /* perspective or ortho */ 00370 if (fly->rv3d->persp==RV3D_ORTHO) 00371 fly->rv3d->persp= RV3D_PERSP; /*if ortho projection, make perspective */ 00372 00373 copy_qt_qt(fly->rot_backup, fly->rv3d->viewquat); 00374 copy_v3_v3(fly->ofs_backup, fly->rv3d->ofs); 00375 00376 /* the dist defines a vector that is infront of the offset 00377 to rotate the view about. 00378 this is no good for fly mode because we 00379 want to rotate about the viewers center. 00380 but to correct the dist removal we must 00381 alter offset so the view doesn't jump. */ 00382 00383 fly->rv3d->dist= 0.0f; 00384 00385 upvec[2]= fly->dist_backup; /*x and y are 0*/ 00386 mul_m3_v3(mat, upvec); 00387 sub_v3_v3(fly->rv3d->ofs, upvec); 00388 /*Done with correcting for the dist*/ 00389 } 00390 00391 /* center the mouse, probably the UI mafia are against this but without its quite annoying */ 00392 WM_cursor_warp(CTX_wm_window(C), fly->ar->winrct.xmin + fly->ar->winx/2, fly->ar->winrct.ymin + fly->ar->winy/2); 00393 00394 return 1; 00395 } 00396 00397 static int flyEnd(bContext *C, FlyInfo *fly) 00398 { 00399 RegionView3D *rv3d= fly->rv3d; 00400 View3D *v3d = fly->v3d; 00401 00402 float upvec[3]; 00403 00404 if (fly->state == FLY_RUNNING) 00405 return OPERATOR_RUNNING_MODAL; 00406 00407 #ifdef NDOF_FLY_DEBUG 00408 puts("\n-- fly end --"); 00409 #endif 00410 00411 WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), fly->timer); 00412 00413 ED_region_draw_cb_exit(fly->ar->type, fly->draw_handle_pixel); 00414 00415 rv3d->dist= fly->dist_backup; 00416 00417 if (fly->state == FLY_CANCEL) { 00418 /* Revert to original view? */ 00419 if (fly->persp_backup==RV3D_CAMOB) { /* a camera view */ 00420 Object *ob_back; 00421 ob_back= (fly->root_parent) ? fly->root_parent : fly->v3d->camera; 00422 00423 /* store the original camera loc and rot */ 00424 object_tfm_restore(ob_back, fly->obtfm); 00425 00426 DAG_id_tag_update(&ob_back->id, OB_RECALC_OB); 00427 } 00428 else { 00429 /* Non Camera we need to reset the view back to the original location bacause the user canceled*/ 00430 copy_qt_qt(rv3d->viewquat, fly->rot_backup); 00431 copy_v3_v3(rv3d->ofs, fly->ofs_backup); 00432 rv3d->persp= fly->persp_backup; 00433 } 00434 } 00435 else if (fly->persp_backup==RV3D_CAMOB) { /* camera */ 00436 DAG_id_tag_update(fly->root_parent ? &fly->root_parent->id : &v3d->camera->id, OB_RECALC_OB); 00437 } 00438 else { /* not camera */ 00439 /* Apply the fly mode view */ 00440 /*restore the dist*/ 00441 float mat[3][3]; 00442 upvec[0]= upvec[1]= 0; 00443 upvec[2]= fly->dist_backup; /*x and y are 0*/ 00444 copy_m3_m4(mat, rv3d->viewinv); 00445 mul_m3_v3(mat, upvec); 00446 add_v3_v3(rv3d->ofs, upvec); 00447 /*Done with correcting for the dist */ 00448 } 00449 00450 if(fly->is_ortho_cam) { 00451 ((Camera *)fly->v3d->camera->data)->type= CAM_ORTHO; 00452 } 00453 00454 rv3d->rflag &= ~RV3D_NAVIGATING; 00455 //XXX2.5 BIF_view3d_previewrender_signal(fly->sa, PR_DBASE|PR_DISPRECT); /* not working at the moment not sure why */ 00456 00457 if (fly->obtfm) 00458 MEM_freeN(fly->obtfm); 00459 00460 if (fly->ndof) 00461 MEM_freeN(fly->ndof); 00462 00463 if (fly->state == FLY_CONFIRM) { 00464 MEM_freeN(fly); 00465 return OPERATOR_FINISHED; 00466 } 00467 00468 MEM_freeN(fly); 00469 return OPERATOR_CANCELLED; 00470 } 00471 00472 static void flyEvent(FlyInfo *fly, wmEvent *event) 00473 { 00474 if (event->type == TIMER && event->customdata == fly->timer) { 00475 fly->redraw = 1; 00476 } 00477 else if (event->type == MOUSEMOVE) { 00478 copy_v2_v2_int(fly->mval, event->mval); 00479 } 00480 else if (event->type == NDOF_MOTION) { 00481 // do these automagically get delivered? yes. 00482 // puts("ndof motion detected in fly mode!"); 00483 // static const char* tag_name = "3D mouse position"; 00484 00485 wmNDOFMotionData* incoming_ndof = (wmNDOFMotionData*) event->customdata; 00486 switch (incoming_ndof->progress) { 00487 case P_STARTING: 00488 // start keeping track of 3D mouse position 00489 #ifdef NDOF_FLY_DEBUG 00490 puts("start keeping track of 3D mouse position"); 00491 #endif 00492 // fall through... 00493 case P_IN_PROGRESS: 00494 // update 3D mouse position 00495 #ifdef NDOF_FLY_DEBUG 00496 putchar('.'); fflush(stdout); 00497 #endif 00498 if (fly->ndof == NULL) { 00499 // fly->ndof = MEM_mallocN(sizeof(wmNDOFMotionData), tag_name); 00500 fly->ndof = MEM_dupallocN(incoming_ndof); 00501 // fly->ndof = malloc(sizeof(wmNDOFMotionData)); 00502 } 00503 else { 00504 memcpy(fly->ndof, incoming_ndof, sizeof(wmNDOFMotionData)); 00505 } 00506 break; 00507 case P_FINISHING: 00508 // stop keeping track of 3D mouse position 00509 #ifdef NDOF_FLY_DEBUG 00510 puts("stop keeping track of 3D mouse position"); 00511 #endif 00512 if (fly->ndof) { 00513 MEM_freeN(fly->ndof); 00514 // free(fly->ndof); 00515 fly->ndof = NULL; 00516 } 00517 /* update the time else the view will jump when 2D mouse/timer resume */ 00518 fly->time_lastdraw= PIL_check_seconds_timer(); 00519 break; 00520 default: 00521 ; // should always be one of the above 3 00522 } 00523 } 00524 /* handle modal keymap first */ 00525 else if (event->type == EVT_MODAL_MAP) { 00526 switch (event->val) { 00527 case FLY_MODAL_CANCEL: 00528 fly->state = FLY_CANCEL; 00529 break; 00530 case FLY_MODAL_CONFIRM: 00531 fly->state = FLY_CONFIRM; 00532 break; 00533 00534 case FLY_MODAL_ACCELERATE: 00535 { 00536 double time_currwheel; 00537 float time_wheel; 00538 00539 time_currwheel= PIL_check_seconds_timer(); 00540 time_wheel = (float)(time_currwheel - fly->time_lastwheel); 00541 fly->time_lastwheel = time_currwheel; 00542 /*printf("Wheel %f\n", time_wheel);*/ 00543 /*Mouse wheel delays range from 0.5==slow to 0.01==fast*/ 00544 time_wheel = 1.0f + (10.0f - (20.0f * MIN2(time_wheel, 0.5f))); /* 0-0.5 -> 0-5.0 */ 00545 00546 if (fly->speed < 0.0f) { 00547 fly->speed= 0.0f; 00548 } 00549 else { 00550 fly->speed += fly->grid*time_wheel * (fly->use_precision ? 0.1f : 1.0f); 00551 } 00552 break; 00553 } 00554 case FLY_MODAL_DECELERATE: 00555 { 00556 double time_currwheel; 00557 float time_wheel; 00558 00559 time_currwheel= PIL_check_seconds_timer(); 00560 time_wheel = (float)(time_currwheel - fly->time_lastwheel); 00561 fly->time_lastwheel = time_currwheel; 00562 time_wheel = 1.0f + (10.0f - (20.0f * MIN2(time_wheel, 0.5f))); /* 0-0.5 -> 0-5.0 */ 00563 00564 if (fly->speed > 0.0f) { 00565 fly->speed=0; 00566 } 00567 else { 00568 fly->speed-= fly->grid*time_wheel * (fly->use_precision ? 0.1f : 1.0f); 00569 } 00570 break; 00571 } 00572 case FLY_MODAL_PAN_ENABLE: 00573 fly->pan_view= TRUE; 00574 break; 00575 case FLY_MODAL_PAN_DISABLE: 00576 //XXX2.5 warp_pointer(cent_orig[0], cent_orig[1]); 00577 fly->pan_view= FALSE; 00578 break; 00579 00580 /* impliment WASD keys */ 00581 case FLY_MODAL_DIR_FORWARD: 00582 if (fly->speed < 0.0f) fly->speed= -fly->speed; /* flip speed rather than stopping, game like motion */ 00583 else if (fly->axis==2) fly->speed += fly->grid; /* increse like mousewheel if were already moving in that difection*/ 00584 fly->axis= 2; 00585 break; 00586 case FLY_MODAL_DIR_BACKWARD: 00587 if (fly->speed > 0.0f) fly->speed= -fly->speed; 00588 else if (fly->axis==2) fly->speed -= fly->grid; 00589 fly->axis= 2; 00590 break; 00591 case FLY_MODAL_DIR_LEFT: 00592 if (fly->speed < 0.0f) fly->speed= -fly->speed; 00593 else if (fly->axis==0) fly->speed += fly->grid; 00594 fly->axis= 0; 00595 break; 00596 case FLY_MODAL_DIR_RIGHT: 00597 if (fly->speed > 0.0f) fly->speed= -fly->speed; 00598 else if (fly->axis==0) fly->speed -= fly->grid; 00599 fly->axis= 0; 00600 break; 00601 case FLY_MODAL_DIR_DOWN: 00602 if (fly->speed < 0.0f) fly->speed= -fly->speed; 00603 else if (fly->axis==1) fly->speed += fly->grid; 00604 fly->axis= 1; 00605 break; 00606 case FLY_MODAL_DIR_UP: 00607 if (fly->speed > 0.0f) fly->speed= -fly->speed; 00608 else if (fly->axis==1) fly->speed -= fly->grid; 00609 fly->axis= 1; 00610 break; 00611 00612 case FLY_MODAL_AXIS_LOCK_X: 00613 if (fly->xlock) fly->xlock=0; 00614 else { 00615 fly->xlock = 2; 00616 fly->xlock_momentum = 0.0; 00617 } 00618 break; 00619 case FLY_MODAL_AXIS_LOCK_Z: 00620 if (fly->zlock) fly->zlock=0; 00621 else { 00622 fly->zlock = 2; 00623 fly->zlock_momentum = 0.0; 00624 } 00625 break; 00626 00627 case FLY_MODAL_PRECISION_ENABLE: 00628 fly->use_precision= TRUE; 00629 break; 00630 case FLY_MODAL_PRECISION_DISABLE: 00631 fly->use_precision= FALSE; 00632 break; 00633 00634 case FLY_MODAL_FREELOOK_ENABLE: 00635 fly->use_freelook= TRUE; 00636 break; 00637 case FLY_MODAL_FREELOOK_DISABLE: 00638 fly->use_freelook= FALSE; 00639 break; 00640 } 00641 } 00642 } 00643 00644 00645 static void move_camera(bContext* C, RegionView3D* rv3d, FlyInfo* fly, int orientationChanged, int positionChanged) 00646 { 00647 /* we are in camera view so apply the view ofs and quat to the view matrix and set the camera to the view */ 00648 00649 View3D* v3d = fly->v3d; 00650 Scene *scene= fly->scene; 00651 ID *id_key; 00652 00653 /* transform the parent or the camera? */ 00654 if (fly->root_parent) { 00655 Object *ob_update; 00656 00657 float view_mat[4][4]; 00658 float prev_view_mat[4][4]; 00659 float prev_view_imat[4][4]; 00660 float diff_mat[4][4]; 00661 float parent_mat[4][4]; 00662 00663 ED_view3d_to_m4(prev_view_mat, fly->rv3d->ofs, fly->rv3d->viewquat, fly->rv3d->dist); 00664 invert_m4_m4(prev_view_imat, prev_view_mat); 00665 ED_view3d_to_m4(view_mat, rv3d->ofs, rv3d->viewquat, rv3d->dist); 00666 mult_m4_m4m4(diff_mat, view_mat, prev_view_imat); 00667 mult_m4_m4m4(parent_mat, diff_mat, fly->root_parent->obmat); 00668 object_apply_mat4(fly->root_parent, parent_mat, TRUE, FALSE); 00669 00670 // where_is_object(scene, fly->root_parent); 00671 00672 ob_update= v3d->camera->parent; 00673 while(ob_update) { 00674 DAG_id_tag_update(&ob_update->id, OB_RECALC_OB); 00675 ob_update= ob_update->parent; 00676 } 00677 00678 id_key= &fly->root_parent->id; 00679 } 00680 else { 00681 float view_mat[4][4]; 00682 ED_view3d_to_m4(view_mat, rv3d->ofs, rv3d->viewquat, rv3d->dist); 00683 object_apply_mat4(v3d->camera, view_mat, TRUE, FALSE); 00684 id_key= &v3d->camera->id; 00685 } 00686 00687 /* record the motion */ 00688 if (autokeyframe_cfra_can_key(scene, id_key)) { 00689 ListBase dsources = {NULL, NULL}; 00690 00691 /* add datasource override for the camera object */ 00692 ANIM_relative_keyingset_add_source(&dsources, id_key, NULL, NULL); 00693 00694 /* insert keyframes 00695 * 1) on the first frame 00696 * 2) on each subsequent frame 00697 * TODO: need to check in future that frame changed before doing this 00698 */ 00699 if (orientationChanged) { 00700 KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_ROTATION_ID); 00701 ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA); 00702 } 00703 if (positionChanged) { 00704 KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOCATION_ID); 00705 ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA); 00706 } 00707 00708 /* free temp data */ 00709 BLI_freelistN(&dsources); 00710 } 00711 } 00712 00713 static int flyApply(bContext *C, FlyInfo *fly) 00714 { 00715 #define FLY_ROTATE_FAC 2.5f /* more is faster */ 00716 #define FLY_ZUP_CORRECT_FAC 0.1f /* amount to correct per step */ 00717 #define FLY_ZUP_CORRECT_ACCEL 0.05f /* increase upright momentum each step */ 00718 00719 /* 00720 fly mode - Shift+F 00721 a fly loop where the user can move move the view as if they are flying 00722 */ 00723 RegionView3D *rv3d= fly->rv3d; 00724 ARegion *ar = fly->ar; 00725 00726 float mat[3][3], /* 3x3 copy of the view matrix so we can move along the view axis */ 00727 dvec[3]={0,0,0}, /* this is the direction thast added to the view offset per redraw */ 00728 00729 /* Camera Uprighting variables */ 00730 upvec[3]={0,0,0}, /* stores the view's up vector */ 00731 00732 moffset[2], /* mouse offset from the views center */ 00733 tmp_quat[4]; /* used for rotating the view */ 00734 00735 int 00736 // cent_orig[2], /* view center */ 00737 //XXX- can avoid using // cent[2], /* view center modified */ 00738 xmargin, ymargin; /* x and y margin are define the safe area where the mouses movement wont rotate the view */ 00739 00740 #ifdef NDOF_FLY_DEBUG 00741 static unsigned int iteration = 1; 00742 printf("fly timer %d\n", iteration++); 00743 #endif 00744 00745 00746 xmargin= ar->winx/20.0f; 00747 ymargin= ar->winy/20.0f; 00748 00749 // UNUSED 00750 // cent_orig[0]= ar->winrct.xmin + ar->winx/2; 00751 // cent_orig[1]= ar->winrct.ymin + ar->winy/2; 00752 00753 { 00754 00755 /* mouse offset from the center */ 00756 moffset[0]= fly->mval[0]- ar->winx/2; 00757 moffset[1]= fly->mval[1]- ar->winy/2; 00758 00759 /* enforce a view margin */ 00760 if (moffset[0]>xmargin) moffset[0]-=xmargin; 00761 else if (moffset[0] < -xmargin) moffset[0]+=xmargin; 00762 else moffset[0]=0; 00763 00764 if (moffset[1]>ymargin) moffset[1]-=ymargin; 00765 else if (moffset[1] < -ymargin) moffset[1]+=ymargin; 00766 else moffset[1]=0; 00767 00768 00769 /* scale the mouse movement by this value - scales mouse movement to the view size 00770 * moffset[0]/(ar->winx-xmargin*2) - window size minus margin (same for y) 00771 * 00772 * the mouse moves isnt linear */ 00773 00774 if (moffset[0]) { 00775 moffset[0] /= ar->winx - (xmargin*2); 00776 moffset[0] *= fabsf(moffset[0]); 00777 } 00778 00779 if (moffset[1]) { 00780 moffset[1] /= ar->winy - (ymargin*2); 00781 moffset[1] *= fabsf(moffset[1]); 00782 } 00783 00784 /* Should we redraw? */ 00785 if (fly->speed != 0.0f || moffset[0] || moffset[1] || fly->zlock || fly->xlock || dvec[0] || dvec[1] || dvec[2] ) { 00786 float dvec_tmp[3]; 00787 double time_current; /*time how fast it takes for us to redraw, this is so simple scenes dont fly too fast */ 00788 float time_redraw; 00789 float time_redraw_clamped; 00790 #ifdef NDOF_FLY_DRAW_TOOMUCH 00791 fly->redraw= 1; 00792 #endif 00793 time_current= PIL_check_seconds_timer(); 00794 time_redraw= (float)(time_current - fly->time_lastdraw); 00795 time_redraw_clamped= MIN2(0.05f, time_redraw); /* clamt the redraw time to avoid jitter in roll correction */ 00796 fly->time_lastdraw= time_current; 00797 /*fprintf(stderr, "%f\n", time_redraw);*/ /* 0.002 is a small redraw 0.02 is larger */ 00798 00799 /* Scale the time to use shift to scale the speed down- just like 00800 shift slows many other areas of blender down */ 00801 if (fly->use_precision) 00802 fly->speed= fly->speed * (1.0f-time_redraw_clamped); 00803 00804 copy_m3_m4(mat, rv3d->viewinv); 00805 00806 if (fly->pan_view==TRUE) { 00807 /* pan only */ 00808 dvec_tmp[0]= -moffset[0]; 00809 dvec_tmp[1]= -moffset[1]; 00810 dvec_tmp[2]= 0; 00811 00812 if (fly->use_precision) { 00813 dvec_tmp[0] *= 0.1f; 00814 dvec_tmp[1] *= 0.1f; 00815 } 00816 00817 mul_m3_v3(mat, dvec_tmp); 00818 mul_v3_fl(dvec_tmp, time_redraw * 200.0f * fly->grid); 00819 } 00820 else { 00821 float roll; /* similar to the angle between the camera's up and the Z-up, but its very rough so just roll*/ 00822 00823 /* rotate about the X axis- look up/down */ 00824 if (moffset[1]) { 00825 upvec[0]=1; 00826 upvec[1]=0; 00827 upvec[2]=0; 00828 mul_m3_v3(mat, upvec); 00829 axis_angle_to_quat( tmp_quat, upvec, (float)moffset[1] * time_redraw * -FLY_ROTATE_FAC); /* Rotate about the relative up vec */ 00830 mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, tmp_quat); 00831 00832 if (fly->xlock) fly->xlock = 2; /*check for rotation*/ 00833 if (fly->zlock) fly->zlock = 2; 00834 fly->xlock_momentum= 0.0f; 00835 } 00836 00837 /* rotate about the Y axis- look left/right */ 00838 if (moffset[0]) { 00839 00840 /* if we're upside down invert the moffset */ 00841 upvec[0]= 0.0f; 00842 upvec[1]= 1.0f; 00843 upvec[2]= 0.0f; 00844 mul_m3_v3(mat, upvec); 00845 00846 if (upvec[2] < 0.0f) 00847 moffset[0]= -moffset[0]; 00848 00849 /* make the lock vectors */ 00850 if (fly->zlock) { 00851 upvec[0]= 0.0f; 00852 upvec[1]= 0.0f; 00853 upvec[2]= 1.0f; 00854 } 00855 else { 00856 upvec[0]= 0.0f; 00857 upvec[1]= 1.0f; 00858 upvec[2]= 0.0f; 00859 mul_m3_v3(mat, upvec); 00860 } 00861 00862 axis_angle_to_quat(tmp_quat, upvec, (float)moffset[0] * time_redraw * FLY_ROTATE_FAC); /* Rotate about the relative up vec */ 00863 mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, tmp_quat); 00864 00865 if (fly->xlock) fly->xlock = 2;/*check for rotation*/ 00866 if (fly->zlock) fly->zlock = 2; 00867 } 00868 00869 if (fly->zlock==2) { 00870 upvec[0]= 1.0f; 00871 upvec[1]= 0.0f; 00872 upvec[2]= 0.0f; 00873 mul_m3_v3(mat, upvec); 00874 00875 /*make sure we have some z rolling*/ 00876 if (fabsf(upvec[2]) > 0.00001f) { 00877 roll= upvec[2] * 5.0f; 00878 upvec[0]= 0.0f; /*rotate the view about this axis*/ 00879 upvec[1]= 0.0f; 00880 upvec[2]= 1.0f; 00881 00882 mul_m3_v3(mat, upvec); 00883 axis_angle_to_quat( tmp_quat, upvec, roll*time_redraw_clamped*fly->zlock_momentum * FLY_ZUP_CORRECT_FAC); /* Rotate about the relative up vec */ 00884 mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, tmp_quat); 00885 00886 fly->zlock_momentum += FLY_ZUP_CORRECT_ACCEL; 00887 } 00888 else { 00889 fly->zlock= 1; /* dont check until the view rotates again */ 00890 fly->zlock_momentum= 0.0f; 00891 } 00892 } 00893 00894 if (fly->xlock==2 && moffset[1]==0) { /*only apply xcorrect when mouse isnt applying x rot*/ 00895 upvec[0]=0; 00896 upvec[1]=0; 00897 upvec[2]=1; 00898 mul_m3_v3(mat, upvec); 00899 /*make sure we have some z rolling*/ 00900 if (fabsf(upvec[2]) > 0.00001f) { 00901 roll= upvec[2] * -5.0f; 00902 00903 upvec[0]= 1.0f; /*rotate the view about this axis*/ 00904 upvec[1]= 0.0f; 00905 upvec[2]= 0.0f; 00906 00907 mul_m3_v3(mat, upvec); 00908 00909 axis_angle_to_quat( tmp_quat, upvec, roll*time_redraw_clamped*fly->xlock_momentum*0.1f); /* Rotate about the relative up vec */ 00910 mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, tmp_quat); 00911 00912 fly->xlock_momentum += 0.05f; 00913 } 00914 else { 00915 fly->xlock=1; /* see above */ 00916 fly->xlock_momentum= 0.0f; 00917 } 00918 } 00919 00920 00921 if (!fly->use_freelook) { 00922 /* Normal operation */ 00923 /* define dvec, view direction vector */ 00924 dvec_tmp[0]= dvec_tmp[1]= dvec_tmp[2]= 0.0f; 00925 /* move along the current axis */ 00926 dvec_tmp[fly->axis]= 1.0f; 00927 00928 mul_m3_v3(mat, dvec_tmp); 00929 } 00930 else { 00931 normalize_v3_v3(dvec_tmp, fly->dvec_prev); 00932 if(fly->speed < 0.0f) { 00933 negate_v3(dvec_tmp); 00934 } 00935 } 00936 00937 mul_v3_fl(dvec_tmp, fly->speed * time_redraw * 0.25f); 00938 } 00939 00940 /* impose a directional lag */ 00941 interp_v3_v3v3(dvec, dvec_tmp, fly->dvec_prev, (1.0f/(1.0f+(time_redraw*5.0f)))); 00942 00943 if (rv3d->persp==RV3D_CAMOB) { 00944 Object *lock_ob= fly->root_parent ? fly->root_parent : fly->v3d->camera; 00945 if (lock_ob->protectflag & OB_LOCK_LOCX) dvec[0] = 0.0; 00946 if (lock_ob->protectflag & OB_LOCK_LOCY) dvec[1] = 0.0; 00947 if (lock_ob->protectflag & OB_LOCK_LOCZ) dvec[2] = 0.0; 00948 } 00949 00950 add_v3_v3(rv3d->ofs, dvec); 00951 00952 /* todo, dynamic keys */ 00953 #if 0 00954 if (fly->zlock && fly->xlock) 00955 ED_area_headerprint(fly->ar, "FlyKeys Speed:(+/- | Wheel), Upright Axis:X on/Z on, Slow:Shift, Direction:WASDRF, Ok:LMB, Pan:MMB, Cancel:RMB"); 00956 else if (fly->zlock) 00957 ED_area_headerprint(fly->ar, "FlyKeys Speed:(+/- | Wheel), Upright Axis:X off/Z on, Slow:Shift, Direction:WASDRF, Ok:LMB, Pan:MMB, Cancel:RMB"); 00958 else if (fly->xlock) 00959 ED_area_headerprint(fly->ar, "FlyKeys Speed:(+/- | Wheel), Upright Axis:X on/Z off, Slow:Shift, Direction:WASDRF, Ok:LMB, Pan:MMB, Cancel:RMB"); 00960 else 00961 ED_area_headerprint(fly->ar, "FlyKeys Speed:(+/- | Wheel), Upright Axis:X off/Z off, Slow:Shift, Direction:WASDRF, Ok:LMB, Pan:MMB, Cancel:RMB"); 00962 #endif 00963 00964 if (rv3d->persp==RV3D_CAMOB) 00965 move_camera(C, rv3d, fly, (fly->xlock || fly->zlock || moffset[0] || moffset[1]), fly->speed); 00966 00967 } 00968 else { 00969 /* we're not redrawing but we need to update the time else the view will jump */ 00970 fly->time_lastdraw= PIL_check_seconds_timer(); 00971 } 00972 /* end drawing */ 00973 copy_v3_v3(fly->dvec_prev, dvec); 00974 } 00975 00976 return OPERATOR_FINISHED; 00977 } 00978 00979 static int flyApply_ndof(bContext *C, FlyInfo *fly) 00980 { 00981 /* shorthand for oft-used variables */ 00982 wmNDOFMotionData* ndof = fly->ndof; 00983 const float dt = ndof->dt; 00984 RegionView3D* rv3d = fly->rv3d; 00985 const int flag = U.ndof_flag; 00986 00987 /* int shouldRotate = (flag & NDOF_SHOULD_ROTATE) && (fly->pan_view == FALSE), 00988 shouldTranslate = (flag & (NDOF_SHOULD_PAN | NDOF_SHOULD_ZOOM)); */ 00989 00990 int shouldRotate = (fly->pan_view == FALSE), 00991 shouldTranslate = TRUE; 00992 00993 float view_inv[4]; 00994 invert_qt_qt(view_inv, rv3d->viewquat); 00995 00996 rv3d->rot_angle = 0.f; // disable onscreen rotation doo-dad 00997 00998 if (shouldTranslate) { 00999 const float forward_sensitivity = 1.f; 01000 const float vertical_sensitivity = 0.4f; 01001 const float lateral_sensitivity = 0.6f; 01002 01003 float speed = 10.f; /* blender units per second */ 01004 /* ^^ this is ok for default cube scene, but should scale with.. something */ 01005 01006 float trans[3] = {lateral_sensitivity * ndof->tvec[0], 01007 vertical_sensitivity * ndof->tvec[1], 01008 forward_sensitivity * ndof->tvec[2]}; 01009 01010 if (fly->use_precision) 01011 speed *= 0.2f; 01012 01013 mul_v3_fl(trans, speed * dt); 01014 01015 // transform motion from view to world coordinates 01016 mul_qt_v3(view_inv, trans); 01017 01018 if (flag & NDOF_FLY_HELICOPTER) { 01019 /* replace world z component with device y (yes it makes sense) */ 01020 trans[2] = speed * dt * vertical_sensitivity * ndof->tvec[1]; 01021 } 01022 01023 if (rv3d->persp==RV3D_CAMOB) { 01024 // respect camera position locks 01025 Object *lock_ob= fly->root_parent ? fly->root_parent : fly->v3d->camera; 01026 if (lock_ob->protectflag & OB_LOCK_LOCX) trans[0] = 0.f; 01027 if (lock_ob->protectflag & OB_LOCK_LOCY) trans[1] = 0.f; 01028 if (lock_ob->protectflag & OB_LOCK_LOCZ) trans[2] = 0.f; 01029 } 01030 01031 if (!is_zero_v3(trans)) { 01032 // move center of view opposite of hand motion (this is camera mode, not object mode) 01033 sub_v3_v3(rv3d->ofs, trans); 01034 shouldTranslate = TRUE; 01035 } 01036 else { 01037 shouldTranslate = FALSE; 01038 } 01039 } 01040 01041 if (shouldRotate) { 01042 const float turn_sensitivity = 1.f; 01043 01044 float rotation[4]; 01045 float axis[3]; 01046 float angle = turn_sensitivity * ndof_to_axis_angle(ndof, axis); 01047 01048 if (fabsf(angle) > 0.0001f) { 01049 shouldRotate = TRUE; 01050 01051 if (fly->use_precision) 01052 angle *= 0.2f; 01053 01054 /* transform rotation axis from view to world coordinates */ 01055 mul_qt_v3(view_inv, axis); 01056 01057 // apply rotation to view 01058 axis_angle_to_quat(rotation, axis, angle); 01059 mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rotation); 01060 01061 if (flag & NDOF_LOCK_HORIZON) { 01062 /* force an upright viewpoint 01063 * TODO: make this less... sudden */ 01064 float view_horizon[3] = {1.f, 0.f, 0.f}; /* view +x */ 01065 float view_direction[3] = {0.f, 0.f, -1.f}; /* view -z (into screen) */ 01066 01067 /* find new inverse since viewquat has changed */ 01068 invert_qt_qt(view_inv, rv3d->viewquat); 01069 /* could apply reverse rotation to existing view_inv to save a few cycles */ 01070 01071 /* transform view vectors to world coordinates */ 01072 mul_qt_v3(view_inv, view_horizon); 01073 mul_qt_v3(view_inv, view_direction); 01074 01075 /* find difference between view & world horizons 01076 * true horizon lives in world xy plane, so look only at difference in z */ 01077 angle = -asinf(view_horizon[2]); 01078 01079 #ifdef NDOF_FLY_DEBUG 01080 printf("lock horizon: adjusting %.1f degrees\n\n", RAD2DEG(angle)); 01081 #endif 01082 01083 /* rotate view so view horizon = world horizon */ 01084 axis_angle_to_quat(rotation, view_direction, angle); 01085 mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rotation); 01086 } 01087 01088 rv3d->view = RV3D_VIEW_USER; 01089 } 01090 else { 01091 shouldRotate = FALSE; 01092 } 01093 } 01094 01095 if (shouldTranslate || shouldRotate) { 01096 fly->redraw = TRUE; 01097 01098 if (rv3d->persp==RV3D_CAMOB) { 01099 move_camera(C, rv3d, fly, shouldRotate, shouldTranslate); 01100 } 01101 } 01102 01103 return OPERATOR_FINISHED; 01104 } 01105 01106 01107 static int fly_invoke(bContext *C, wmOperator *op, wmEvent *event) 01108 { 01109 RegionView3D *rv3d= CTX_wm_region_view3d(C); 01110 FlyInfo *fly; 01111 01112 if (rv3d->viewlock) 01113 return OPERATOR_CANCELLED; 01114 01115 fly= MEM_callocN(sizeof(FlyInfo), "FlyOperation"); 01116 01117 op->customdata= fly; 01118 01119 if (initFlyInfo(C, fly, op, event)==FALSE) { 01120 MEM_freeN(op->customdata); 01121 return OPERATOR_CANCELLED; 01122 } 01123 01124 flyEvent(fly, event); 01125 01126 WM_event_add_modal_handler(C, op); 01127 01128 return OPERATOR_RUNNING_MODAL; 01129 } 01130 01131 static int fly_cancel(bContext *C, wmOperator *op) 01132 { 01133 FlyInfo *fly = op->customdata; 01134 01135 fly->state = FLY_CANCEL; 01136 flyEnd(C, fly); 01137 op->customdata= NULL; 01138 01139 return OPERATOR_CANCELLED; 01140 } 01141 01142 static int fly_modal(bContext *C, wmOperator *op, wmEvent *event) 01143 { 01144 int exit_code; 01145 short do_draw= FALSE; 01146 FlyInfo *fly= op->customdata; 01147 RegionView3D *rv3d= fly->rv3d; 01148 Object *fly_object= fly->root_parent ? fly->root_parent : fly->v3d->camera; 01149 01150 fly->redraw= 0; 01151 01152 flyEvent(fly, event); 01153 01154 if (fly->ndof) { /* 3D mouse overrules [2D mouse + timer] */ 01155 if (event->type==NDOF_MOTION) { 01156 flyApply_ndof(C, fly); 01157 } 01158 } 01159 else if (event->type==TIMER && event->customdata == fly->timer) { 01160 flyApply(C, fly); 01161 } 01162 01163 do_draw |= fly->redraw; 01164 01165 exit_code = flyEnd(C, fly); 01166 01167 if (exit_code!=OPERATOR_RUNNING_MODAL) 01168 do_draw= TRUE; 01169 01170 if (do_draw) { 01171 if (rv3d->persp==RV3D_CAMOB) { 01172 WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, fly_object); 01173 } 01174 01175 // puts("redraw!"); // too frequent, commented with NDOF_FLY_DRAW_TOOMUCH for now 01176 ED_region_tag_redraw(CTX_wm_region(C)); 01177 } 01178 01179 return exit_code; 01180 } 01181 01182 void VIEW3D_OT_fly(wmOperatorType *ot) 01183 { 01184 /* identifiers */ 01185 ot->name= "Fly Navigation"; 01186 ot->description= "Interactively fly around the scene"; 01187 ot->idname= "VIEW3D_OT_fly"; 01188 01189 /* api callbacks */ 01190 ot->invoke= fly_invoke; 01191 ot->cancel= fly_cancel; 01192 ot->modal= fly_modal; 01193 ot->poll= ED_operator_view3d_active; 01194 01195 /* flags */ 01196 ot->flag= OPTYPE_BLOCKING; 01197 }