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