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 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. 00019 * All rights reserved. 00020 * 00021 * The Original Code is: all of this file. 00022 * 00023 * Contributor(s): none yet. 00024 * 00025 * ***** END GPL LICENSE BLOCK ***** 00026 */ 00027 00033 #include <stdlib.h> 00034 #include <stdio.h> 00035 #include <string.h> 00036 #include <math.h> 00037 #include <float.h> 00038 00039 #ifndef WIN32 00040 #include <unistd.h> 00041 #else 00042 #include <io.h> 00043 #endif 00044 00045 #include "MEM_guardedalloc.h" 00046 00047 #include "DNA_anim_types.h" 00048 #include "DNA_armature_types.h" 00049 #include "DNA_constraint_types.h" 00050 #include "DNA_meshdata_types.h" 00051 #include "DNA_movieclip_types.h" 00052 #include "DNA_scene_types.h" /* PET modes */ 00053 00054 #include "RNA_access.h" 00055 00056 #include "BIF_gl.h" 00057 #include "BIF_glutil.h" 00058 00059 #include "BKE_nla.h" 00060 #include "BKE_bmesh.h" 00061 #include "BKE_context.h" 00062 #include "BKE_constraint.h" 00063 #include "BKE_global.h" 00064 #include "BKE_particle.h" 00065 #include "BKE_pointcache.h" 00066 #include "BKE_unit.h" 00067 00068 #include "ED_image.h" 00069 #include "ED_keyframing.h" 00070 #include "ED_screen.h" 00071 #include "ED_space_api.h" 00072 #include "ED_markers.h" 00073 #include "ED_view3d.h" 00074 #include "ED_mesh.h" 00075 #include "ED_clip.h" 00076 00077 #include "UI_view2d.h" 00078 #include "WM_types.h" 00079 #include "WM_api.h" 00080 00081 #include "BLI_math.h" 00082 #include "BLI_blenlib.h" 00083 #include "BLI_utildefines.h" 00084 #include "BLI_editVert.h" 00085 #include "BLI_ghash.h" 00086 #include "BLI_linklist.h" 00087 00088 #include "UI_resources.h" 00089 00090 //#include "blendef.h" 00091 // 00092 //#include "mydevice.h" 00093 00094 #include "transform.h" 00095 00096 static void drawTransformApply(const struct bContext *C, struct ARegion *ar, void *arg); 00097 static int doEdgeSlide(TransInfo *t, float perc); 00098 00099 /* ************************** SPACE DEPENDANT CODE **************************** */ 00100 00101 void setTransformViewMatrices(TransInfo *t) 00102 { 00103 if(t->spacetype==SPACE_VIEW3D && t->ar && t->ar->regiontype == RGN_TYPE_WINDOW) { 00104 RegionView3D *rv3d = t->ar->regiondata; 00105 00106 copy_m4_m4(t->viewmat, rv3d->viewmat); 00107 copy_m4_m4(t->viewinv, rv3d->viewinv); 00108 copy_m4_m4(t->persmat, rv3d->persmat); 00109 copy_m4_m4(t->persinv, rv3d->persinv); 00110 t->persp = rv3d->persp; 00111 } 00112 else { 00113 unit_m4(t->viewmat); 00114 unit_m4(t->viewinv); 00115 unit_m4(t->persmat); 00116 unit_m4(t->persinv); 00117 t->persp = RV3D_ORTHO; 00118 } 00119 00120 calculateCenter2D(t); 00121 } 00122 00123 static void convertViewVec2D(View2D *v2d, float *vec, int dx, int dy) 00124 { 00125 float divx, divy; 00126 00127 divx= v2d->mask.xmax - v2d->mask.xmin; 00128 divy= v2d->mask.ymax - v2d->mask.ymin; 00129 00130 vec[0]= (v2d->cur.xmax - v2d->cur.xmin) * dx / divx; 00131 vec[1]= (v2d->cur.ymax - v2d->cur.ymin) * dy / divy; 00132 vec[2]= 0.0f; 00133 } 00134 00135 void convertViewVec(TransInfo *t, float *vec, int dx, int dy) 00136 { 00137 if(t->spacetype==SPACE_VIEW3D) { 00138 if(t->ar->regiontype == RGN_TYPE_WINDOW) { 00139 float mval_f[2]; 00140 mval_f[0]= dx; 00141 mval_f[1]= dy; 00142 ED_view3d_win_to_delta(t->ar, mval_f, vec); 00143 } 00144 } 00145 else if(t->spacetype==SPACE_IMAGE) { 00146 float aspx, aspy; 00147 00148 convertViewVec2D(t->view, vec, dx, dy); 00149 00150 ED_space_image_uv_aspect(t->sa->spacedata.first, &aspx, &aspy); 00151 vec[0]*= aspx; 00152 vec[1]*= aspy; 00153 } 00154 else if(ELEM(t->spacetype, SPACE_IPO, SPACE_NLA)) { 00155 convertViewVec2D(t->view, vec, dx, dy); 00156 } 00157 else if(ELEM(t->spacetype, SPACE_NODE, SPACE_SEQ)) { 00158 convertViewVec2D(&t->ar->v2d, vec, dx, dy); 00159 } 00160 else if(t->spacetype==SPACE_CLIP) { 00161 View2D *v2d = t->view; 00162 float divx, divy; 00163 00164 divx= v2d->mask.xmax-v2d->mask.xmin; 00165 divy= v2d->mask.ymax-v2d->mask.ymin; 00166 00167 vec[0]= (v2d->cur.xmax-v2d->cur.xmin)*(dx)/divx; 00168 vec[1]= (v2d->cur.ymax-v2d->cur.ymin)*(dy)/divy; 00169 vec[2]= 0.0f; 00170 } 00171 } 00172 00173 void projectIntView(TransInfo *t, float *vec, int *adr) 00174 { 00175 if (t->spacetype==SPACE_VIEW3D) { 00176 if(t->ar->regiontype == RGN_TYPE_WINDOW) 00177 project_int_noclip(t->ar, vec, adr); 00178 } 00179 else if(t->spacetype==SPACE_IMAGE) { 00180 float aspx, aspy, v[2]; 00181 00182 ED_space_image_uv_aspect(t->sa->spacedata.first, &aspx, &aspy); 00183 v[0]= vec[0]/aspx; 00184 v[1]= vec[1]/aspy; 00185 00186 UI_view2d_to_region_no_clip(t->view, v[0], v[1], adr, adr+1); 00187 } 00188 else if(t->spacetype == SPACE_ACTION) { 00189 int out[2] = {0, 0}; 00190 #if 0 00191 SpaceAction *sact = t->sa->spacedata.first; 00192 00193 if (sact->flag & SACTION_DRAWTIME) { 00194 //vec[0] = vec[0]/((t->scene->r.frs_sec / t->scene->r.frs_sec_base)); 00195 /* same as below */ 00196 UI_view2d_to_region_no_clip((View2D *)t->view, vec[0], vec[1], out, out+1); 00197 } 00198 else 00199 #endif 00200 { 00201 UI_view2d_to_region_no_clip((View2D *)t->view, vec[0], vec[1], out, out+1); 00202 } 00203 00204 adr[0]= out[0]; 00205 adr[1]= out[1]; 00206 } 00207 else if(ELEM(t->spacetype, SPACE_IPO, SPACE_NLA)) { 00208 int out[2] = {0, 0}; 00209 00210 UI_view2d_to_region_no_clip((View2D *)t->view, vec[0], vec[1], out, out+1); 00211 adr[0]= out[0]; 00212 adr[1]= out[1]; 00213 } 00214 else if(t->spacetype==SPACE_SEQ) { /* XXX not tested yet, but should work */ 00215 int out[2] = {0, 0}; 00216 00217 UI_view2d_to_region_no_clip((View2D *)t->view, vec[0], vec[1], out, out+1); 00218 adr[0]= out[0]; 00219 adr[1]= out[1]; 00220 } 00221 else if(t->spacetype==SPACE_CLIP) { 00222 UI_view2d_to_region_no_clip(t->view, vec[0], vec[1], adr, adr+1); 00223 } 00224 } 00225 00226 void projectFloatView(TransInfo *t, float *vec, float *adr) 00227 { 00228 if (t->spacetype==SPACE_VIEW3D) { 00229 if(t->ar->regiontype == RGN_TYPE_WINDOW) 00230 project_float_noclip(t->ar, vec, adr); 00231 } 00232 else if(ELEM(t->spacetype, SPACE_IMAGE, SPACE_CLIP)) { 00233 int a[2]; 00234 00235 projectIntView(t, vec, a); 00236 adr[0]= a[0]; 00237 adr[1]= a[1]; 00238 } 00239 else if(ELEM(t->spacetype, SPACE_IPO, SPACE_NLA)) { 00240 int a[2]; 00241 00242 projectIntView(t, vec, a); 00243 adr[0]= a[0]; 00244 adr[1]= a[1]; 00245 } 00246 } 00247 00248 void applyAspectRatio(TransInfo *t, float *vec) 00249 { 00250 if ((t->spacetype==SPACE_IMAGE) && (t->mode==TFM_TRANSLATION)) { 00251 SpaceImage *sima= t->sa->spacedata.first; 00252 float aspx, aspy; 00253 00254 if((sima->flag & SI_COORDFLOATS)==0) { 00255 int width, height; 00256 ED_space_image_size(sima, &width, &height); 00257 00258 vec[0] *= width; 00259 vec[1] *= height; 00260 } 00261 00262 ED_space_image_uv_aspect(sima, &aspx, &aspy); 00263 vec[0] /= aspx; 00264 vec[1] /= aspy; 00265 } 00266 } 00267 00268 void removeAspectRatio(TransInfo *t, float *vec) 00269 { 00270 if ((t->spacetype==SPACE_IMAGE) && (t->mode==TFM_TRANSLATION)) { 00271 SpaceImage *sima= t->sa->spacedata.first; 00272 float aspx, aspy; 00273 00274 if((sima->flag & SI_COORDFLOATS)==0) { 00275 int width, height; 00276 ED_space_image_size(sima, &width, &height); 00277 00278 vec[0] /= width; 00279 vec[1] /= height; 00280 } 00281 00282 ED_space_image_uv_aspect(sima, &aspx, &aspy); 00283 vec[0] *= aspx; 00284 vec[1] *= aspy; 00285 } 00286 } 00287 00288 static void viewRedrawForce(const bContext *C, TransInfo *t) 00289 { 00290 if (t->spacetype == SPACE_VIEW3D) 00291 { 00292 /* Do we need more refined tags? */ 00293 if(t->flag & T_POSE) 00294 WM_event_add_notifier(C, NC_OBJECT|ND_POSE, NULL); 00295 else 00296 WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL); 00297 00298 /* for realtime animation record - send notifiers recognised by animation editors */ 00299 // XXX: is this notifier a lame duck? 00300 if ((t->animtimer) && IS_AUTOKEY_ON(t->scene)) 00301 WM_event_add_notifier(C, NC_OBJECT|ND_KEYS, NULL); 00302 00303 } 00304 else if (t->spacetype == SPACE_ACTION) { 00305 //SpaceAction *saction= (SpaceAction *)t->sa->spacedata.first; 00306 WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|NA_EDITED, NULL); 00307 } 00308 else if (t->spacetype == SPACE_IPO) { 00309 //SpaceIpo *sipo= (SpaceIpo *)t->sa->spacedata.first; 00310 WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|NA_EDITED, NULL); 00311 } 00312 else if (t->spacetype == SPACE_NLA) { 00313 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL); 00314 } 00315 else if(t->spacetype == SPACE_NODE) 00316 { 00317 //ED_area_tag_redraw(t->sa); 00318 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_NODE_VIEW, NULL); 00319 } 00320 else if(t->spacetype == SPACE_SEQ) 00321 { 00322 WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER, NULL); 00323 } 00324 else if (t->spacetype==SPACE_IMAGE) { 00325 // XXX how to deal with lock? 00326 SpaceImage *sima= (SpaceImage*)t->sa->spacedata.first; 00327 if(sima->lock) WM_event_add_notifier(C, NC_GEOM|ND_DATA, t->obedit->data); 00328 else ED_area_tag_redraw(t->sa); 00329 } 00330 else if (t->spacetype==SPACE_CLIP) { 00331 SpaceClip *sc= (SpaceClip*)t->sa->spacedata.first; 00332 MovieClip *clip= ED_space_clip(sc); 00333 00334 /* objects could be parented to tracking data, so send this for viewport refresh */ 00335 WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL); 00336 00337 WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, clip); 00338 } 00339 } 00340 00341 static void viewRedrawPost(bContext *C, TransInfo *t) 00342 { 00343 ED_area_headerprint(t->sa, NULL); 00344 00345 if(t->spacetype == SPACE_VIEW3D) { 00346 /* if autokeying is enabled, send notifiers that keyframes were added */ 00347 if (IS_AUTOKEY_ON(t->scene)) 00348 WM_main_add_notifier(NC_ANIMATION|ND_KEYFRAME|NA_EDITED, NULL); 00349 00350 /* XXX temp, first hack to get auto-render in compositor work (ton) */ 00351 WM_event_add_notifier(C, NC_SCENE|ND_TRANSFORM_DONE, CTX_data_scene(C)); 00352 00353 } 00354 00355 #if 0 // TRANSFORM_FIX_ME 00356 if(t->spacetype==SPACE_VIEW3D) { 00357 allqueue(REDRAWBUTSOBJECT, 0); 00358 allqueue(REDRAWVIEW3D, 0); 00359 } 00360 else if(t->spacetype==SPACE_IMAGE) { 00361 allqueue(REDRAWIMAGE, 0); 00362 allqueue(REDRAWVIEW3D, 0); 00363 } 00364 else if(ELEM3(t->spacetype, SPACE_ACTION, SPACE_NLA, SPACE_IPO)) { 00365 allqueue(REDRAWVIEW3D, 0); 00366 allqueue(REDRAWACTION, 0); 00367 allqueue(REDRAWNLA, 0); 00368 allqueue(REDRAWIPO, 0); 00369 allqueue(REDRAWTIME, 0); 00370 allqueue(REDRAWBUTSOBJECT, 0); 00371 } 00372 00373 scrarea_queue_headredraw(curarea); 00374 #endif 00375 } 00376 00377 /* ************************** TRANSFORMATIONS **************************** */ 00378 00379 void BIF_selectOrientation(void) 00380 { 00381 #if 0 // TRANSFORM_FIX_ME 00382 short val; 00383 char *str_menu = BIF_menustringTransformOrientation("Orientation"); 00384 val= pupmenu(str_menu); 00385 MEM_freeN(str_menu); 00386 00387 if(val >= 0) { 00388 G.vd->twmode = val; 00389 } 00390 #endif 00391 } 00392 00393 static void view_editmove(unsigned short UNUSED(event)) 00394 { 00395 #if 0 // TRANSFORM_FIX_ME 00396 int refresh = 0; 00397 /* Regular: Zoom in */ 00398 /* Shift: Scroll up */ 00399 /* Ctrl: Scroll right */ 00400 /* Alt-Shift: Rotate up */ 00401 /* Alt-Ctrl: Rotate right */ 00402 00403 /* only work in 3D window for now 00404 * In the end, will have to send to event to a 2D window handler instead 00405 */ 00406 if (Trans.flag & T_2D_EDIT) 00407 return; 00408 00409 switch(event) { 00410 case WHEELUPMOUSE: 00411 00412 if( G.qual & LR_SHIFTKEY ) { 00413 if( G.qual & LR_ALTKEY ) { 00414 G.qual &= ~LR_SHIFTKEY; 00415 persptoetsen(PAD2); 00416 G.qual |= LR_SHIFTKEY; 00417 } else { 00418 persptoetsen(PAD2); 00419 } 00420 } else if( G.qual & LR_CTRLKEY ) { 00421 if( G.qual & LR_ALTKEY ) { 00422 G.qual &= ~LR_CTRLKEY; 00423 persptoetsen(PAD4); 00424 G.qual |= LR_CTRLKEY; 00425 } else { 00426 persptoetsen(PAD4); 00427 } 00428 } else if(U.uiflag & USER_WHEELZOOMDIR) 00429 persptoetsen(PADMINUS); 00430 else 00431 persptoetsen(PADPLUSKEY); 00432 00433 refresh = 1; 00434 break; 00435 case WHEELDOWNMOUSE: 00436 if( G.qual & LR_SHIFTKEY ) { 00437 if( G.qual & LR_ALTKEY ) { 00438 G.qual &= ~LR_SHIFTKEY; 00439 persptoetsen(PAD8); 00440 G.qual |= LR_SHIFTKEY; 00441 } else { 00442 persptoetsen(PAD8); 00443 } 00444 } else if( G.qual & LR_CTRLKEY ) { 00445 if( G.qual & LR_ALTKEY ) { 00446 G.qual &= ~LR_CTRLKEY; 00447 persptoetsen(PAD6); 00448 G.qual |= LR_CTRLKEY; 00449 } else { 00450 persptoetsen(PAD6); 00451 } 00452 } else if(U.uiflag & USER_WHEELZOOMDIR) 00453 persptoetsen(PADPLUSKEY); 00454 else 00455 persptoetsen(PADMINUS); 00456 00457 refresh = 1; 00458 break; 00459 } 00460 00461 if (refresh) 00462 setTransformViewMatrices(&Trans); 00463 #endif 00464 } 00465 00466 /* ************************************************* */ 00467 00468 /* NOTE: these defines are saved in keymap files, do not change values but just add new ones */ 00469 #define TFM_MODAL_CANCEL 1 00470 #define TFM_MODAL_CONFIRM 2 00471 #define TFM_MODAL_TRANSLATE 3 00472 #define TFM_MODAL_ROTATE 4 00473 #define TFM_MODAL_RESIZE 5 00474 #define TFM_MODAL_SNAP_INV_ON 6 00475 #define TFM_MODAL_SNAP_INV_OFF 7 00476 #define TFM_MODAL_SNAP_TOGGLE 8 00477 #define TFM_MODAL_AXIS_X 9 00478 #define TFM_MODAL_AXIS_Y 10 00479 #define TFM_MODAL_AXIS_Z 11 00480 #define TFM_MODAL_PLANE_X 12 00481 #define TFM_MODAL_PLANE_Y 13 00482 #define TFM_MODAL_PLANE_Z 14 00483 #define TFM_MODAL_CONS_OFF 15 00484 #define TFM_MODAL_ADD_SNAP 16 00485 #define TFM_MODAL_REMOVE_SNAP 17 00486 /* 18 and 19 used by numinput, defined in transform.h 00487 * */ 00488 #define TFM_MODAL_PROPSIZE_UP 20 00489 #define TFM_MODAL_PROPSIZE_DOWN 21 00490 #define TFM_MODAL_AUTOIK_LEN_INC 22 00491 #define TFM_MODAL_AUTOIK_LEN_DEC 23 00492 00493 /* called in transform_ops.c, on each regeneration of keymaps */ 00494 wmKeyMap* transform_modal_keymap(wmKeyConfig *keyconf) 00495 { 00496 static EnumPropertyItem modal_items[] = { 00497 {TFM_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""}, 00498 {TFM_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""}, 00499 {TFM_MODAL_TRANSLATE, "TRANSLATE", 0, "Translate", ""}, 00500 {TFM_MODAL_ROTATE, "ROTATE", 0, "Rotate", ""}, 00501 {TFM_MODAL_RESIZE, "RESIZE", 0, "Resize", ""}, 00502 {TFM_MODAL_SNAP_INV_ON, "SNAP_INV_ON", 0, "Invert Snap On", ""}, 00503 {TFM_MODAL_SNAP_INV_OFF, "SNAP_INV_OFF", 0, "Invert Snap Off", ""}, 00504 {TFM_MODAL_SNAP_TOGGLE, "SNAP_TOGGLE", 0, "Snap Toggle", ""}, 00505 {TFM_MODAL_AXIS_X, "AXIS_X", 0, "Orientation X axis", ""}, 00506 {TFM_MODAL_AXIS_Y, "AXIS_Y", 0, "Orientation Y axis", ""}, 00507 {TFM_MODAL_AXIS_Z, "AXIS_Z", 0, "Orientation Z axis", ""}, 00508 {TFM_MODAL_PLANE_X, "PLANE_X", 0, "Orientation X plane", ""}, 00509 {TFM_MODAL_PLANE_Y, "PLANE_Y", 0, "Orientation Y plane", ""}, 00510 {TFM_MODAL_PLANE_Z, "PLANE_Z", 0, "Orientation Z plane", ""}, 00511 {TFM_MODAL_CONS_OFF, "CONS_OFF", 0, "Remove Constraints", ""}, 00512 {TFM_MODAL_ADD_SNAP, "ADD_SNAP", 0, "Add Snap Point", ""}, 00513 {TFM_MODAL_REMOVE_SNAP, "REMOVE_SNAP", 0, "Remove Last Snap Point", ""}, 00514 {NUM_MODAL_INCREMENT_UP, "INCREMENT_UP", 0, "Numinput Increment Up", ""}, 00515 {NUM_MODAL_INCREMENT_DOWN, "INCREMENT_DOWN", 0, "Numinput Increment Down", ""}, 00516 {TFM_MODAL_PROPSIZE_UP, "PROPORTIONAL_SIZE_UP", 0, "Increase Proportional Influence", ""}, 00517 {TFM_MODAL_PROPSIZE_DOWN, "PROPORTIONAL_SIZE_DOWN", 0, "Decrease Proportional Influence", ""}, 00518 {TFM_MODAL_AUTOIK_LEN_INC, "AUTOIK_CHAIN_LEN_UP", 0, "Increase Max AutoIK Chain Length", ""}, 00519 {TFM_MODAL_AUTOIK_LEN_DEC, "AUTOIK_CHAIN_LEN_DOWN", 0, "Decrease Max AutoIK Chain Length", ""}, 00520 {0, NULL, 0, NULL, NULL}}; 00521 00522 wmKeyMap *keymap= WM_modalkeymap_get(keyconf, "Transform Modal Map"); 00523 00524 /* this function is called for each spacetype, only needs to add map once */ 00525 if(keymap) return NULL; 00526 00527 keymap= WM_modalkeymap_add(keyconf, "Transform Modal Map", modal_items); 00528 00529 /* items for modal map */ 00530 WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, TFM_MODAL_CANCEL); 00531 WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_ANY, 0, TFM_MODAL_CONFIRM); 00532 WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, TFM_MODAL_CONFIRM); 00533 WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, KM_ANY, 0, TFM_MODAL_CONFIRM); 00534 00535 WM_modalkeymap_add_item(keymap, GKEY, KM_PRESS, 0, 0, TFM_MODAL_TRANSLATE); 00536 WM_modalkeymap_add_item(keymap, RKEY, KM_PRESS, 0, 0, TFM_MODAL_ROTATE); 00537 WM_modalkeymap_add_item(keymap, SKEY, KM_PRESS, 0, 0, TFM_MODAL_RESIZE); 00538 00539 WM_modalkeymap_add_item(keymap, TABKEY, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_SNAP_TOGGLE); 00540 00541 WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, TFM_MODAL_SNAP_INV_ON); 00542 WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, TFM_MODAL_SNAP_INV_OFF); 00543 00544 WM_modalkeymap_add_item(keymap, RIGHTCTRLKEY, KM_PRESS, KM_ANY, 0, TFM_MODAL_SNAP_INV_ON); 00545 WM_modalkeymap_add_item(keymap, RIGHTCTRLKEY, KM_RELEASE, KM_ANY, 0, TFM_MODAL_SNAP_INV_OFF); 00546 00547 WM_modalkeymap_add_item(keymap, AKEY, KM_PRESS, 0, 0, TFM_MODAL_ADD_SNAP); 00548 WM_modalkeymap_add_item(keymap, AKEY, KM_PRESS, KM_ALT, 0, TFM_MODAL_REMOVE_SNAP); 00549 00550 WM_modalkeymap_add_item(keymap, PAGEUPKEY, KM_PRESS, 0, 0, TFM_MODAL_PROPSIZE_UP); 00551 WM_modalkeymap_add_item(keymap, PAGEDOWNKEY, KM_PRESS, 0, 0, TFM_MODAL_PROPSIZE_DOWN); 00552 WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, 0, 0, TFM_MODAL_PROPSIZE_UP); 00553 WM_modalkeymap_add_item(keymap, WHEELUPMOUSE, KM_PRESS, 0, 0, TFM_MODAL_PROPSIZE_DOWN); 00554 00555 WM_modalkeymap_add_item(keymap, PAGEUPKEY, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_AUTOIK_LEN_INC); 00556 WM_modalkeymap_add_item(keymap, PAGEDOWNKEY, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_AUTOIK_LEN_DEC); 00557 WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_AUTOIK_LEN_INC); 00558 WM_modalkeymap_add_item(keymap, WHEELUPMOUSE, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_AUTOIK_LEN_DEC); 00559 00560 return keymap; 00561 } 00562 00563 00564 int transformEvent(TransInfo *t, wmEvent *event) 00565 { 00566 float mati[3][3]= MAT3_UNITY; 00567 char cmode = constraintModeToChar(t); 00568 int handled = 1; 00569 00570 t->redraw |= handleMouseInput(t, &t->mouse, event); 00571 00572 if (event->type == MOUSEMOVE) 00573 { 00574 if (t->modifiers & MOD_CONSTRAINT_SELECT) 00575 t->con.mode |= CON_SELECT; 00576 00577 copy_v2_v2_int(t->mval, event->mval); 00578 00579 // t->redraw |= TREDRAW_SOFT; /* Use this for soft redraw. Might cause flicker in object mode */ 00580 t->redraw |= TREDRAW_HARD; 00581 00582 00583 if (t->state == TRANS_STARTING) { 00584 t->state = TRANS_RUNNING; 00585 } 00586 00587 applyMouseInput(t, &t->mouse, t->mval, t->values); 00588 00589 // Snapping mouse move events 00590 t->redraw |= handleSnapping(t, event); 00591 } 00592 00593 /* handle modal keymap first */ 00594 if (event->type == EVT_MODAL_MAP) { 00595 switch (event->val) { 00596 case TFM_MODAL_CANCEL: 00597 t->state = TRANS_CANCEL; 00598 break; 00599 case TFM_MODAL_CONFIRM: 00600 t->state = TRANS_CONFIRM; 00601 break; 00602 case TFM_MODAL_TRANSLATE: 00603 /* only switch when... */ 00604 if( ELEM3(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL) ) { 00605 resetTransRestrictions(t); 00606 restoreTransObjects(t); 00607 initTranslation(t); 00608 initSnapping(t, NULL); // need to reinit after mode change 00609 t->redraw |= TREDRAW_HARD; 00610 } 00611 else if(t->mode == TFM_TRANSLATION) { 00612 if(t->options&CTX_MOVIECLIP) { 00613 restoreTransObjects(t); 00614 00615 t->flag^= T_ALT_TRANSFORM; 00616 t->redraw |= TREDRAW_HARD; 00617 } 00618 } 00619 break; 00620 case TFM_MODAL_ROTATE: 00621 /* only switch when... */ 00622 if(!(t->options & CTX_TEXTURE) && !(t->options & CTX_MOVIECLIP)) { 00623 if( ELEM4(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION) ) { 00624 00625 resetTransRestrictions(t); 00626 00627 if (t->mode == TFM_ROTATION) { 00628 restoreTransObjects(t); 00629 initTrackball(t); 00630 } 00631 else { 00632 restoreTransObjects(t); 00633 initRotation(t); 00634 } 00635 initSnapping(t, NULL); // need to reinit after mode change 00636 t->redraw |= TREDRAW_HARD; 00637 } 00638 } 00639 break; 00640 case TFM_MODAL_RESIZE: 00641 /* only switch when... */ 00642 if( ELEM3(t->mode, TFM_ROTATION, TFM_TRANSLATION, TFM_TRACKBALL) ) { 00643 resetTransRestrictions(t); 00644 restoreTransObjects(t); 00645 initResize(t); 00646 initSnapping(t, NULL); // need to reinit after mode change 00647 t->redraw |= TREDRAW_HARD; 00648 } 00649 break; 00650 00651 case TFM_MODAL_SNAP_INV_ON: 00652 t->modifiers |= MOD_SNAP_INVERT; 00653 t->redraw |= TREDRAW_HARD; 00654 break; 00655 case TFM_MODAL_SNAP_INV_OFF: 00656 t->modifiers &= ~MOD_SNAP_INVERT; 00657 t->redraw |= TREDRAW_HARD; 00658 break; 00659 case TFM_MODAL_SNAP_TOGGLE: 00660 t->modifiers ^= MOD_SNAP; 00661 t->redraw |= TREDRAW_HARD; 00662 break; 00663 case TFM_MODAL_AXIS_X: 00664 if ((t->flag & T_NO_CONSTRAINT)==0) { 00665 if (cmode == 'X') { 00666 stopConstraint(t); 00667 } 00668 else { 00669 if (t->flag & T_2D_EDIT) { 00670 setUserConstraint(t, V3D_MANIP_GLOBAL, (CON_AXIS0), "along X"); 00671 } 00672 else { 00673 setUserConstraint(t, t->current_orientation, (CON_AXIS0), "along %s X"); 00674 } 00675 } 00676 t->redraw |= TREDRAW_HARD; 00677 } 00678 break; 00679 case TFM_MODAL_AXIS_Y: 00680 if ((t->flag & T_NO_CONSTRAINT)==0) { 00681 if (cmode == 'Y') { 00682 stopConstraint(t); 00683 } 00684 else { 00685 if (t->flag & T_2D_EDIT) { 00686 setUserConstraint(t, V3D_MANIP_GLOBAL, (CON_AXIS1), "along Y"); 00687 } 00688 else { 00689 setUserConstraint(t, t->current_orientation, (CON_AXIS1), "along %s Y"); 00690 } 00691 } 00692 t->redraw |= TREDRAW_HARD; 00693 } 00694 break; 00695 case TFM_MODAL_AXIS_Z: 00696 if ((t->flag & (T_NO_CONSTRAINT|T_2D_EDIT))== 0) { 00697 if (cmode == 'Z') { 00698 stopConstraint(t); 00699 } 00700 else { 00701 setUserConstraint(t, t->current_orientation, (CON_AXIS2), "along %s Z"); 00702 } 00703 t->redraw |= TREDRAW_HARD; 00704 } 00705 break; 00706 case TFM_MODAL_PLANE_X: 00707 if ((t->flag & (T_NO_CONSTRAINT|T_2D_EDIT))== 0) { 00708 if (cmode == 'X') { 00709 stopConstraint(t); 00710 } 00711 else { 00712 setUserConstraint(t, t->current_orientation, (CON_AXIS1|CON_AXIS2), "locking %s X"); 00713 } 00714 t->redraw |= TREDRAW_HARD; 00715 } 00716 break; 00717 case TFM_MODAL_PLANE_Y: 00718 if ((t->flag & (T_NO_CONSTRAINT|T_2D_EDIT))== 0) { 00719 if (cmode == 'Y') { 00720 stopConstraint(t); 00721 } 00722 else { 00723 setUserConstraint(t, t->current_orientation, (CON_AXIS0|CON_AXIS2), "locking %s Y"); 00724 } 00725 t->redraw |= TREDRAW_HARD; 00726 } 00727 break; 00728 case TFM_MODAL_PLANE_Z: 00729 if ((t->flag & (T_NO_CONSTRAINT|T_2D_EDIT))== 0) { 00730 if (cmode == 'Z') { 00731 stopConstraint(t); 00732 } 00733 else { 00734 setUserConstraint(t, t->current_orientation, (CON_AXIS0|CON_AXIS1), "locking %s Z"); 00735 } 00736 t->redraw |= TREDRAW_HARD; 00737 } 00738 break; 00739 case TFM_MODAL_CONS_OFF: 00740 if ((t->flag & T_NO_CONSTRAINT)==0) { 00741 stopConstraint(t); 00742 t->redraw |= TREDRAW_HARD; 00743 } 00744 break; 00745 case TFM_MODAL_ADD_SNAP: 00746 addSnapPoint(t); 00747 t->redraw |= TREDRAW_HARD; 00748 break; 00749 case TFM_MODAL_REMOVE_SNAP: 00750 removeSnapPoint(t); 00751 t->redraw |= TREDRAW_HARD; 00752 break; 00753 case TFM_MODAL_PROPSIZE_UP: 00754 if(t->flag & T_PROP_EDIT) { 00755 t->prop_size*= 1.1f; 00756 if(t->spacetype==SPACE_VIEW3D && t->persp != RV3D_ORTHO) 00757 t->prop_size= MIN2(t->prop_size, ((View3D *)t->view)->far); 00758 calculatePropRatio(t); 00759 } 00760 t->redraw |= TREDRAW_HARD; 00761 break; 00762 case TFM_MODAL_PROPSIZE_DOWN: 00763 if (t->flag & T_PROP_EDIT) { 00764 t->prop_size*= 0.90909090f; 00765 calculatePropRatio(t); 00766 } 00767 t->redraw |= TREDRAW_HARD; 00768 break; 00769 case TFM_MODAL_AUTOIK_LEN_INC: 00770 if (t->flag & T_AUTOIK) 00771 transform_autoik_update(t, 1); 00772 t->redraw |= TREDRAW_HARD; 00773 break; 00774 case TFM_MODAL_AUTOIK_LEN_DEC: 00775 if (t->flag & T_AUTOIK) 00776 transform_autoik_update(t, -1); 00777 t->redraw |= TREDRAW_HARD; 00778 break; 00779 default: 00780 handled = 0; 00781 break; 00782 } 00783 00784 // Modal numinput events 00785 t->redraw |= handleNumInput(&(t->num), event); 00786 } 00787 /* else do non-mapped events */ 00788 else if (event->val==KM_PRESS) { 00789 switch (event->type){ 00790 case RIGHTMOUSE: 00791 t->state = TRANS_CANCEL; 00792 break; 00793 /* enforce redraw of transform when modifiers are used */ 00794 case LEFTSHIFTKEY: 00795 case RIGHTSHIFTKEY: 00796 t->modifiers |= MOD_CONSTRAINT_PLANE; 00797 t->redraw |= TREDRAW_HARD; 00798 break; 00799 00800 case SPACEKEY: 00801 if ((t->spacetype==SPACE_VIEW3D) && event->alt) { 00802 #if 0 // TRANSFORM_FIX_ME 00803 int mval[2]; 00804 00805 getmouseco_sc(mval); 00806 BIF_selectOrientation(); 00807 calc_manipulator_stats(curarea); 00808 copy_m3_m4(t->spacemtx, G.vd->twmat); 00809 warp_pointer(mval[0], mval[1]); 00810 #endif 00811 } 00812 else { 00813 t->state = TRANS_CONFIRM; 00814 } 00815 break; 00816 00817 case MIDDLEMOUSE: 00818 if ((t->flag & T_NO_CONSTRAINT)==0) { 00819 /* exception for switching to dolly, or trackball, in camera view */ 00820 if (t->flag & T_CAMERA) { 00821 if (t->mode==TFM_TRANSLATION) 00822 setLocalConstraint(t, (CON_AXIS2), "along local Z"); 00823 else if (t->mode==TFM_ROTATION) { 00824 restoreTransObjects(t); 00825 initTrackball(t); 00826 } 00827 } 00828 else { 00829 t->modifiers |= MOD_CONSTRAINT_SELECT; 00830 if (t->con.mode & CON_APPLY) { 00831 stopConstraint(t); 00832 } 00833 else { 00834 if (event->shift) { 00835 initSelectConstraint(t, t->spacemtx); 00836 } 00837 else { 00838 /* bit hackish... but it prevents mmb select to print the orientation from menu */ 00839 strcpy(t->spacename, "global"); 00840 initSelectConstraint(t, mati); 00841 } 00842 postSelectConstraint(t); 00843 } 00844 } 00845 t->redraw |= TREDRAW_HARD; 00846 } 00847 break; 00848 case ESCKEY: 00849 t->state = TRANS_CANCEL; 00850 break; 00851 case PADENTER: 00852 case RETKEY: 00853 t->state = TRANS_CONFIRM; 00854 break; 00855 case GKEY: 00856 /* only switch when... */ 00857 if( ELEM3(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL) ) { 00858 resetTransRestrictions(t); 00859 restoreTransObjects(t); 00860 initTranslation(t); 00861 initSnapping(t, NULL); // need to reinit after mode change 00862 t->redraw |= TREDRAW_HARD; 00863 } 00864 break; 00865 case SKEY: 00866 /* only switch when... */ 00867 if( ELEM3(t->mode, TFM_ROTATION, TFM_TRANSLATION, TFM_TRACKBALL) ) { 00868 resetTransRestrictions(t); 00869 restoreTransObjects(t); 00870 initResize(t); 00871 initSnapping(t, NULL); // need to reinit after mode change 00872 t->redraw |= TREDRAW_HARD; 00873 } 00874 break; 00875 case RKEY: 00876 /* only switch when... */ 00877 if(!(t->options & CTX_TEXTURE) && !(t->options & CTX_MOVIECLIP)) { 00878 if( ELEM4(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION) ) { 00879 00880 resetTransRestrictions(t); 00881 00882 if (t->mode == TFM_ROTATION) { 00883 restoreTransObjects(t); 00884 initTrackball(t); 00885 } 00886 else { 00887 restoreTransObjects(t); 00888 initRotation(t); 00889 } 00890 initSnapping(t, NULL); // need to reinit after mode change 00891 t->redraw |= TREDRAW_HARD; 00892 } 00893 } 00894 break; 00895 case CKEY: 00896 if (event->alt) { 00897 t->flag ^= T_PROP_CONNECTED; 00898 sort_trans_data_dist(t); 00899 calculatePropRatio(t); 00900 t->redraw= 1; 00901 } 00902 else { 00903 stopConstraint(t); 00904 t->redraw |= TREDRAW_HARD; 00905 } 00906 break; 00907 case XKEY: 00908 if ((t->flag & T_NO_CONSTRAINT)==0) { 00909 if (t->flag & T_2D_EDIT) { 00910 if (cmode == 'X') { 00911 stopConstraint(t); 00912 } else { 00913 setUserConstraint(t, V3D_MANIP_GLOBAL, (CON_AXIS0), "along X"); 00914 } 00915 } else { 00916 if (cmode == 'X') { 00917 if (t->con.orientation != V3D_MANIP_GLOBAL) { 00918 stopConstraint(t); 00919 } else { 00920 short orientation = t->current_orientation != V3D_MANIP_GLOBAL ? t->current_orientation : V3D_MANIP_LOCAL; 00921 if ((t->modifiers & MOD_CONSTRAINT_PLANE) == 0) 00922 setUserConstraint(t, orientation, (CON_AXIS0), "along %s X"); 00923 else if (t->modifiers & MOD_CONSTRAINT_PLANE) 00924 setUserConstraint(t, orientation, (CON_AXIS1|CON_AXIS2), "locking %s X"); 00925 } 00926 } else { 00927 if ((t->modifiers & MOD_CONSTRAINT_PLANE) == 0) 00928 setUserConstraint(t, V3D_MANIP_GLOBAL, (CON_AXIS0), "along %s X"); 00929 else if (t->modifiers & MOD_CONSTRAINT_PLANE) 00930 setUserConstraint(t, V3D_MANIP_GLOBAL, (CON_AXIS1|CON_AXIS2), "locking %s X"); 00931 } 00932 } 00933 t->redraw |= TREDRAW_HARD; 00934 } 00935 break; 00936 case YKEY: 00937 if ((t->flag & T_NO_CONSTRAINT)==0) { 00938 if (t->flag & T_2D_EDIT) { 00939 if (cmode == 'Y') { 00940 stopConstraint(t); 00941 } else { 00942 setUserConstraint(t, V3D_MANIP_GLOBAL, (CON_AXIS1), "along Y"); 00943 } 00944 } else { 00945 if (cmode == 'Y') { 00946 if (t->con.orientation != V3D_MANIP_GLOBAL) { 00947 stopConstraint(t); 00948 } else { 00949 short orientation = t->current_orientation != V3D_MANIP_GLOBAL ? t->current_orientation : V3D_MANIP_LOCAL; 00950 if ((t->modifiers & MOD_CONSTRAINT_PLANE) == 0) 00951 setUserConstraint(t, orientation, (CON_AXIS1), "along %s Y"); 00952 else if (t->modifiers & MOD_CONSTRAINT_PLANE) 00953 setUserConstraint(t, orientation, (CON_AXIS0|CON_AXIS2), "locking %s Y"); 00954 } 00955 } else { 00956 if ((t->modifiers & MOD_CONSTRAINT_PLANE) == 0) 00957 setUserConstraint(t, V3D_MANIP_GLOBAL, (CON_AXIS1), "along %s Y"); 00958 else if (t->modifiers & MOD_CONSTRAINT_PLANE) 00959 setUserConstraint(t, V3D_MANIP_GLOBAL, (CON_AXIS0|CON_AXIS2), "locking %s Y"); 00960 } 00961 } 00962 t->redraw |= TREDRAW_HARD; 00963 } 00964 break; 00965 case ZKEY: 00966 if ((t->flag & (T_NO_CONSTRAINT|T_2D_EDIT))==0) { 00967 if (cmode == 'Z') { 00968 if (t->con.orientation != V3D_MANIP_GLOBAL) { 00969 stopConstraint(t); 00970 } else { 00971 short orientation = t->current_orientation != V3D_MANIP_GLOBAL ? t->current_orientation : V3D_MANIP_LOCAL; 00972 if ((t->modifiers & MOD_CONSTRAINT_PLANE) == 0) 00973 setUserConstraint(t, orientation, (CON_AXIS2), "along %s Z"); 00974 else if (t->modifiers & MOD_CONSTRAINT_PLANE) 00975 setUserConstraint(t, orientation, (CON_AXIS0|CON_AXIS1), "locking %s Z"); 00976 } 00977 } else { 00978 if ((t->modifiers & MOD_CONSTRAINT_PLANE) == 0) 00979 setUserConstraint(t, V3D_MANIP_GLOBAL, (CON_AXIS2), "along %s Z"); 00980 else if (t->modifiers & MOD_CONSTRAINT_PLANE) 00981 setUserConstraint(t, V3D_MANIP_GLOBAL, (CON_AXIS0|CON_AXIS1), "locking %s Z"); 00982 } 00983 t->redraw |= TREDRAW_HARD; 00984 } 00985 break; 00986 case OKEY: 00987 if (t->flag & T_PROP_EDIT && event->shift) { 00988 t->prop_mode = (t->prop_mode + 1) % PROP_MODE_MAX; 00989 calculatePropRatio(t); 00990 t->redraw |= TREDRAW_HARD; 00991 } 00992 break; 00993 case PADPLUSKEY: 00994 if(event->alt && t->flag & T_PROP_EDIT) { 00995 t->prop_size *= 1.1f; 00996 if(t->spacetype==SPACE_VIEW3D && t->persp != RV3D_ORTHO) 00997 t->prop_size= MIN2(t->prop_size, ((View3D *)t->view)->far); 00998 calculatePropRatio(t); 00999 } 01000 t->redraw= 1; 01001 break; 01002 case PAGEUPKEY: 01003 case WHEELDOWNMOUSE: 01004 if (t->flag & T_AUTOIK) { 01005 transform_autoik_update(t, 1); 01006 } 01007 else view_editmove(event->type); 01008 t->redraw= 1; 01009 break; 01010 case PADMINUS: 01011 if(event->alt && t->flag & T_PROP_EDIT) { 01012 t->prop_size*= 0.90909090f; 01013 calculatePropRatio(t); 01014 } 01015 t->redraw= 1; 01016 break; 01017 case PAGEDOWNKEY: 01018 case WHEELUPMOUSE: 01019 if (t->flag & T_AUTOIK) { 01020 transform_autoik_update(t, -1); 01021 } 01022 else view_editmove(event->type); 01023 t->redraw= 1; 01024 break; 01025 default: 01026 handled = 0; 01027 break; 01028 } 01029 01030 // Numerical input events 01031 t->redraw |= handleNumInput(&(t->num), event); 01032 01033 // Snapping key events 01034 t->redraw |= handleSnapping(t, event); 01035 01036 } 01037 else if (event->val==KM_RELEASE) { 01038 switch (event->type){ 01039 case LEFTSHIFTKEY: 01040 case RIGHTSHIFTKEY: 01041 t->modifiers &= ~MOD_CONSTRAINT_PLANE; 01042 t->redraw |= TREDRAW_HARD; 01043 break; 01044 01045 case MIDDLEMOUSE: 01046 if ((t->flag & T_NO_CONSTRAINT)==0) { 01047 t->modifiers &= ~MOD_CONSTRAINT_SELECT; 01048 postSelectConstraint(t); 01049 t->redraw |= TREDRAW_HARD; 01050 } 01051 break; 01052 // case LEFTMOUSE: 01053 // case RIGHTMOUSE: 01054 // if(WM_modal_tweak_exit(event, t->event_type)) 01056 // t->state = TRANS_CONFIRM; 01057 // break; 01058 default: 01059 handled = 0; 01060 break; 01061 } 01062 01063 /* confirm transform if launch key is released after mouse move */ 01064 if (t->flag & T_RELEASE_CONFIRM) 01065 { 01066 /* XXX Keyrepeat bug in Xorg fucks this up, will test when fixed */ 01067 if (event->type == t->launch_event && (t->launch_event == LEFTMOUSE || t->launch_event == RIGHTMOUSE)) 01068 { 01069 t->state = TRANS_CONFIRM; 01070 } 01071 } 01072 } 01073 01074 // Per transform event, if present 01075 if (t->handleEvent) 01076 t->redraw |= t->handleEvent(t, event); 01077 01078 if (handled || t->redraw) 01079 return 0; 01080 else 01081 return OPERATOR_PASS_THROUGH; 01082 } 01083 01084 int calculateTransformCenter(bContext *C, int centerMode, float *vec) 01085 { 01086 TransInfo *t = MEM_callocN(sizeof(TransInfo), "TransInfo data"); 01087 int success = 1; 01088 01089 t->state = TRANS_RUNNING; 01090 01091 t->options = CTX_NONE; 01092 01093 t->mode = TFM_DUMMY; 01094 01095 initTransInfo(C, t, NULL, NULL); // internal data, mouse, vectors 01096 01097 createTransData(C, t); // make TransData structs from selection 01098 01099 t->around = centerMode; // override userdefined mode 01100 01101 if (t->total == 0) { 01102 success = 0; 01103 } 01104 else { 01105 success = 1; 01106 01107 calculateCenter(t); 01108 01109 // Copy center from constraint center. Transform center can be local 01110 copy_v3_v3(vec, t->con.center); 01111 } 01112 01113 01114 /* aftertrans does insert ipos and action channels, and clears base flags, doesnt read transdata */ 01115 special_aftertrans_update(C, t); 01116 01117 postTrans(C, t); 01118 01119 MEM_freeN(t); 01120 01121 return success; 01122 } 01123 01124 typedef enum { 01125 UP, 01126 DOWN, 01127 LEFT, 01128 RIGHT 01129 } ArrowDirection; 01130 static void drawArrow(ArrowDirection d, short offset, short length, short size) 01131 { 01132 switch(d) 01133 { 01134 case LEFT: 01135 offset = -offset; 01136 length = -length; 01137 size = -size; 01138 case RIGHT: 01139 glBegin(GL_LINES); 01140 glVertex2s( offset, 0); 01141 glVertex2s( offset + length, 0); 01142 glVertex2s( offset + length, 0); 01143 glVertex2s( offset + length - size, -size); 01144 glVertex2s( offset + length, 0); 01145 glVertex2s( offset + length - size, size); 01146 glEnd(); 01147 break; 01148 case DOWN: 01149 offset = -offset; 01150 length = -length; 01151 size = -size; 01152 case UP: 01153 glBegin(GL_LINES); 01154 glVertex2s( 0, offset); 01155 glVertex2s( 0, offset + length); 01156 glVertex2s( 0, offset + length); 01157 glVertex2s(-size, offset + length - size); 01158 glVertex2s( 0, offset + length); 01159 glVertex2s( size, offset + length - size); 01160 glEnd(); 01161 break; 01162 } 01163 } 01164 01165 static void drawArrowHead(ArrowDirection d, short size) 01166 { 01167 switch(d) 01168 { 01169 case LEFT: 01170 size = -size; 01171 case RIGHT: 01172 glBegin(GL_LINES); 01173 glVertex2s( 0, 0); 01174 glVertex2s( -size, -size); 01175 glVertex2s( 0, 0); 01176 glVertex2s( -size, size); 01177 glEnd(); 01178 break; 01179 case DOWN: 01180 size = -size; 01181 case UP: 01182 glBegin(GL_LINES); 01183 glVertex2s( 0, 0); 01184 glVertex2s(-size, -size); 01185 glVertex2s( 0, 0); 01186 glVertex2s( size, -size); 01187 glEnd(); 01188 break; 01189 } 01190 } 01191 01192 static void drawArc(float size, float angle_start, float angle_end, int segments) 01193 { 01194 float delta = (angle_end - angle_start) / segments; 01195 float angle; 01196 01197 glBegin(GL_LINE_STRIP); 01198 01199 for( angle = angle_start; angle < angle_end; angle += delta) 01200 { 01201 glVertex2f( cosf(angle) * size, sinf(angle) * size); 01202 } 01203 glVertex2f( cosf(angle_end) * size, sinf(angle_end) * size); 01204 01205 glEnd(); 01206 } 01207 01208 static int helpline_poll(bContext *C) 01209 { 01210 ARegion *ar= CTX_wm_region(C); 01211 01212 if(ar && ar->regiontype==RGN_TYPE_WINDOW) 01213 return 1; 01214 return 0; 01215 } 01216 01217 static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata) 01218 { 01219 TransInfo *t = (TransInfo*)customdata; 01220 01221 if (t->helpline != HLP_NONE && !(t->flag & T_USES_MANIPULATOR)) 01222 { 01223 float vecrot[3], cent[2]; 01224 int mval[2]; 01225 01226 mval[0]= x; 01227 mval[1]= y; 01228 01229 copy_v3_v3(vecrot, t->center); 01230 if(t->flag & T_EDIT) { 01231 Object *ob= t->obedit; 01232 if(ob) mul_m4_v3(ob->obmat, vecrot); 01233 } 01234 else if(t->flag & T_POSE) { 01235 Object *ob=t->poseobj; 01236 if(ob) mul_m4_v3(ob->obmat, vecrot); 01237 } 01238 01239 projectFloatView(t, vecrot, cent); // no overflow in extreme cases 01240 01241 glPushMatrix(); 01242 01243 switch(t->helpline) 01244 { 01245 case HLP_SPRING: 01246 UI_ThemeColor(TH_WIRE); 01247 01248 setlinestyle(3); 01249 glBegin(GL_LINE_STRIP); 01250 glVertex2iv(t->mval); 01251 glVertex2fv(cent); 01252 glEnd(); 01253 01254 glTranslatef(mval[0], mval[1], 0); 01255 glRotatef(-RAD2DEGF(atan2f(cent[0] - t->mval[0], cent[1] - t->mval[1])), 0, 0, 1); 01256 01257 setlinestyle(0); 01258 glLineWidth(3.0); 01259 drawArrow(UP, 5, 10, 5); 01260 drawArrow(DOWN, 5, 10, 5); 01261 glLineWidth(1.0); 01262 break; 01263 case HLP_HARROW: 01264 UI_ThemeColor(TH_WIRE); 01265 01266 glTranslatef(mval[0], mval[1], 0); 01267 01268 glLineWidth(3.0); 01269 drawArrow(RIGHT, 5, 10, 5); 01270 drawArrow(LEFT, 5, 10, 5); 01271 glLineWidth(1.0); 01272 break; 01273 case HLP_VARROW: 01274 UI_ThemeColor(TH_WIRE); 01275 01276 glTranslatef(mval[0], mval[1], 0); 01277 01278 glLineWidth(3.0); 01279 glBegin(GL_LINES); 01280 drawArrow(UP, 5, 10, 5); 01281 drawArrow(DOWN, 5, 10, 5); 01282 glLineWidth(1.0); 01283 break; 01284 case HLP_ANGLE: 01285 { 01286 float dx = t->mval[0] - cent[0], dy = t->mval[1] - cent[1]; 01287 float angle = atan2f(dy, dx); 01288 float dist = sqrtf(dx*dx + dy*dy); 01289 float delta_angle = MIN2(15.0f / dist, (float)M_PI/4.0f); 01290 float spacing_angle = MIN2(5.0f / dist, (float)M_PI/12.0f); 01291 UI_ThemeColor(TH_WIRE); 01292 01293 setlinestyle(3); 01294 glBegin(GL_LINE_STRIP); 01295 glVertex2iv(t->mval); 01296 glVertex2fv(cent); 01297 glEnd(); 01298 01299 glTranslatef(cent[0] - t->mval[0] + mval[0], cent[1] - t->mval[1] + mval[1], 0); 01300 01301 setlinestyle(0); 01302 glLineWidth(3.0); 01303 drawArc(dist, angle - delta_angle, angle - spacing_angle, 10); 01304 drawArc(dist, angle + spacing_angle, angle + delta_angle, 10); 01305 01306 glPushMatrix(); 01307 01308 glTranslatef(cosf(angle - delta_angle) * dist, sinf(angle - delta_angle) * dist, 0); 01309 glRotatef(RAD2DEGF(angle - delta_angle), 0, 0, 1); 01310 01311 drawArrowHead(DOWN, 5); 01312 01313 glPopMatrix(); 01314 01315 glTranslatef(cosf(angle + delta_angle) * dist, sinf(angle + delta_angle) * dist, 0); 01316 glRotatef(RAD2DEGF(angle + delta_angle), 0, 0, 1); 01317 01318 drawArrowHead(UP, 5); 01319 01320 glLineWidth(1.0); 01321 break; 01322 } 01323 case HLP_TRACKBALL: 01324 { 01325 unsigned char col[3], col2[3]; 01326 UI_GetThemeColor3ubv(TH_GRID, col); 01327 01328 glTranslatef(mval[0], mval[1], 0); 01329 01330 glLineWidth(3.0); 01331 01332 UI_make_axis_color(col, col2, 'X'); 01333 glColor3ubv((GLubyte *)col2); 01334 01335 drawArrow(RIGHT, 5, 10, 5); 01336 drawArrow(LEFT, 5, 10, 5); 01337 01338 UI_make_axis_color(col, col2, 'Y'); 01339 glColor3ubv((GLubyte *)col2); 01340 01341 drawArrow(UP, 5, 10, 5); 01342 drawArrow(DOWN, 5, 10, 5); 01343 glLineWidth(1.0); 01344 break; 01345 } 01346 } 01347 01348 glPopMatrix(); 01349 } 01350 } 01351 01352 static void drawTransformView(const struct bContext *C, struct ARegion *UNUSED(ar), void *arg) 01353 { 01354 TransInfo *t = arg; 01355 01356 drawConstraint(t); 01357 drawPropCircle(C, t); 01358 drawSnapping(C, t); 01359 } 01360 01361 #if 0 01362 static void drawTransformPixel(const struct bContext *UNUSED(C), struct ARegion *UNUSED(ar), void *UNUSED(arg)) 01363 { 01364 // TransInfo *t = arg; 01365 // 01366 // drawHelpline(C, t->mval[0], t->mval[1], t); 01367 } 01368 #endif 01369 01370 void saveTransform(bContext *C, TransInfo *t, wmOperator *op) 01371 { 01372 ToolSettings *ts = CTX_data_tool_settings(C); 01373 int constraint_axis[3] = {0, 0, 0}; 01374 int proportional = 0; 01375 PropertyRNA *prop; 01376 01377 // Save back mode in case we're in the generic operator 01378 if ((prop= RNA_struct_find_property(op->ptr, "mode"))) { 01379 RNA_property_enum_set(op->ptr, prop, t->mode); 01380 } 01381 01382 if ((prop= RNA_struct_find_property(op->ptr, "value"))) { 01383 float *values= (t->flag & T_AUTOVALUES) ? t->auto_values : t->values; 01384 if (RNA_property_array_check(prop)) { 01385 RNA_property_float_set_array(op->ptr, prop, values); 01386 } 01387 else { 01388 RNA_property_float_set(op->ptr, prop, values[0]); 01389 } 01390 } 01391 01392 /* convert flag to enum */ 01393 switch(t->flag & (T_PROP_EDIT|T_PROP_CONNECTED)) 01394 { 01395 case (T_PROP_EDIT|T_PROP_CONNECTED): 01396 proportional = PROP_EDIT_CONNECTED; 01397 break; 01398 case T_PROP_EDIT: 01399 proportional = PROP_EDIT_ON; 01400 break; 01401 default: 01402 proportional = PROP_EDIT_OFF; 01403 } 01404 01405 // If modal, save settings back in scene if not set as operator argument 01406 if (t->flag & T_MODAL) { 01407 01408 /* save settings if not set in operator */ 01409 if ( (prop = RNA_struct_find_property(op->ptr, "proportional")) && !RNA_property_is_set(op->ptr, prop)) 01410 { 01411 if (t->obedit) 01412 ts->proportional = proportional; 01413 else 01414 ts->proportional_objects = (proportional != PROP_EDIT_OFF); 01415 } 01416 01417 if ( (prop = RNA_struct_find_property(op->ptr, "proportional_size")) && !RNA_property_is_set(op->ptr, prop)) 01418 { 01419 ts->proportional_size = t->prop_size; 01420 } 01421 01422 if ( (prop = RNA_struct_find_property(op->ptr, "proportional_edit_falloff")) && !RNA_property_is_set(op->ptr, prop)) 01423 { 01424 ts->prop_mode = t->prop_mode; 01425 } 01426 01427 /* do we check for parameter? */ 01428 if (t->modifiers & MOD_SNAP) { 01429 ts->snap_flag |= SCE_SNAP; 01430 } else { 01431 ts->snap_flag &= ~SCE_SNAP; 01432 } 01433 01434 if (t->spacetype == SPACE_VIEW3D) { 01435 if ( (prop = RNA_struct_find_property(op->ptr, "constraint_orientation")) && !RNA_property_is_set(op->ptr, prop)) 01436 { 01437 View3D *v3d = t->view; 01438 01439 v3d->twmode = t->current_orientation; 01440 } 01441 } 01442 } 01443 01444 if (RNA_struct_find_property(op->ptr, "proportional")) 01445 { 01446 RNA_enum_set(op->ptr, "proportional", proportional); 01447 RNA_enum_set(op->ptr, "proportional_edit_falloff", t->prop_mode); 01448 RNA_float_set(op->ptr, "proportional_size", t->prop_size); 01449 } 01450 01451 if ((prop = RNA_struct_find_property(op->ptr, "axis"))) 01452 { 01453 RNA_property_float_set_array(op->ptr, prop, t->axis); 01454 } 01455 01456 if ((prop = RNA_struct_find_property(op->ptr, "mirror"))) 01457 { 01458 RNA_property_boolean_set(op->ptr, prop, t->flag & T_MIRROR); 01459 } 01460 01461 if ((prop = RNA_struct_find_property(op->ptr, "constraint_axis"))) 01462 { 01463 /* constraint orientation can be global, event if user selects something else 01464 * so use the orientation in the constraint if set 01465 * */ 01466 if (t->con.mode & CON_APPLY) { 01467 RNA_enum_set(op->ptr, "constraint_orientation", t->con.orientation); 01468 } else { 01469 RNA_enum_set(op->ptr, "constraint_orientation", t->current_orientation); 01470 } 01471 01472 if (t->con.mode & CON_APPLY) 01473 { 01474 if (t->con.mode & CON_AXIS0) { 01475 constraint_axis[0] = 1; 01476 } 01477 if (t->con.mode & CON_AXIS1) { 01478 constraint_axis[1] = 1; 01479 } 01480 if (t->con.mode & CON_AXIS2) { 01481 constraint_axis[2] = 1; 01482 } 01483 } 01484 01485 RNA_property_boolean_set_array(op->ptr, prop, constraint_axis); 01486 } 01487 } 01488 01489 /* note: caller needs to free 't' on a 0 return */ 01490 int initTransform(bContext *C, TransInfo *t, wmOperator *op, wmEvent *event, int mode) 01491 { 01492 int options = 0; 01493 PropertyRNA *prop; 01494 01495 t->context = C; 01496 01497 /* added initialize, for external calls to set stuff in TransInfo, like undo string */ 01498 01499 t->state = TRANS_STARTING; 01500 01501 if ( (prop = RNA_struct_find_property(op->ptr, "texture_space")) && RNA_property_is_set(op->ptr, prop)) 01502 { 01503 if(RNA_property_boolean_get(op->ptr, prop)) { 01504 options |= CTX_TEXTURE; 01505 } 01506 } 01507 01508 t->options = options; 01509 01510 t->mode = mode; 01511 01512 t->launch_event = event ? event->type : -1; 01513 01514 if (t->launch_event == EVT_TWEAK_R) 01515 { 01516 t->launch_event = RIGHTMOUSE; 01517 } 01518 else if (t->launch_event == EVT_TWEAK_L) 01519 { 01520 t->launch_event = LEFTMOUSE; 01521 } 01522 01523 // XXX Remove this when wm_operator_call_internal doesn't use window->eventstate (which can have type = 0) 01524 // For manipulator only, so assume LEFTMOUSE 01525 if (t->launch_event == 0) 01526 { 01527 t->launch_event = LEFTMOUSE; 01528 } 01529 01530 if (!initTransInfo(C, t, op, event)) // internal data, mouse, vectors 01531 { 01532 return 0; 01533 } 01534 01535 if(t->spacetype == SPACE_VIEW3D) 01536 { 01537 //calc_manipulator_stats(curarea); 01538 initTransformOrientation(C, t); 01539 01540 t->draw_handle_apply = ED_region_draw_cb_activate(t->ar->type, drawTransformApply, t, REGION_DRAW_PRE_VIEW); 01541 t->draw_handle_view = ED_region_draw_cb_activate(t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW); 01542 //t->draw_handle_pixel = ED_region_draw_cb_activate(t->ar->type, drawTransformPixel, t, REGION_DRAW_POST_PIXEL); 01543 t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), helpline_poll, drawHelpline, t); 01544 } 01545 else if(t->spacetype == SPACE_IMAGE) { 01546 unit_m3(t->spacemtx); 01547 t->draw_handle_view = ED_region_draw_cb_activate(t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW); 01548 //t->draw_handle_pixel = ED_region_draw_cb_activate(t->ar->type, drawTransformPixel, t, REGION_DRAW_POST_PIXEL); 01549 } 01550 else if(t->spacetype == SPACE_CLIP) { 01551 unit_m3(t->spacemtx); 01552 t->draw_handle_view = ED_region_draw_cb_activate(t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW); 01553 t->options |= CTX_MOVIECLIP; 01554 } 01555 else 01556 unit_m3(t->spacemtx); 01557 01558 createTransData(C, t); // make TransData structs from selection 01559 01560 if (t->total == 0) { 01561 postTrans(C, t); 01562 return 0; 01563 } 01564 01565 /* Stupid code to have Ctrl-Click on manipulator work ok */ 01566 if(event) 01567 { 01568 wmKeyMap *keymap = WM_keymap_active(CTX_wm_manager(C), op->type->modalkeymap); 01569 wmKeyMapItem *kmi; 01570 01571 for (kmi = keymap->items.first; kmi; kmi = kmi->next) 01572 { 01573 if (kmi->propvalue == TFM_MODAL_SNAP_INV_ON && kmi->val == KM_PRESS) 01574 { 01575 if ((ELEM(kmi->type, LEFTCTRLKEY, RIGHTCTRLKEY) && event->ctrl) || 01576 (ELEM(kmi->type, LEFTSHIFTKEY, RIGHTSHIFTKEY) && event->shift) || 01577 (ELEM(kmi->type, LEFTALTKEY, RIGHTALTKEY) && event->alt) || 01578 ((kmi->type == OSKEY) && event->oskey) ) 01579 { 01580 t->modifiers |= MOD_SNAP_INVERT; 01581 } 01582 break; 01583 } 01584 } 01585 01586 } 01587 01588 initSnapping(t, op); // Initialize snapping data AFTER mode flags 01589 01590 /* EVIL! posemode code can switch translation to rotate when 1 bone is selected. will be removed (ton) */ 01591 /* EVIL2: we gave as argument also texture space context bit... was cleared */ 01592 /* EVIL3: extend mode for animation editors also switches modes... but is best way to avoid duplicate code */ 01593 mode = t->mode; 01594 01595 calculatePropRatio(t); 01596 calculateCenter(t); 01597 01598 initMouseInput(t, &t->mouse, t->center2d, t->imval); 01599 01600 switch (mode) { 01601 case TFM_TRANSLATION: 01602 initTranslation(t); 01603 break; 01604 case TFM_ROTATION: 01605 initRotation(t); 01606 break; 01607 case TFM_RESIZE: 01608 initResize(t); 01609 break; 01610 case TFM_TOSPHERE: 01611 initToSphere(t); 01612 break; 01613 case TFM_SHEAR: 01614 initShear(t); 01615 break; 01616 case TFM_WARP: 01617 initWarp(t); 01618 break; 01619 case TFM_SHRINKFATTEN: 01620 initShrinkFatten(t); 01621 break; 01622 case TFM_TILT: 01623 initTilt(t); 01624 break; 01625 case TFM_CURVE_SHRINKFATTEN: 01626 initCurveShrinkFatten(t); 01627 break; 01628 case TFM_TRACKBALL: 01629 initTrackball(t); 01630 break; 01631 case TFM_PUSHPULL: 01632 initPushPull(t); 01633 break; 01634 case TFM_CREASE: 01635 initCrease(t); 01636 break; 01637 case TFM_BONESIZE: 01638 { /* used for both B-Bone width (bonesize) as for deform-dist (envelope) */ 01639 bArmature *arm= t->poseobj->data; 01640 if(arm->drawtype==ARM_ENVELOPE) 01641 initBoneEnvelope(t); 01642 else 01643 initBoneSize(t); 01644 } 01645 break; 01646 case TFM_BONE_ENVELOPE: 01647 initBoneEnvelope(t); 01648 break; 01649 case TFM_EDGE_SLIDE: 01650 initEdgeSlide(t); 01651 break; 01652 case TFM_BONE_ROLL: 01653 initBoneRoll(t); 01654 break; 01655 case TFM_TIME_TRANSLATE: 01656 initTimeTranslate(t); 01657 break; 01658 case TFM_TIME_SLIDE: 01659 initTimeSlide(t); 01660 break; 01661 case TFM_TIME_SCALE: 01662 initTimeScale(t); 01663 break; 01664 case TFM_TIME_DUPLICATE: 01665 /* same as TFM_TIME_EXTEND, but we need the mode info for later 01666 * so that duplicate-culling will work properly 01667 */ 01668 if ELEM(t->spacetype, SPACE_IPO, SPACE_NLA) 01669 initTranslation(t); 01670 else 01671 initTimeTranslate(t); 01672 t->mode = mode; 01673 break; 01674 case TFM_TIME_EXTEND: 01675 /* now that transdata has been made, do like for TFM_TIME_TRANSLATE (for most Animation 01676 * Editors because they have only 1D transforms for time values) or TFM_TRANSLATION 01677 * (for Graph/NLA Editors only since they uses 'standard' transforms to get 2D movement) 01678 * depending on which editor this was called from 01679 */ 01680 if ELEM(t->spacetype, SPACE_IPO, SPACE_NLA) 01681 initTranslation(t); 01682 else 01683 initTimeTranslate(t); 01684 break; 01685 case TFM_BAKE_TIME: 01686 initBakeTime(t); 01687 break; 01688 case TFM_MIRROR: 01689 initMirror(t); 01690 break; 01691 case TFM_BEVEL: 01692 initBevel(t); 01693 break; 01694 case TFM_BWEIGHT: 01695 initBevelWeight(t); 01696 break; 01697 case TFM_ALIGN: 01698 initAlign(t); 01699 break; 01700 case TFM_SEQ_SLIDE: 01701 initSeqSlide(t); 01702 break; 01703 } 01704 01705 if(t->state == TRANS_CANCEL) 01706 { 01707 postTrans(C, t); 01708 return 0; 01709 } 01710 01711 01712 /* overwrite initial values if operator supplied a non-null vector */ 01713 if ( (prop = RNA_struct_find_property(op->ptr, "value")) && RNA_property_is_set(op->ptr, prop)) 01714 { 01715 float values[4]= {0}; /* incase value isn't length 4, avoid uninitialized memory */ 01716 01717 if(RNA_property_array_check(prop)) { 01718 RNA_float_get_array(op->ptr, "value", values); 01719 } else { 01720 values[0]= RNA_float_get(op->ptr, "value"); 01721 } 01722 01723 copy_v4_v4(t->values, values); 01724 copy_v4_v4(t->auto_values, values); 01725 t->flag |= T_AUTOVALUES; 01726 } 01727 01728 /* Transformation axis from operator */ 01729 if ((prop = RNA_struct_find_property(op->ptr, "axis")) && RNA_property_is_set(op->ptr, prop)) 01730 { 01731 RNA_property_float_get_array(op->ptr, prop, t->axis); 01732 normalize_v3(t->axis); 01733 copy_v3_v3(t->axis_orig, t->axis); 01734 } 01735 01736 /* Constraint init from operator */ 01737 if ((prop = RNA_struct_find_property(op->ptr, "constraint_axis")) && RNA_property_is_set(op->ptr, prop)) 01738 { 01739 int constraint_axis[3]; 01740 01741 RNA_property_boolean_get_array(op->ptr, prop, constraint_axis); 01742 01743 if (constraint_axis[0] || constraint_axis[1] || constraint_axis[2]) 01744 { 01745 t->con.mode |= CON_APPLY; 01746 01747 if (constraint_axis[0]) { 01748 t->con.mode |= CON_AXIS0; 01749 } 01750 if (constraint_axis[1]) { 01751 t->con.mode |= CON_AXIS1; 01752 } 01753 if (constraint_axis[2]) { 01754 t->con.mode |= CON_AXIS2; 01755 } 01756 01757 setUserConstraint(t, t->current_orientation, t->con.mode, "%s"); 01758 } 01759 } 01760 01761 t->context = NULL; 01762 01763 return 1; 01764 } 01765 01766 void transformApply(bContext *C, TransInfo *t) 01767 { 01768 t->context = C; 01769 01770 if ((t->redraw & TREDRAW_HARD) || (t->draw_handle_apply == NULL && (t->redraw & TREDRAW_SOFT))) 01771 { 01772 selectConstraint(t); 01773 if (t->transform) { 01774 t->transform(t, t->mval); // calls recalcData() 01775 viewRedrawForce(C, t); 01776 } 01777 t->redraw = TREDRAW_NOTHING; 01778 } else if (t->redraw & TREDRAW_SOFT) { 01779 viewRedrawForce(C, t); 01780 } 01781 01782 /* If auto confirm is on, break after one pass */ 01783 if (t->options & CTX_AUTOCONFIRM) 01784 { 01785 t->state = TRANS_CONFIRM; 01786 } 01787 01788 if (BKE_ptcache_get_continue_physics()) 01789 { 01790 // TRANSFORM_FIX_ME 01791 //do_screenhandlers(G.curscreen); 01792 t->redraw |= TREDRAW_HARD; 01793 } 01794 01795 t->context = NULL; 01796 } 01797 01798 static void drawTransformApply(const bContext *C, struct ARegion *UNUSED(ar), void *arg) 01799 { 01800 TransInfo *t = arg; 01801 01802 if (t->redraw & TREDRAW_SOFT) { 01803 t->redraw |= TREDRAW_HARD; 01804 transformApply((bContext *)C, t); 01805 } 01806 } 01807 01808 int transformEnd(bContext *C, TransInfo *t) 01809 { 01810 int exit_code = OPERATOR_RUNNING_MODAL; 01811 01812 t->context = C; 01813 01814 if (t->state != TRANS_STARTING && t->state != TRANS_RUNNING) 01815 { 01816 /* handle restoring objects */ 01817 if(t->state == TRANS_CANCEL) 01818 { 01819 /* exception, edge slide transformed UVs too */ 01820 if(t->mode==TFM_EDGE_SLIDE) 01821 doEdgeSlide(t, 0.0f); 01822 01823 exit_code = OPERATOR_CANCELLED; 01824 restoreTransObjects(t); // calls recalcData() 01825 } 01826 else 01827 { 01828 exit_code = OPERATOR_FINISHED; 01829 } 01830 01831 /* aftertrans does insert keyframes, and clears base flags, doesnt read transdata */ 01832 special_aftertrans_update(C, t); 01833 01834 /* free data */ 01835 postTrans(C, t); 01836 01837 /* send events out for redraws */ 01838 viewRedrawPost(C, t); 01839 01840 /* Undo as last, certainly after special_trans_update! */ 01841 01842 if(t->state == TRANS_CANCEL) { 01843 // if(t->undostr) ED_undo_push(C, t->undostr); 01844 } 01845 else { 01846 // if(t->undostr) ED_undo_push(C, t->undostr); 01847 // else ED_undo_push(C, transform_to_undostr(t)); 01848 } 01849 t->undostr= NULL; 01850 01851 viewRedrawForce(C, t); 01852 } 01853 01854 t->context = NULL; 01855 01856 return exit_code; 01857 } 01858 01859 /* ************************** TRANSFORM LOCKS **************************** */ 01860 01861 static void protectedTransBits(short protectflag, float *vec) 01862 { 01863 if(protectflag & OB_LOCK_LOCX) 01864 vec[0]= 0.0f; 01865 if(protectflag & OB_LOCK_LOCY) 01866 vec[1]= 0.0f; 01867 if(protectflag & OB_LOCK_LOCZ) 01868 vec[2]= 0.0f; 01869 } 01870 01871 static void protectedSizeBits(short protectflag, float *size) 01872 { 01873 if(protectflag & OB_LOCK_SCALEX) 01874 size[0]= 1.0f; 01875 if(protectflag & OB_LOCK_SCALEY) 01876 size[1]= 1.0f; 01877 if(protectflag & OB_LOCK_SCALEZ) 01878 size[2]= 1.0f; 01879 } 01880 01881 static void protectedRotateBits(short protectflag, float *eul, float *oldeul) 01882 { 01883 if(protectflag & OB_LOCK_ROTX) 01884 eul[0]= oldeul[0]; 01885 if(protectflag & OB_LOCK_ROTY) 01886 eul[1]= oldeul[1]; 01887 if(protectflag & OB_LOCK_ROTZ) 01888 eul[2]= oldeul[2]; 01889 } 01890 01891 01892 /* this function only does the delta rotation */ 01893 /* axis-angle is usually internally stored as quats... */ 01894 static void protectedAxisAngleBits(short protectflag, float axis[3], float *angle, float oldAxis[3], float oldAngle) 01895 { 01896 /* check that protection flags are set */ 01897 if ((protectflag & (OB_LOCK_ROTX|OB_LOCK_ROTY|OB_LOCK_ROTZ|OB_LOCK_ROTW)) == 0) 01898 return; 01899 01900 if (protectflag & OB_LOCK_ROT4D) { 01901 /* axis-angle getting limited as 4D entities that they are... */ 01902 if (protectflag & OB_LOCK_ROTW) 01903 *angle= oldAngle; 01904 if (protectflag & OB_LOCK_ROTX) 01905 axis[0]= oldAxis[0]; 01906 if (protectflag & OB_LOCK_ROTY) 01907 axis[1]= oldAxis[1]; 01908 if (protectflag & OB_LOCK_ROTZ) 01909 axis[2]= oldAxis[2]; 01910 } 01911 else { 01912 /* axis-angle get limited with euler... */ 01913 float eul[3], oldeul[3]; 01914 01915 axis_angle_to_eulO( eul, EULER_ORDER_DEFAULT,axis, *angle); 01916 axis_angle_to_eulO( oldeul, EULER_ORDER_DEFAULT,oldAxis, oldAngle); 01917 01918 if (protectflag & OB_LOCK_ROTX) 01919 eul[0]= oldeul[0]; 01920 if (protectflag & OB_LOCK_ROTY) 01921 eul[1]= oldeul[1]; 01922 if (protectflag & OB_LOCK_ROTZ) 01923 eul[2]= oldeul[2]; 01924 01925 eulO_to_axis_angle( axis, angle,eul, EULER_ORDER_DEFAULT); 01926 01927 /* when converting to axis-angle, we need a special exception for the case when there is no axis */ 01928 if (IS_EQF(axis[0], axis[1]) && IS_EQF(axis[1], axis[2])) { 01929 /* for now, rotate around y-axis then (so that it simply becomes the roll) */ 01930 axis[1]= 1.0f; 01931 } 01932 } 01933 } 01934 01935 /* this function only does the delta rotation */ 01936 static void protectedQuaternionBits(short protectflag, float *quat, float *oldquat) 01937 { 01938 /* check that protection flags are set */ 01939 if ((protectflag & (OB_LOCK_ROTX|OB_LOCK_ROTY|OB_LOCK_ROTZ|OB_LOCK_ROTW)) == 0) 01940 return; 01941 01942 if (protectflag & OB_LOCK_ROT4D) { 01943 /* quaternions getting limited as 4D entities that they are... */ 01944 if (protectflag & OB_LOCK_ROTW) 01945 quat[0]= oldquat[0]; 01946 if (protectflag & OB_LOCK_ROTX) 01947 quat[1]= oldquat[1]; 01948 if (protectflag & OB_LOCK_ROTY) 01949 quat[2]= oldquat[2]; 01950 if (protectflag & OB_LOCK_ROTZ) 01951 quat[3]= oldquat[3]; 01952 } 01953 else { 01954 /* quaternions get limited with euler... (compatibility mode) */ 01955 float eul[3], oldeul[3], nquat[4], noldquat[4]; 01956 float qlen; 01957 01958 qlen= normalize_qt_qt(nquat, quat); 01959 normalize_qt_qt(noldquat, oldquat); 01960 01961 quat_to_eul(eul, nquat); 01962 quat_to_eul(oldeul, noldquat); 01963 01964 if (protectflag & OB_LOCK_ROTX) 01965 eul[0]= oldeul[0]; 01966 if (protectflag & OB_LOCK_ROTY) 01967 eul[1]= oldeul[1]; 01968 if (protectflag & OB_LOCK_ROTZ) 01969 eul[2]= oldeul[2]; 01970 01971 eul_to_quat( quat,eul); 01972 01973 /* restore original quat size */ 01974 mul_qt_fl(quat, qlen); 01975 01976 /* quaternions flip w sign to accumulate rotations correctly */ 01977 if ( (nquat[0]<0.0f && quat[0]>0.0f) || (nquat[0]>0.0f && quat[0]<0.0f) ) { 01978 mul_qt_fl(quat, -1.0f); 01979 } 01980 } 01981 } 01982 01983 /* ******************* TRANSFORM LIMITS ********************** */ 01984 01985 static void constraintTransLim(TransInfo *t, TransData *td) 01986 { 01987 if (td->con) { 01988 bConstraintTypeInfo *ctiLoc= get_constraint_typeinfo(CONSTRAINT_TYPE_LOCLIMIT); 01989 bConstraintTypeInfo *ctiDist= get_constraint_typeinfo(CONSTRAINT_TYPE_DISTLIMIT); 01990 01991 bConstraintOb cob= {NULL}; 01992 bConstraint *con; 01993 float ctime = (float)(t->scene->r.cfra); 01994 01995 /* Make a temporary bConstraintOb for using these limit constraints 01996 * - they only care that cob->matrix is correctly set ;-) 01997 * - current space should be local 01998 */ 01999 unit_m4(cob.matrix); 02000 copy_v3_v3(cob.matrix[3], td->loc); 02001 02002 /* Evaluate valid constraints */ 02003 for (con= td->con; con; con= con->next) { 02004 bConstraintTypeInfo *cti = NULL; 02005 ListBase targets = {NULL, NULL}; 02006 float tmat[4][4]; 02007 02008 /* only consider constraint if enabled */ 02009 if (con->flag & CONSTRAINT_DISABLE) continue; 02010 if (con->enforce == 0.0f) continue; 02011 02012 /* only use it if it's tagged for this purpose (and the right type) */ 02013 if (con->type == CONSTRAINT_TYPE_LOCLIMIT) { 02014 bLocLimitConstraint *data= con->data; 02015 02016 if ((data->flag2 & LIMIT_TRANSFORM)==0) 02017 continue; 02018 cti = ctiLoc; 02019 } 02020 else if (con->type == CONSTRAINT_TYPE_DISTLIMIT) { 02021 bDistLimitConstraint *data= con->data; 02022 02023 if ((data->flag & LIMITDIST_TRANSFORM)==0) 02024 continue; 02025 cti = ctiDist; 02026 } 02027 02028 if (cti) { 02029 /* do space conversions */ 02030 if (con->ownspace == CONSTRAINT_SPACE_WORLD) { 02031 /* just multiply by td->mtx (this should be ok) */ 02032 copy_m4_m4(tmat, cob.matrix); 02033 mul_m4_m3m4(cob.matrix, td->mtx, tmat); 02034 } 02035 else if (con->ownspace != CONSTRAINT_SPACE_LOCAL) { 02036 /* skip... incompatable spacetype */ 02037 continue; 02038 } 02039 02040 /* get constraint targets if needed */ 02041 get_constraint_targets_for_solving(con, &cob, &targets, ctime); 02042 02043 /* do constraint */ 02044 cti->evaluate_constraint(con, &cob, &targets); 02045 02046 /* convert spaces again */ 02047 if (con->ownspace == CONSTRAINT_SPACE_WORLD) { 02048 /* just multiply by td->mtx (this should be ok) */ 02049 copy_m4_m4(tmat, cob.matrix); 02050 mul_m4_m3m4(cob.matrix, td->smtx, tmat); 02051 } 02052 02053 /* free targets list */ 02054 BLI_freelistN(&targets); 02055 } 02056 } 02057 02058 /* copy results from cob->matrix */ 02059 copy_v3_v3(td->loc, cob.matrix[3]); 02060 } 02061 } 02062 02063 static void constraintob_from_transdata(bConstraintOb *cob, TransData *td) 02064 { 02065 /* Make a temporary bConstraintOb for use by limit constraints 02066 * - they only care that cob->matrix is correctly set ;-) 02067 * - current space should be local 02068 */ 02069 memset(cob, 0, sizeof(bConstraintOb)); 02070 if (td->ext) 02071 { 02072 if (td->ext->rotOrder == ROT_MODE_QUAT) { 02073 /* quats */ 02074 /* objects and bones do normalization first too, otherwise 02075 we don't necessarily end up with a rotation matrix, and 02076 then conversion back to quat gives a different result */ 02077 float quat[4]; 02078 normalize_qt_qt(quat, td->ext->quat); 02079 quat_to_mat4(cob->matrix, quat); 02080 } 02081 else if (td->ext->rotOrder == ROT_MODE_AXISANGLE) { 02082 /* axis angle */ 02083 axis_angle_to_mat4(cob->matrix, &td->ext->quat[1], td->ext->quat[0]); 02084 } 02085 else { 02086 /* eulers */ 02087 eulO_to_mat4(cob->matrix, td->ext->rot, td->ext->rotOrder); 02088 } 02089 } 02090 } 02091 02092 static void constraintRotLim(TransInfo *UNUSED(t), TransData *td) 02093 { 02094 if (td->con) { 02095 bConstraintTypeInfo *cti= get_constraint_typeinfo(CONSTRAINT_TYPE_ROTLIMIT); 02096 bConstraintOb cob; 02097 bConstraint *con; 02098 int dolimit = 0; 02099 02100 /* Evaluate valid constraints */ 02101 for (con= td->con; con; con= con->next) { 02102 /* only consider constraint if enabled */ 02103 if (con->flag & CONSTRAINT_DISABLE) continue; 02104 if (con->enforce == 0.0f) continue; 02105 02106 /* we're only interested in Limit-Rotation constraints */ 02107 if (con->type == CONSTRAINT_TYPE_ROTLIMIT) { 02108 bRotLimitConstraint *data= con->data; 02109 float tmat[4][4]; 02110 02111 /* only use it if it's tagged for this purpose */ 02112 if ((data->flag2 & LIMIT_TRANSFORM)==0) 02113 continue; 02114 02115 /* skip incompatable spacetypes */ 02116 if (!ELEM(con->ownspace, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL)) 02117 continue; 02118 02119 /* only do conversion if necessary, to preserve quats and eulers */ 02120 if(!dolimit) { 02121 constraintob_from_transdata(&cob, td); 02122 dolimit= 1; 02123 } 02124 02125 /* do space conversions */ 02126 if (con->ownspace == CONSTRAINT_SPACE_WORLD) { 02127 /* just multiply by td->mtx (this should be ok) */ 02128 copy_m4_m4(tmat, cob.matrix); 02129 mul_m4_m3m4(cob.matrix, td->mtx, tmat); 02130 } 02131 02132 /* do constraint */ 02133 cti->evaluate_constraint(con, &cob, NULL); 02134 02135 /* convert spaces again */ 02136 if (con->ownspace == CONSTRAINT_SPACE_WORLD) { 02137 /* just multiply by td->mtx (this should be ok) */ 02138 copy_m4_m4(tmat, cob.matrix); 02139 mul_m4_m3m4(cob.matrix, td->smtx, tmat); 02140 } 02141 } 02142 } 02143 02144 if(dolimit) { 02145 /* copy results from cob->matrix */ 02146 if (td->ext->rotOrder == ROT_MODE_QUAT) { 02147 /* quats */ 02148 mat4_to_quat( td->ext->quat,cob.matrix); 02149 } 02150 else if (td->ext->rotOrder == ROT_MODE_AXISANGLE) { 02151 /* axis angle */ 02152 mat4_to_axis_angle( &td->ext->quat[1], &td->ext->quat[0],cob.matrix); 02153 } 02154 else { 02155 /* eulers */ 02156 mat4_to_eulO( td->ext->rot, td->ext->rotOrder,cob.matrix); 02157 } 02158 } 02159 } 02160 } 02161 02162 static void constraintSizeLim(TransInfo *t, TransData *td) 02163 { 02164 if (td->con && td->ext) { 02165 bConstraintTypeInfo *cti= get_constraint_typeinfo(CONSTRAINT_TYPE_SIZELIMIT); 02166 bConstraintOb cob= {NULL}; 02167 bConstraint *con; 02168 02169 /* Make a temporary bConstraintOb for using these limit constraints 02170 * - they only care that cob->matrix is correctly set ;-) 02171 * - current space should be local 02172 */ 02173 if ((td->flag & TD_SINGLESIZE) && !(t->con.mode & CON_APPLY)) { 02174 /* scale val and reset size */ 02175 return; // TODO: fix this case 02176 } 02177 else { 02178 /* Reset val if SINGLESIZE but using a constraint */ 02179 if (td->flag & TD_SINGLESIZE) 02180 return; 02181 02182 size_to_mat4( cob.matrix,td->ext->size); 02183 } 02184 02185 /* Evaluate valid constraints */ 02186 for (con= td->con; con; con= con->next) { 02187 /* only consider constraint if enabled */ 02188 if (con->flag & CONSTRAINT_DISABLE) continue; 02189 if (con->enforce == 0.0f) continue; 02190 02191 /* we're only interested in Limit-Scale constraints */ 02192 if (con->type == CONSTRAINT_TYPE_SIZELIMIT) { 02193 bSizeLimitConstraint *data= con->data; 02194 float tmat[4][4]; 02195 02196 /* only use it if it's tagged for this purpose */ 02197 if ((data->flag2 & LIMIT_TRANSFORM)==0) 02198 continue; 02199 02200 /* do space conversions */ 02201 if (con->ownspace == CONSTRAINT_SPACE_WORLD) { 02202 /* just multiply by td->mtx (this should be ok) */ 02203 copy_m4_m4(tmat, cob.matrix); 02204 mul_m4_m3m4(cob.matrix, td->mtx, tmat); 02205 } 02206 else if (con->ownspace != CONSTRAINT_SPACE_LOCAL) { 02207 /* skip... incompatable spacetype */ 02208 continue; 02209 } 02210 02211 /* do constraint */ 02212 cti->evaluate_constraint(con, &cob, NULL); 02213 02214 /* convert spaces again */ 02215 if (con->ownspace == CONSTRAINT_SPACE_WORLD) { 02216 /* just multiply by td->mtx (this should be ok) */ 02217 copy_m4_m4(tmat, cob.matrix); 02218 mul_m4_m3m4(cob.matrix, td->smtx, tmat); 02219 } 02220 } 02221 } 02222 02223 /* copy results from cob->matrix */ 02224 if ((td->flag & TD_SINGLESIZE) && !(t->con.mode & CON_APPLY)) { 02225 /* scale val and reset size */ 02226 return; // TODO: fix this case 02227 } 02228 else { 02229 /* Reset val if SINGLESIZE but using a constraint */ 02230 if (td->flag & TD_SINGLESIZE) 02231 return; 02232 02233 mat4_to_size( td->ext->size,cob.matrix); 02234 } 02235 } 02236 } 02237 02238 /* ************************** WARP *************************** */ 02239 02240 static void postInputWarp(TransInfo *t, float values[3]) 02241 { 02242 mul_v3_fl(values, (float)(M_PI * 2)); 02243 02244 if (t->customData) /* non-null value indicates reversed input */ 02245 { 02246 negate_v3(values); 02247 } 02248 } 02249 02250 void initWarp(TransInfo *t) 02251 { 02252 float max[3], min[3]; 02253 int i; 02254 02255 t->mode = TFM_WARP; 02256 t->transform = Warp; 02257 t->handleEvent = handleEventWarp; 02258 02259 setInputPostFct(&t->mouse, postInputWarp); 02260 initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_RATIO); 02261 02262 t->idx_max = 0; 02263 t->num.idx_max = 0; 02264 t->snap[0] = 0.0f; 02265 t->snap[1] = 5.0f / 180.0f * (float)M_PI; 02266 t->snap[2] = 1.0f / 180.0f * (float)M_PI; 02267 02268 t->num.increment = 1.0f; 02269 02270 t->flag |= T_NO_CONSTRAINT; 02271 02272 /* we need min/max in view space */ 02273 for(i = 0; i < t->total; i++) { 02274 float center[3]; 02275 copy_v3_v3(center, t->data[i].center); 02276 mul_m3_v3(t->data[i].mtx, center); 02277 mul_m4_v3(t->viewmat, center); 02278 sub_v3_v3(center, t->viewmat[3]); 02279 if (i) 02280 minmax_v3v3_v3(min, max, center); 02281 else { 02282 copy_v3_v3(max, center); 02283 copy_v3_v3(min, center); 02284 } 02285 } 02286 02287 mid_v3_v3v3(t->center, min, max); 02288 02289 if (max[0] == min[0]) max[0] += 0.1f; /* not optimal, but flipping is better than invalid garbage (i.e. division by zero!) */ 02290 t->val= (max[0]-min[0])/2.0f; /* t->val is X dimension projected boundbox */ 02291 } 02292 02293 int handleEventWarp(TransInfo *t, wmEvent *event) 02294 { 02295 int status = 0; 02296 02297 if (event->type == MIDDLEMOUSE && event->val==KM_PRESS) 02298 { 02299 // Use customData pointer to signal warp direction 02300 if (t->customData == NULL) 02301 t->customData = (void*)1; 02302 else 02303 t->customData = NULL; 02304 02305 status = 1; 02306 } 02307 02308 return status; 02309 } 02310 02311 int Warp(TransInfo *t, const int UNUSED(mval[2])) 02312 { 02313 TransData *td = t->data; 02314 float vec[3], circumfac, dist, phi0, co, si, *curs, cursor[3], gcursor[3]; 02315 int i; 02316 char str[50]; 02317 02318 curs= give_cursor(t->scene, t->view); 02319 /* 02320 * gcursor is the one used for helpline. 02321 * It has to be in the same space as the drawing loop 02322 * (that means it needs to be in the object's space when in edit mode and 02323 * in global space in object mode) 02324 * 02325 * cursor is used for calculations. 02326 * It needs to be in view space, but we need to take object's offset 02327 * into account if in Edit mode. 02328 */ 02329 copy_v3_v3(cursor, curs); 02330 copy_v3_v3(gcursor, cursor); 02331 if (t->flag & T_EDIT) { 02332 sub_v3_v3(cursor, t->obedit->obmat[3]); 02333 sub_v3_v3(gcursor, t->obedit->obmat[3]); 02334 mul_m3_v3(t->data->smtx, gcursor); 02335 } 02336 mul_m4_v3(t->viewmat, cursor); 02337 sub_v3_v3(cursor, t->viewmat[3]); 02338 02339 /* amount of radians for warp */ 02340 circumfac = t->values[0]; 02341 02342 snapGrid(t, &circumfac); 02343 applyNumInput(&t->num, &circumfac); 02344 02345 /* header print for NumInput */ 02346 if (hasNumInput(&t->num)) { 02347 char c[20]; 02348 02349 outputNumInput(&(t->num), c); 02350 02351 sprintf(str, "Warp: %s", c); 02352 02353 circumfac = DEG2RADF(circumfac); 02354 } 02355 else { 02356 /* default header print */ 02357 sprintf(str, "Warp: %.3f", RAD2DEGF(circumfac)); 02358 } 02359 02360 t->values[0] = circumfac; 02361 02362 circumfac /= 2; /* only need 180 on each side to make 360 */ 02363 02364 for(i = 0; i < t->total; i++, td++) { 02365 float loc[3]; 02366 if (td->flag & TD_NOACTION) 02367 break; 02368 02369 if (td->flag & TD_SKIP) 02370 continue; 02371 02372 /* translate point to center, rotate in such a way that outline==distance */ 02373 copy_v3_v3(vec, td->iloc); 02374 mul_m3_v3(td->mtx, vec); 02375 mul_m4_v3(t->viewmat, vec); 02376 sub_v3_v3(vec, t->viewmat[3]); 02377 02378 dist= vec[0]-cursor[0]; 02379 02380 /* t->val is X dimension projected boundbox */ 02381 phi0= (circumfac*dist/t->val); 02382 02383 vec[1]= (vec[1]-cursor[1]); 02384 02385 co= (float)cos(phi0); 02386 si= (float)sin(phi0); 02387 loc[0]= -si*vec[1]+cursor[0]; 02388 loc[1]= co*vec[1]+cursor[1]; 02389 loc[2]= vec[2]; 02390 02391 mul_m4_v3(t->viewinv, loc); 02392 sub_v3_v3(loc, t->viewinv[3]); 02393 mul_m3_v3(td->smtx, loc); 02394 02395 sub_v3_v3(loc, td->iloc); 02396 mul_v3_fl(loc, td->factor); 02397 add_v3_v3v3(td->loc, td->iloc, loc); 02398 } 02399 02400 recalcData(t); 02401 02402 ED_area_headerprint(t->sa, str); 02403 02404 return 1; 02405 } 02406 02407 /* ************************** SHEAR *************************** */ 02408 02409 static void postInputShear(TransInfo *UNUSED(t), float values[3]) 02410 { 02411 mul_v3_fl(values, 0.05f); 02412 } 02413 02414 void initShear(TransInfo *t) 02415 { 02416 t->mode = TFM_SHEAR; 02417 t->transform = Shear; 02418 t->handleEvent = handleEventShear; 02419 02420 setInputPostFct(&t->mouse, postInputShear); 02421 initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_ABSOLUTE); 02422 02423 t->idx_max = 0; 02424 t->num.idx_max = 0; 02425 t->snap[0] = 0.0f; 02426 t->snap[1] = 0.1f; 02427 t->snap[2] = t->snap[1] * 0.1f; 02428 02429 t->num.increment = 0.1f; 02430 02431 t->flag |= T_NO_CONSTRAINT; 02432 } 02433 02434 int handleEventShear(TransInfo *t, wmEvent *event) 02435 { 02436 int status = 0; 02437 02438 if (event->type == MIDDLEMOUSE && event->val==KM_PRESS) 02439 { 02440 // Use customData pointer to signal Shear direction 02441 if (t->customData == NULL) 02442 { 02443 initMouseInputMode(t, &t->mouse, INPUT_VERTICAL_ABSOLUTE); 02444 t->customData = (void*)1; 02445 } 02446 else 02447 { 02448 initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_ABSOLUTE); 02449 t->customData = NULL; 02450 } 02451 02452 status = 1; 02453 } 02454 02455 return status; 02456 } 02457 02458 02459 int Shear(TransInfo *t, const int UNUSED(mval[2])) 02460 { 02461 TransData *td = t->data; 02462 float vec[3]; 02463 float smat[3][3], tmat[3][3], totmat[3][3], persmat[3][3], persinv[3][3]; 02464 float value; 02465 int i; 02466 char str[50]; 02467 02468 copy_m3_m4(persmat, t->viewmat); 02469 invert_m3_m3(persinv, persmat); 02470 02471 value = t->values[0]; 02472 02473 snapGrid(t, &value); 02474 02475 applyNumInput(&t->num, &value); 02476 02477 /* header print for NumInput */ 02478 if (hasNumInput(&t->num)) { 02479 char c[20]; 02480 02481 outputNumInput(&(t->num), c); 02482 02483 sprintf(str, "Shear: %s %s", c, t->proptext); 02484 } 02485 else { 02486 /* default header print */ 02487 sprintf(str, "Shear: %.3f %s", value, t->proptext); 02488 } 02489 02490 unit_m3(smat); 02491 02492 // Custom data signals shear direction 02493 if (t->customData == NULL) 02494 smat[1][0] = value; 02495 else 02496 smat[0][1] = value; 02497 02498 mul_m3_m3m3(tmat, smat, persmat); 02499 mul_m3_m3m3(totmat, persinv, tmat); 02500 02501 for(i = 0 ; i < t->total; i++, td++) { 02502 if (td->flag & TD_NOACTION) 02503 break; 02504 02505 if (td->flag & TD_SKIP) 02506 continue; 02507 02508 if (t->obedit) { 02509 float mat3[3][3]; 02510 mul_m3_m3m3(mat3, totmat, td->mtx); 02511 mul_m3_m3m3(tmat, td->smtx, mat3); 02512 } 02513 else { 02514 copy_m3_m3(tmat, totmat); 02515 } 02516 sub_v3_v3v3(vec, td->center, t->center); 02517 02518 mul_m3_v3(tmat, vec); 02519 02520 add_v3_v3(vec, t->center); 02521 sub_v3_v3(vec, td->center); 02522 02523 mul_v3_fl(vec, td->factor); 02524 02525 add_v3_v3v3(td->loc, td->iloc, vec); 02526 } 02527 02528 recalcData(t); 02529 02530 ED_area_headerprint(t->sa, str); 02531 02532 return 1; 02533 } 02534 02535 /* ************************** RESIZE *************************** */ 02536 02537 void initResize(TransInfo *t) 02538 { 02539 t->mode = TFM_RESIZE; 02540 t->transform = Resize; 02541 02542 initMouseInputMode(t, &t->mouse, INPUT_SPRING_FLIP); 02543 02544 t->flag |= T_NULL_ONE; 02545 t->num.flag |= NUM_NULL_ONE; 02546 t->num.flag |= NUM_AFFECT_ALL; 02547 if (!t->obedit) { 02548 t->flag |= T_NO_ZERO; 02549 t->num.flag |= NUM_NO_ZERO; 02550 } 02551 02552 t->idx_max = 2; 02553 t->num.idx_max = 2; 02554 t->snap[0] = 0.0f; 02555 t->snap[1] = 0.1f; 02556 t->snap[2] = t->snap[1] * 0.1f; 02557 02558 t->num.increment = t->snap[1]; 02559 } 02560 02561 static void headerResize(TransInfo *t, float vec[3], char *str) 02562 { 02563 char tvec[60]; 02564 char *spos= str; 02565 if (hasNumInput(&t->num)) { 02566 outputNumInput(&(t->num), tvec); 02567 } 02568 else { 02569 BLI_snprintf(&tvec[0], 20, "%.4f", vec[0]); 02570 BLI_snprintf(&tvec[20], 20, "%.4f", vec[1]); 02571 BLI_snprintf(&tvec[40], 20, "%.4f", vec[2]); 02572 } 02573 02574 if (t->con.mode & CON_APPLY) { 02575 switch(t->num.idx_max) { 02576 case 0: 02577 spos += sprintf(spos, "Scale: %s%s %s", &tvec[0], t->con.text, t->proptext); 02578 break; 02579 case 1: 02580 spos += sprintf(spos, "Scale: %s : %s%s %s", &tvec[0], &tvec[20], t->con.text, t->proptext); 02581 break; 02582 case 2: 02583 spos += sprintf(spos, "Scale: %s : %s : %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext); 02584 } 02585 } 02586 else { 02587 if (t->flag & T_2D_EDIT) 02588 spos += sprintf(spos, "Scale X: %s Y: %s%s %s", &tvec[0], &tvec[20], t->con.text, t->proptext); 02589 else 02590 spos += sprintf(spos, "Scale X: %s Y: %s Z: %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext); 02591 } 02592 02593 if (t->flag & (T_PROP_EDIT|T_PROP_CONNECTED)) { 02594 spos += sprintf(spos, " Proportional size: %.2f", t->prop_size); 02595 } 02596 02597 (void)spos; 02598 } 02599 02600 #define SIGN(a) (a<-FLT_EPSILON?1:a>FLT_EPSILON?2:3) 02601 #define VECSIGNFLIP(a, b) ((SIGN(a[0]) & SIGN(b[0]))==0 || (SIGN(a[1]) & SIGN(b[1]))==0 || (SIGN(a[2]) & SIGN(b[2]))==0) 02602 02603 /* smat is reference matrix, only scaled */ 02604 static void TransMat3ToSize( float mat[][3], float smat[][3], float *size) 02605 { 02606 float vec[3]; 02607 02608 copy_v3_v3(vec, mat[0]); 02609 size[0]= normalize_v3(vec); 02610 copy_v3_v3(vec, mat[1]); 02611 size[1]= normalize_v3(vec); 02612 copy_v3_v3(vec, mat[2]); 02613 size[2]= normalize_v3(vec); 02614 02615 /* first tried with dotproduct... but the sign flip is crucial */ 02616 if( VECSIGNFLIP(mat[0], smat[0]) ) size[0]= -size[0]; 02617 if( VECSIGNFLIP(mat[1], smat[1]) ) size[1]= -size[1]; 02618 if( VECSIGNFLIP(mat[2], smat[2]) ) size[2]= -size[2]; 02619 } 02620 02621 02622 static void ElementResize(TransInfo *t, TransData *td, float mat[3][3]) 02623 { 02624 float tmat[3][3], smat[3][3], center[3]; 02625 float vec[3]; 02626 02627 if (t->flag & T_EDIT) { 02628 mul_m3_m3m3(smat, mat, td->mtx); 02629 mul_m3_m3m3(tmat, td->smtx, smat); 02630 } 02631 else { 02632 copy_m3_m3(tmat, mat); 02633 } 02634 02635 if (t->con.applySize) { 02636 t->con.applySize(t, td, tmat); 02637 } 02638 02639 /* local constraint shouldn't alter center */ 02640 if ((t->around == V3D_LOCAL) && 02641 ( (t->flag & (T_OBJECT|T_POSE)) || 02642 ((t->flag & T_EDIT) && (t->settings->selectmode & (SCE_SELECT_EDGE|SCE_SELECT_FACE))) || 02643 (t->obedit && t->obedit->type == OB_ARMATURE)) 02644 ) 02645 { 02646 copy_v3_v3(center, td->center); 02647 } 02648 else { 02649 copy_v3_v3(center, t->center); 02650 } 02651 02652 if (td->ext) { 02653 float fsize[3]; 02654 02655 if (t->flag & (T_OBJECT|T_TEXTURE|T_POSE)) { 02656 float obsizemat[3][3]; 02657 // Reorient the size mat to fit the oriented object. 02658 mul_m3_m3m3(obsizemat, tmat, td->axismtx); 02659 //print_m3("obsizemat", obsizemat); 02660 TransMat3ToSize(obsizemat, td->axismtx, fsize); 02661 //print_v3("fsize", fsize); 02662 } 02663 else { 02664 mat3_to_size( fsize,tmat); 02665 } 02666 02667 protectedSizeBits(td->protectflag, fsize); 02668 02669 if ((t->flag & T_V3D_ALIGN)==0) { // align mode doesn't resize objects itself 02670 if((td->flag & TD_SINGLESIZE) && !(t->con.mode & CON_APPLY)){ 02671 /* scale val and reset size */ 02672 *td->val = td->ival * (1 + (fsize[0] - 1) * td->factor); 02673 02674 td->ext->size[0] = td->ext->isize[0]; 02675 td->ext->size[1] = td->ext->isize[1]; 02676 td->ext->size[2] = td->ext->isize[2]; 02677 } 02678 else { 02679 /* Reset val if SINGLESIZE but using a constraint */ 02680 if (td->flag & TD_SINGLESIZE) 02681 *td->val = td->ival; 02682 02683 td->ext->size[0] = td->ext->isize[0] * (1 + (fsize[0] - 1) * td->factor); 02684 td->ext->size[1] = td->ext->isize[1] * (1 + (fsize[1] - 1) * td->factor); 02685 td->ext->size[2] = td->ext->isize[2] * (1 + (fsize[2] - 1) * td->factor); 02686 } 02687 } 02688 02689 constraintSizeLim(t, td); 02690 } 02691 02692 /* For individual element center, Editmode need to use iloc */ 02693 if (t->flag & T_POINTS) 02694 sub_v3_v3v3(vec, td->iloc, center); 02695 else 02696 sub_v3_v3v3(vec, td->center, center); 02697 02698 mul_m3_v3(tmat, vec); 02699 02700 add_v3_v3(vec, center); 02701 if (t->flag & T_POINTS) 02702 sub_v3_v3(vec, td->iloc); 02703 else 02704 sub_v3_v3(vec, td->center); 02705 02706 mul_v3_fl(vec, td->factor); 02707 02708 if (t->flag & (T_OBJECT|T_POSE)) { 02709 mul_m3_v3(td->smtx, vec); 02710 } 02711 02712 protectedTransBits(td->protectflag, vec); 02713 add_v3_v3v3(td->loc, td->iloc, vec); 02714 02715 constraintTransLim(t, td); 02716 } 02717 02718 int Resize(TransInfo *t, const int mval[2]) 02719 { 02720 TransData *td; 02721 float size[3], mat[3][3]; 02722 float ratio; 02723 int i; 02724 char str[200]; 02725 02726 /* for manipulator, center handle, the scaling can't be done relative to center */ 02727 if( (t->flag & T_USES_MANIPULATOR) && t->con.mode==0) 02728 { 02729 ratio = 1.0f - ((t->imval[0] - mval[0]) + (t->imval[1] - mval[1]))/100.0f; 02730 } 02731 else 02732 { 02733 ratio = t->values[0]; 02734 } 02735 02736 size[0] = size[1] = size[2] = ratio; 02737 02738 snapGrid(t, size); 02739 02740 if (hasNumInput(&t->num)) { 02741 applyNumInput(&t->num, size); 02742 constraintNumInput(t, size); 02743 } 02744 02745 applySnapping(t, size); 02746 02747 if (t->flag & T_AUTOVALUES) 02748 { 02749 copy_v3_v3(size, t->auto_values); 02750 } 02751 02752 copy_v3_v3(t->values, size); 02753 02754 size_to_mat3( mat,size); 02755 02756 if (t->con.applySize) { 02757 t->con.applySize(t, NULL, mat); 02758 } 02759 02760 copy_m3_m3(t->mat, mat); // used in manipulator 02761 02762 headerResize(t, size, str); 02763 02764 for(i = 0, td=t->data; i < t->total; i++, td++) { 02765 if (td->flag & TD_NOACTION) 02766 break; 02767 02768 if (td->flag & TD_SKIP) 02769 continue; 02770 02771 ElementResize(t, td, mat); 02772 } 02773 02774 /* evil hack - redo resize if cliping needed */ 02775 if (t->flag & T_CLIP_UV && clipUVTransform(t, size, 1)) { 02776 size_to_mat3( mat,size); 02777 02778 if (t->con.applySize) 02779 t->con.applySize(t, NULL, mat); 02780 02781 for(i = 0, td=t->data; i < t->total; i++, td++) 02782 ElementResize(t, td, mat); 02783 } 02784 02785 recalcData(t); 02786 02787 ED_area_headerprint(t->sa, str); 02788 02789 return 1; 02790 } 02791 02792 /* ************************** TOSPHERE *************************** */ 02793 02794 void initToSphere(TransInfo *t) 02795 { 02796 TransData *td = t->data; 02797 int i; 02798 02799 t->mode = TFM_TOSPHERE; 02800 t->transform = ToSphere; 02801 02802 initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_RATIO); 02803 02804 t->idx_max = 0; 02805 t->num.idx_max = 0; 02806 t->snap[0] = 0.0f; 02807 t->snap[1] = 0.1f; 02808 t->snap[2] = t->snap[1] * 0.1f; 02809 02810 t->num.increment = t->snap[1]; 02811 02812 t->num.flag |= NUM_NULL_ONE | NUM_NO_NEGATIVE; 02813 t->flag |= T_NO_CONSTRAINT; 02814 02815 // Calculate average radius 02816 for(i = 0 ; i < t->total; i++, td++) { 02817 t->val += len_v3v3(t->center, td->iloc); 02818 } 02819 02820 t->val /= (float)t->total; 02821 } 02822 02823 int ToSphere(TransInfo *t, const int UNUSED(mval[2])) 02824 { 02825 float vec[3]; 02826 float ratio, radius; 02827 int i; 02828 char str[64]; 02829 TransData *td = t->data; 02830 02831 ratio = t->values[0]; 02832 02833 snapGrid(t, &ratio); 02834 02835 applyNumInput(&t->num, &ratio); 02836 02837 if (ratio < 0) 02838 ratio = 0.0f; 02839 else if (ratio > 1) 02840 ratio = 1.0f; 02841 02842 t->values[0] = ratio; 02843 02844 /* header print for NumInput */ 02845 if (hasNumInput(&t->num)) { 02846 char c[20]; 02847 02848 outputNumInput(&(t->num), c); 02849 02850 sprintf(str, "To Sphere: %s %s", c, t->proptext); 02851 } 02852 else { 02853 /* default header print */ 02854 sprintf(str, "To Sphere: %.4f %s", ratio, t->proptext); 02855 } 02856 02857 02858 for(i = 0 ; i < t->total; i++, td++) { 02859 float tratio; 02860 if (td->flag & TD_NOACTION) 02861 break; 02862 02863 if (td->flag & TD_SKIP) 02864 continue; 02865 02866 sub_v3_v3v3(vec, td->iloc, t->center); 02867 02868 radius = normalize_v3(vec); 02869 02870 tratio = ratio * td->factor; 02871 02872 mul_v3_fl(vec, radius * (1.0f - tratio) + t->val * tratio); 02873 02874 add_v3_v3v3(td->loc, t->center, vec); 02875 } 02876 02877 02878 recalcData(t); 02879 02880 ED_area_headerprint(t->sa, str); 02881 02882 return 1; 02883 } 02884 02885 /* ************************** ROTATION *************************** */ 02886 02887 02888 static void postInputRotation(TransInfo *t, float values[3]) 02889 { 02890 if ((t->con.mode & CON_APPLY) && t->con.applyRot) { 02891 t->con.applyRot(t, NULL, t->axis, values); 02892 } 02893 } 02894 02895 void initRotation(TransInfo *t) 02896 { 02897 t->mode = TFM_ROTATION; 02898 t->transform = Rotation; 02899 02900 setInputPostFct(&t->mouse, postInputRotation); 02901 initMouseInputMode(t, &t->mouse, INPUT_ANGLE); 02902 02903 t->idx_max = 0; 02904 t->num.idx_max = 0; 02905 t->snap[0] = 0.0f; 02906 t->snap[1] = (float)((5.0/180)*M_PI); 02907 t->snap[2] = t->snap[1] * 0.2f; 02908 02909 t->num.increment = 1.0f; 02910 02911 if (t->flag & T_2D_EDIT) 02912 t->flag |= T_NO_CONSTRAINT; 02913 02914 negate_v3_v3(t->axis, t->viewinv[2]); 02915 normalize_v3(t->axis); 02916 02917 copy_v3_v3(t->axis_orig, t->axis); 02918 } 02919 02920 static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short around) 02921 { 02922 float vec[3], totmat[3][3], smat[3][3]; 02923 float eul[3], fmat[3][3], quat[4]; 02924 float *center = t->center; 02925 02926 /* local constraint shouldn't alter center */ 02927 if (around == V3D_LOCAL) { 02928 if ( (t->flag & (T_OBJECT|T_POSE)) || 02929 (t->settings->selectmode & (SCE_SELECT_EDGE|SCE_SELECT_FACE)) || 02930 (t->obedit && t->obedit->type == OB_ARMATURE)) 02931 { 02932 center = td->center; 02933 } 02934 } 02935 02936 if (t->flag & T_POINTS) { 02937 mul_m3_m3m3(totmat, mat, td->mtx); 02938 mul_m3_m3m3(smat, td->smtx, totmat); 02939 02940 sub_v3_v3v3(vec, td->iloc, center); 02941 mul_m3_v3(smat, vec); 02942 02943 add_v3_v3v3(td->loc, vec, center); 02944 02945 sub_v3_v3v3(vec,td->loc,td->iloc); 02946 protectedTransBits(td->protectflag, vec); 02947 add_v3_v3v3(td->loc, td->iloc, vec); 02948 02949 02950 if(td->flag & TD_USEQUAT) { 02951 mul_serie_m3(fmat, td->mtx, mat, td->smtx, NULL, NULL, NULL, NULL, NULL); 02952 mat3_to_quat( quat,fmat); // Actual transform 02953 02954 if(td->ext->quat){ 02955 mul_qt_qtqt(td->ext->quat, quat, td->ext->iquat); 02956 02957 /* is there a reason not to have this here? -jahka */ 02958 protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat); 02959 } 02960 } 02961 } 02974 else if (t->flag & T_POSE) { 02975 float pmtx[3][3], imtx[3][3]; 02976 02977 // Extract and invert armature object matrix 02978 copy_m3_m4(pmtx, t->poseobj->obmat); 02979 invert_m3_m3(imtx, pmtx); 02980 02981 if ((td->flag & TD_NO_LOC) == 0) 02982 { 02983 sub_v3_v3v3(vec, td->center, center); 02984 02985 mul_m3_v3(pmtx, vec); // To Global space 02986 mul_m3_v3(mat, vec); // Applying rotation 02987 mul_m3_v3(imtx, vec); // To Local space 02988 02989 add_v3_v3(vec, center); 02990 /* vec now is the location where the object has to be */ 02991 02992 sub_v3_v3v3(vec, vec, td->center); // Translation needed from the initial location 02993 02994 /* special exception, see TD_PBONE_LOCAL_MTX definition comments */ 02995 if(td->flag & TD_PBONE_LOCAL_MTX_P) { 02996 /* do nothing */ 02997 } 02998 else if (td->flag & TD_PBONE_LOCAL_MTX_C) { 02999 mul_m3_v3(pmtx, vec); // To Global space 03000 mul_m3_v3(td->ext->l_smtx, vec);// To Pose space (Local Location) 03001 } 03002 else { 03003 mul_m3_v3(pmtx, vec); // To Global space 03004 mul_m3_v3(td->smtx, vec);// To Pose space 03005 } 03006 03007 protectedTransBits(td->protectflag, vec); 03008 03009 add_v3_v3v3(td->loc, td->iloc, vec); 03010 03011 constraintTransLim(t, td); 03012 } 03013 03014 /* rotation */ 03015 if ((t->flag & T_V3D_ALIGN)==0) { // align mode doesn't rotate objects itself 03016 /* euler or quaternion/axis-angle? */ 03017 if (td->ext->rotOrder == ROT_MODE_QUAT) { 03018 mul_serie_m3(fmat, td->mtx, mat, td->smtx, NULL, NULL, NULL, NULL, NULL); 03019 03020 mat3_to_quat( quat,fmat); // Actual transform 03021 03022 mul_qt_qtqt(td->ext->quat, quat, td->ext->iquat); 03023 /* this function works on end result */ 03024 protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat); 03025 03026 } 03027 else if (td->ext->rotOrder == ROT_MODE_AXISANGLE) { 03028 /* calculate effect based on quats */ 03029 float iquat[4], tquat[4]; 03030 03031 axis_angle_to_quat(iquat, td->ext->irotAxis, td->ext->irotAngle); 03032 03033 mul_serie_m3(fmat, td->mtx, mat, td->smtx, NULL, NULL, NULL, NULL, NULL); 03034 mat3_to_quat( quat,fmat); // Actual transform 03035 mul_qt_qtqt(tquat, quat, iquat); 03036 03037 quat_to_axis_angle( td->ext->rotAxis, td->ext->rotAngle,tquat); 03038 03039 /* this function works on end result */ 03040 protectedAxisAngleBits(td->protectflag, td->ext->rotAxis, td->ext->rotAngle, td->ext->irotAxis, td->ext->irotAngle); 03041 } 03042 else { 03043 float eulmat[3][3]; 03044 03045 mul_m3_m3m3(totmat, mat, td->mtx); 03046 mul_m3_m3m3(smat, td->smtx, totmat); 03047 03048 /* calculate the total rotatation in eulers */ 03049 copy_v3_v3(eul, td->ext->irot); 03050 eulO_to_mat3( eulmat,eul, td->ext->rotOrder); 03051 03052 /* mat = transform, obmat = bone rotation */ 03053 mul_m3_m3m3(fmat, smat, eulmat); 03054 03055 mat3_to_compatible_eulO( eul, td->ext->rot, td->ext->rotOrder,fmat); 03056 03057 /* and apply (to end result only) */ 03058 protectedRotateBits(td->protectflag, eul, td->ext->irot); 03059 copy_v3_v3(td->ext->rot, eul); 03060 } 03061 03062 constraintRotLim(t, td); 03063 } 03064 } 03065 else { 03066 if ((td->flag & TD_NO_LOC) == 0) 03067 { 03068 /* translation */ 03069 sub_v3_v3v3(vec, td->center, center); 03070 mul_m3_v3(mat, vec); 03071 add_v3_v3(vec, center); 03072 /* vec now is the location where the object has to be */ 03073 sub_v3_v3(vec, td->center); 03074 mul_m3_v3(td->smtx, vec); 03075 03076 protectedTransBits(td->protectflag, vec); 03077 03078 add_v3_v3v3(td->loc, td->iloc, vec); 03079 } 03080 03081 03082 constraintTransLim(t, td); 03083 03084 /* rotation */ 03085 if ((t->flag & T_V3D_ALIGN)==0) { // align mode doesn't rotate objects itself 03086 /* euler or quaternion? */ 03087 if ((td->ext->rotOrder == ROT_MODE_QUAT) || (td->flag & TD_USEQUAT)) { 03088 mul_serie_m3(fmat, td->mtx, mat, td->smtx, NULL, NULL, NULL, NULL, NULL); 03089 mat3_to_quat( quat,fmat); // Actual transform 03090 03091 mul_qt_qtqt(td->ext->quat, quat, td->ext->iquat); 03092 /* this function works on end result */ 03093 protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat); 03094 } 03095 else if (td->ext->rotOrder == ROT_MODE_AXISANGLE) { 03096 /* calculate effect based on quats */ 03097 float iquat[4], tquat[4]; 03098 03099 axis_angle_to_quat(iquat, td->ext->irotAxis, td->ext->irotAngle); 03100 03101 mul_serie_m3(fmat, td->mtx, mat, td->smtx, NULL, NULL, NULL, NULL, NULL); 03102 mat3_to_quat( quat,fmat); // Actual transform 03103 mul_qt_qtqt(tquat, quat, iquat); 03104 03105 quat_to_axis_angle( td->ext->rotAxis, td->ext->rotAngle,tquat); 03106 03107 /* this function works on end result */ 03108 protectedAxisAngleBits(td->protectflag, td->ext->rotAxis, td->ext->rotAngle, td->ext->irotAxis, td->ext->irotAngle); 03109 } 03110 else { 03111 float obmat[3][3]; 03112 03113 mul_m3_m3m3(totmat, mat, td->mtx); 03114 mul_m3_m3m3(smat, td->smtx, totmat); 03115 03116 /* calculate the total rotatation in eulers */ 03117 add_v3_v3v3(eul, td->ext->irot, td->ext->drot); /* we have to correct for delta rot */ 03118 eulO_to_mat3( obmat,eul, td->ext->rotOrder); 03119 /* mat = transform, obmat = object rotation */ 03120 mul_m3_m3m3(fmat, smat, obmat); 03121 03122 mat3_to_compatible_eulO( eul, td->ext->rot, td->ext->rotOrder,fmat); 03123 03124 /* correct back for delta rot */ 03125 sub_v3_v3v3(eul, eul, td->ext->drot); 03126 03127 /* and apply */ 03128 protectedRotateBits(td->protectflag, eul, td->ext->irot); 03129 copy_v3_v3(td->ext->rot, eul); 03130 } 03131 03132 constraintRotLim(t, td); 03133 } 03134 } 03135 } 03136 03137 static void applyRotation(TransInfo *t, float angle, float axis[3]) 03138 { 03139 TransData *td = t->data; 03140 float mat[3][3]; 03141 int i; 03142 03143 vec_rot_to_mat3( mat,axis, angle); 03144 03145 for(i = 0 ; i < t->total; i++, td++) { 03146 03147 if (td->flag & TD_NOACTION) 03148 break; 03149 03150 if (td->flag & TD_SKIP) 03151 continue; 03152 03153 if (t->con.applyRot) { 03154 t->con.applyRot(t, td, axis, NULL); 03155 vec_rot_to_mat3( mat,axis, angle * td->factor); 03156 } 03157 else if (t->flag & T_PROP_EDIT) { 03158 vec_rot_to_mat3( mat,axis, angle * td->factor); 03159 } 03160 03161 ElementRotation(t, td, mat, t->around); 03162 } 03163 } 03164 03165 int Rotation(TransInfo *t, const int UNUSED(mval[2])) 03166 { 03167 char str[128], *spos= str; 03168 03169 float final; 03170 03171 final = t->values[0]; 03172 03173 snapGrid(t, &final); 03174 03175 if ((t->con.mode & CON_APPLY) && t->con.applyRot) { 03176 t->con.applyRot(t, NULL, t->axis, NULL); 03177 } else { 03178 /* reset axis if constraint is not set */ 03179 copy_v3_v3(t->axis, t->axis_orig); 03180 } 03181 03182 applySnapping(t, &final); 03183 03184 if (hasNumInput(&t->num)) { 03185 char c[20]; 03186 03187 applyNumInput(&t->num, &final); 03188 03189 outputNumInput(&(t->num), c); 03190 03191 spos+= sprintf(spos, "Rot: %s %s %s", &c[0], t->con.text, t->proptext); 03192 03193 /* Clamp between -180 and 180 */ 03194 final= angle_wrap_rad(DEG2RADF(final)); 03195 } 03196 else { 03197 spos += sprintf(spos, "Rot: %.2f%s %s", RAD2DEGF(final), t->con.text, t->proptext); 03198 } 03199 03200 if (t->flag & (T_PROP_EDIT|T_PROP_CONNECTED)) { 03201 spos += sprintf(spos, " Proportional size: %.2f", t->prop_size); 03202 } 03203 (void)spos; 03204 03205 t->values[0] = final; 03206 03207 applyRotation(t, final, t->axis); 03208 03209 recalcData(t); 03210 03211 ED_area_headerprint(t->sa, str); 03212 03213 return 1; 03214 } 03215 03216 03217 /* ************************** TRACKBALL *************************** */ 03218 03219 void initTrackball(TransInfo *t) 03220 { 03221 t->mode = TFM_TRACKBALL; 03222 t->transform = Trackball; 03223 03224 initMouseInputMode(t, &t->mouse, INPUT_TRACKBALL); 03225 03226 t->idx_max = 1; 03227 t->num.idx_max = 1; 03228 t->snap[0] = 0.0f; 03229 t->snap[1] = (float)((5.0/180)*M_PI); 03230 t->snap[2] = t->snap[1] * 0.2f; 03231 03232 t->num.increment = 1.0f; 03233 03234 t->flag |= T_NO_CONSTRAINT; 03235 } 03236 03237 static void applyTrackball(TransInfo *t, float axis1[3], float axis2[3], float angles[2]) 03238 { 03239 TransData *td = t->data; 03240 float mat[3][3], smat[3][3], totmat[3][3]; 03241 int i; 03242 03243 vec_rot_to_mat3( smat,axis1, angles[0]); 03244 vec_rot_to_mat3( totmat,axis2, angles[1]); 03245 03246 mul_m3_m3m3(mat, smat, totmat); 03247 03248 for(i = 0 ; i < t->total; i++, td++) { 03249 if (td->flag & TD_NOACTION) 03250 break; 03251 03252 if (td->flag & TD_SKIP) 03253 continue; 03254 03255 if (t->flag & T_PROP_EDIT) { 03256 vec_rot_to_mat3( smat,axis1, td->factor * angles[0]); 03257 vec_rot_to_mat3( totmat,axis2, td->factor * angles[1]); 03258 03259 mul_m3_m3m3(mat, smat, totmat); 03260 } 03261 03262 ElementRotation(t, td, mat, t->around); 03263 } 03264 } 03265 03266 int Trackball(TransInfo *t, const int UNUSED(mval[2])) 03267 { 03268 char str[128], *spos= str; 03269 float axis1[3], axis2[3]; 03270 float mat[3][3], totmat[3][3], smat[3][3]; 03271 float phi[2]; 03272 03273 copy_v3_v3(axis1, t->persinv[0]); 03274 copy_v3_v3(axis2, t->persinv[1]); 03275 normalize_v3(axis1); 03276 normalize_v3(axis2); 03277 03278 phi[0] = t->values[0]; 03279 phi[1] = t->values[1]; 03280 03281 snapGrid(t, phi); 03282 03283 if (hasNumInput(&t->num)) { 03284 char c[40]; 03285 03286 applyNumInput(&t->num, phi); 03287 03288 outputNumInput(&(t->num), c); 03289 03290 spos += sprintf(spos, "Trackball: %s %s %s", &c[0], &c[20], t->proptext); 03291 03292 phi[0] = DEG2RADF(phi[0]); 03293 phi[1] = DEG2RADF(phi[1]); 03294 } 03295 else { 03296 spos += sprintf(spos, "Trackball: %.2f %.2f %s", RAD2DEGF(phi[0]), RAD2DEGF(phi[1]), t->proptext); 03297 } 03298 03299 if (t->flag & (T_PROP_EDIT|T_PROP_CONNECTED)) { 03300 spos += sprintf(spos, " Proportional size: %.2f", t->prop_size); 03301 } 03302 (void)spos; 03303 03304 vec_rot_to_mat3( smat,axis1, phi[0]); 03305 vec_rot_to_mat3( totmat,axis2, phi[1]); 03306 03307 mul_m3_m3m3(mat, smat, totmat); 03308 03309 // TRANSFORM_FIX_ME 03310 //copy_m3_m3(t->mat, mat); // used in manipulator 03311 03312 applyTrackball(t, axis1, axis2, phi); 03313 03314 recalcData(t); 03315 03316 ED_area_headerprint(t->sa, str); 03317 03318 return 1; 03319 } 03320 03321 /* ************************** TRANSLATION *************************** */ 03322 03323 void initTranslation(TransInfo *t) 03324 { 03325 if (t->spacetype == SPACE_ACTION) { 03326 /* this space uses time translate */ 03327 t->state = TRANS_CANCEL; 03328 } 03329 03330 t->mode = TFM_TRANSLATION; 03331 t->transform = Translation; 03332 03333 initMouseInputMode(t, &t->mouse, INPUT_VECTOR); 03334 03335 t->idx_max = (t->flag & T_2D_EDIT)? 1: 2; 03336 t->num.flag = 0; 03337 t->num.idx_max = t->idx_max; 03338 03339 if(t->spacetype == SPACE_VIEW3D) { 03340 RegionView3D *rv3d = t->ar->regiondata; 03341 03342 if (rv3d) { 03343 t->snap[0] = 0.0f; 03344 t->snap[1] = rv3d->gridview * 1.0f; 03345 t->snap[2] = t->snap[1] * 0.1f; 03346 } 03347 } 03348 else if(ELEM(t->spacetype, SPACE_IMAGE, SPACE_CLIP)) { 03349 t->snap[0] = 0.0f; 03350 t->snap[1] = 0.125f; 03351 t->snap[2] = 0.0625f; 03352 } 03353 else { 03354 t->snap[0] = 0.0f; 03355 t->snap[1] = t->snap[2] = 1.0f; 03356 } 03357 03358 t->num.increment = t->snap[1]; 03359 } 03360 03361 static void headerTranslation(TransInfo *t, float vec[3], char *str) 03362 { 03363 char *spos= str; 03364 char tvec[60]; 03365 char distvec[20]; 03366 char autoik[20]; 03367 float dist; 03368 03369 if (hasNumInput(&t->num)) { 03370 outputNumInput(&(t->num), tvec); 03371 dist = len_v3(t->num.val); 03372 } 03373 else { 03374 float dvec[3]; 03375 03376 copy_v3_v3(dvec, vec); 03377 applyAspectRatio(t, dvec); 03378 03379 dist = len_v3(vec); 03380 if(!(t->flag & T_2D_EDIT) && t->scene->unit.system) { 03381 int i, do_split= t->scene->unit.flag & USER_UNIT_OPT_SPLIT ? 1:0; 03382 03383 for(i=0; i<3; i++) 03384 bUnit_AsString(&tvec[i*20], 20, dvec[i]*t->scene->unit.scale_length, 4, t->scene->unit.system, B_UNIT_LENGTH, do_split, 1); 03385 } 03386 else { 03387 sprintf(&tvec[0], "%.4f", dvec[0]); 03388 sprintf(&tvec[20], "%.4f", dvec[1]); 03389 sprintf(&tvec[40], "%.4f", dvec[2]); 03390 } 03391 } 03392 03393 if(!(t->flag & T_2D_EDIT) && t->scene->unit.system) 03394 bUnit_AsString(distvec, sizeof(distvec), dist*t->scene->unit.scale_length, 4, t->scene->unit.system, B_UNIT_LENGTH, t->scene->unit.flag & USER_UNIT_OPT_SPLIT, 0); 03395 else if( dist > 1e10f || dist < -1e10f ) /* prevent string buffer overflow */ 03396 sprintf(distvec, "%.4e", dist); 03397 else 03398 sprintf(distvec, "%.4f", dist); 03399 03400 if(t->flag & T_AUTOIK) { 03401 short chainlen= t->settings->autoik_chainlen; 03402 03403 if(chainlen) 03404 sprintf(autoik, "AutoIK-Len: %d", chainlen); 03405 else 03406 autoik[0]= '\0'; 03407 } 03408 else 03409 autoik[0]= '\0'; 03410 03411 if (t->con.mode & CON_APPLY) { 03412 switch(t->num.idx_max) { 03413 case 0: 03414 spos += sprintf(spos, "D: %s (%s)%s %s %s", &tvec[0], distvec, t->con.text, t->proptext, &autoik[0]); 03415 break; 03416 case 1: 03417 spos += sprintf(spos, "D: %s D: %s (%s)%s %s %s", &tvec[0], &tvec[20], distvec, t->con.text, t->proptext, &autoik[0]); 03418 break; 03419 case 2: 03420 spos += sprintf(spos, "D: %s D: %s D: %s (%s)%s %s %s", &tvec[0], &tvec[20], &tvec[40], distvec, t->con.text, t->proptext, &autoik[0]); 03421 } 03422 } 03423 else { 03424 if(t->flag & T_2D_EDIT) 03425 spos += sprintf(spos, "Dx: %s Dy: %s (%s)%s %s", &tvec[0], &tvec[20], distvec, t->con.text, t->proptext); 03426 else 03427 spos += sprintf(spos, "Dx: %s Dy: %s Dz: %s (%s)%s %s %s", &tvec[0], &tvec[20], &tvec[40], distvec, t->con.text, t->proptext, &autoik[0]); 03428 } 03429 03430 if (t->flag & (T_PROP_EDIT|T_PROP_CONNECTED)) { 03431 spos += sprintf(spos, " Proportional size: %.2f", t->prop_size); 03432 } 03433 (void)spos; 03434 } 03435 03436 static void applyTranslation(TransInfo *t, float vec[3]) 03437 { 03438 TransData *td = t->data; 03439 float tvec[3]; 03440 int i; 03441 03442 for(i = 0 ; i < t->total; i++, td++) { 03443 if (td->flag & TD_NOACTION) 03444 break; 03445 03446 if (td->flag & TD_SKIP) 03447 continue; 03448 03449 /* handle snapping rotation before doing the translation */ 03450 if (usingSnappingNormal(t)) 03451 { 03452 if (validSnappingNormal(t)) 03453 { 03454 float *original_normal = td->axismtx[2]; 03455 float axis[3]; 03456 float quat[4]; 03457 float mat[3][3]; 03458 float angle; 03459 03460 cross_v3_v3v3(axis, original_normal, t->tsnap.snapNormal); 03461 angle = saacos(dot_v3v3(original_normal, t->tsnap.snapNormal)); 03462 03463 axis_angle_to_quat(quat, axis, angle); 03464 03465 quat_to_mat3( mat,quat); 03466 03467 ElementRotation(t, td, mat, V3D_LOCAL); 03468 } 03469 else 03470 { 03471 float mat[3][3]; 03472 03473 unit_m3(mat); 03474 03475 ElementRotation(t, td, mat, V3D_LOCAL); 03476 } 03477 } 03478 03479 if (t->con.applyVec) { 03480 float pvec[3]; 03481 t->con.applyVec(t, td, vec, tvec, pvec); 03482 } 03483 else { 03484 copy_v3_v3(tvec, vec); 03485 } 03486 03487 mul_m3_v3(td->smtx, tvec); 03488 mul_v3_fl(tvec, td->factor); 03489 03490 protectedTransBits(td->protectflag, tvec); 03491 03492 add_v3_v3v3(td->loc, td->iloc, tvec); 03493 03494 constraintTransLim(t, td); 03495 } 03496 } 03497 03498 /* uses t->vec to store actual translation in */ 03499 int Translation(TransInfo *t, const int UNUSED(mval[2])) 03500 { 03501 char str[250]; 03502 03503 if (t->con.mode & CON_APPLY) { 03504 float pvec[3] = {0.0f, 0.0f, 0.0f}; 03505 float tvec[3]; 03506 if (hasNumInput(&t->num)) { 03507 removeAspectRatio(t, t->values); 03508 } 03509 applySnapping(t, t->values); 03510 t->con.applyVec(t, NULL, t->values, tvec, pvec); 03511 copy_v3_v3(t->values, tvec); 03512 headerTranslation(t, pvec, str); 03513 } 03514 else { 03515 snapGrid(t, t->values); 03516 applyNumInput(&t->num, t->values); 03517 if (hasNumInput(&t->num)) { 03518 removeAspectRatio(t, t->values); 03519 } 03520 applySnapping(t, t->values); 03521 headerTranslation(t, t->values, str); 03522 } 03523 03524 applyTranslation(t, t->values); 03525 03526 /* evil hack - redo translation if clipping needed */ 03527 if (t->flag & T_CLIP_UV && clipUVTransform(t, t->values, 0)) 03528 applyTranslation(t, t->values); 03529 03530 recalcData(t); 03531 03532 ED_area_headerprint(t->sa, str); 03533 03534 return 1; 03535 } 03536 03537 /* ************************** SHRINK/FATTEN *************************** */ 03538 03539 void initShrinkFatten(TransInfo *t) 03540 { 03541 // If not in mesh edit mode, fallback to Resize 03542 if (t->obedit==NULL || t->obedit->type != OB_MESH) { 03543 initResize(t); 03544 } 03545 else { 03546 t->mode = TFM_SHRINKFATTEN; 03547 t->transform = ShrinkFatten; 03548 03549 initMouseInputMode(t, &t->mouse, INPUT_VERTICAL_ABSOLUTE); 03550 03551 t->idx_max = 0; 03552 t->num.idx_max = 0; 03553 t->snap[0] = 0.0f; 03554 t->snap[1] = 1.0f; 03555 t->snap[2] = t->snap[1] * 0.1f; 03556 03557 t->num.increment = t->snap[1]; 03558 03559 t->flag |= T_NO_CONSTRAINT; 03560 } 03561 } 03562 03563 03564 03565 int ShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) 03566 { 03567 float vec[3]; 03568 float distance; 03569 int i; 03570 char str[64]; 03571 TransData *td = t->data; 03572 03573 distance = -t->values[0]; 03574 03575 snapGrid(t, &distance); 03576 03577 applyNumInput(&t->num, &distance); 03578 03579 /* header print for NumInput */ 03580 if (hasNumInput(&t->num)) { 03581 char c[20]; 03582 03583 outputNumInput(&(t->num), c); 03584 03585 sprintf(str, "Shrink/Fatten: %s %s", c, t->proptext); 03586 } 03587 else { 03588 /* default header print */ 03589 sprintf(str, "Shrink/Fatten: %.4f %s", distance, t->proptext); 03590 } 03591 03592 03593 for(i = 0 ; i < t->total; i++, td++) { 03594 if (td->flag & TD_NOACTION) 03595 break; 03596 03597 if (td->flag & TD_SKIP) 03598 continue; 03599 03600 copy_v3_v3(vec, td->axismtx[2]); 03601 mul_v3_fl(vec, distance); 03602 mul_v3_fl(vec, td->factor); 03603 03604 add_v3_v3v3(td->loc, td->iloc, vec); 03605 } 03606 03607 recalcData(t); 03608 03609 ED_area_headerprint(t->sa, str); 03610 03611 return 1; 03612 } 03613 03614 /* ************************** TILT *************************** */ 03615 03616 void initTilt(TransInfo *t) 03617 { 03618 t->mode = TFM_TILT; 03619 t->transform = Tilt; 03620 03621 initMouseInputMode(t, &t->mouse, INPUT_ANGLE); 03622 03623 t->idx_max = 0; 03624 t->num.idx_max = 0; 03625 t->snap[0] = 0.0f; 03626 t->snap[1] = (float)((5.0/180)*M_PI); 03627 t->snap[2] = t->snap[1] * 0.2f; 03628 03629 t->num.increment = t->snap[1]; 03630 03631 t->flag |= T_NO_CONSTRAINT|T_NO_PROJECT; 03632 } 03633 03634 03635 03636 int Tilt(TransInfo *t, const int UNUSED(mval[2])) 03637 { 03638 TransData *td = t->data; 03639 int i; 03640 char str[50]; 03641 03642 float final; 03643 03644 final = t->values[0]; 03645 03646 snapGrid(t, &final); 03647 03648 if (hasNumInput(&t->num)) { 03649 char c[20]; 03650 03651 applyNumInput(&t->num, &final); 03652 03653 outputNumInput(&(t->num), c); 03654 03655 sprintf(str, "Tilt: %s %s", &c[0], t->proptext); 03656 03657 final = DEG2RADF(final); 03658 } 03659 else { 03660 sprintf(str, "Tilt: %.2f %s", RAD2DEGF(final), t->proptext); 03661 } 03662 03663 for(i = 0 ; i < t->total; i++, td++) { 03664 if (td->flag & TD_NOACTION) 03665 break; 03666 03667 if (td->flag & TD_SKIP) 03668 continue; 03669 03670 if (td->val) { 03671 *td->val = td->ival + final * td->factor; 03672 } 03673 } 03674 03675 recalcData(t); 03676 03677 ED_area_headerprint(t->sa, str); 03678 03679 return 1; 03680 } 03681 03682 03683 /* ******************** Curve Shrink/Fatten *************** */ 03684 03685 void initCurveShrinkFatten(TransInfo *t) 03686 { 03687 t->mode = TFM_CURVE_SHRINKFATTEN; 03688 t->transform = CurveShrinkFatten; 03689 03690 initMouseInputMode(t, &t->mouse, INPUT_SPRING); 03691 03692 t->idx_max = 0; 03693 t->num.idx_max = 0; 03694 t->snap[0] = 0.0f; 03695 t->snap[1] = 0.1f; 03696 t->snap[2] = t->snap[1] * 0.1f; 03697 03698 t->num.increment = t->snap[1]; 03699 03700 t->flag |= T_NO_ZERO; 03701 t->num.flag |= NUM_NO_ZERO; 03702 03703 t->flag |= T_NO_CONSTRAINT; 03704 } 03705 03706 int CurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2])) 03707 { 03708 TransData *td = t->data; 03709 float ratio; 03710 int i; 03711 char str[50]; 03712 03713 ratio = t->values[0]; 03714 03715 snapGrid(t, &ratio); 03716 03717 applyNumInput(&t->num, &ratio); 03718 03719 /* header print for NumInput */ 03720 if (hasNumInput(&t->num)) { 03721 char c[20]; 03722 03723 outputNumInput(&(t->num), c); 03724 sprintf(str, "Shrink/Fatten: %s", c); 03725 } 03726 else { 03727 sprintf(str, "Shrink/Fatten: %3f", ratio); 03728 } 03729 03730 for(i = 0 ; i < t->total; i++, td++) { 03731 if (td->flag & TD_NOACTION) 03732 break; 03733 03734 if (td->flag & TD_SKIP) 03735 continue; 03736 03737 if(td->val) { 03738 //*td->val= ratio; 03739 *td->val= td->ival*ratio; 03740 if (*td->val <= 0.0f) *td->val = 0.001f; 03741 } 03742 } 03743 03744 recalcData(t); 03745 03746 ED_area_headerprint(t->sa, str); 03747 03748 return 1; 03749 } 03750 03751 /* ************************** PUSH/PULL *************************** */ 03752 03753 void initPushPull(TransInfo *t) 03754 { 03755 t->mode = TFM_PUSHPULL; 03756 t->transform = PushPull; 03757 03758 initMouseInputMode(t, &t->mouse, INPUT_VERTICAL_ABSOLUTE); 03759 03760 t->idx_max = 0; 03761 t->num.idx_max = 0; 03762 t->snap[0] = 0.0f; 03763 t->snap[1] = 1.0f; 03764 t->snap[2] = t->snap[1] * 0.1f; 03765 03766 t->num.increment = t->snap[1]; 03767 } 03768 03769 03770 int PushPull(TransInfo *t, const int UNUSED(mval[2])) 03771 { 03772 float vec[3], axis[3]; 03773 float distance; 03774 int i; 03775 char str[128]; 03776 TransData *td = t->data; 03777 03778 distance = t->values[0]; 03779 03780 snapGrid(t, &distance); 03781 03782 applyNumInput(&t->num, &distance); 03783 03784 /* header print for NumInput */ 03785 if (hasNumInput(&t->num)) { 03786 char c[20]; 03787 03788 outputNumInput(&(t->num), c); 03789 03790 sprintf(str, "Push/Pull: %s%s %s", c, t->con.text, t->proptext); 03791 } 03792 else { 03793 /* default header print */ 03794 sprintf(str, "Push/Pull: %.4f%s %s", distance, t->con.text, t->proptext); 03795 } 03796 03797 if (t->con.applyRot && t->con.mode & CON_APPLY) { 03798 t->con.applyRot(t, NULL, axis, NULL); 03799 } 03800 03801 for(i = 0 ; i < t->total; i++, td++) { 03802 if (td->flag & TD_NOACTION) 03803 break; 03804 03805 if (td->flag & TD_SKIP) 03806 continue; 03807 03808 sub_v3_v3v3(vec, t->center, td->center); 03809 if (t->con.applyRot && t->con.mode & CON_APPLY) { 03810 t->con.applyRot(t, td, axis, NULL); 03811 if (isLockConstraint(t)) { 03812 float dvec[3]; 03813 project_v3_v3v3(dvec, vec, axis); 03814 sub_v3_v3(vec, dvec); 03815 } 03816 else { 03817 project_v3_v3v3(vec, vec, axis); 03818 } 03819 } 03820 normalize_v3(vec); 03821 mul_v3_fl(vec, distance); 03822 mul_v3_fl(vec, td->factor); 03823 03824 add_v3_v3v3(td->loc, td->iloc, vec); 03825 } 03826 03827 recalcData(t); 03828 03829 ED_area_headerprint(t->sa, str); 03830 03831 return 1; 03832 } 03833 03834 /* ************************** BEVEL **************************** */ 03835 03836 void initBevel(TransInfo *t) 03837 { 03838 t->transform = Bevel; 03839 t->handleEvent = handleEventBevel; 03840 03841 initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_ABSOLUTE); 03842 03843 t->mode = TFM_BEVEL; 03844 t->flag |= T_NO_CONSTRAINT; 03845 t->num.flag |= NUM_NO_NEGATIVE; 03846 03847 t->idx_max = 0; 03848 t->num.idx_max = 0; 03849 t->snap[0] = 0.0f; 03850 t->snap[1] = 0.1f; 03851 t->snap[2] = t->snap[1] * 0.1f; 03852 03853 t->num.increment = t->snap[1]; 03854 03855 /* DON'T KNOW WHY THIS IS NEEDED */ 03856 if (G.editBMesh->imval[0] == 0 && G.editBMesh->imval[1] == 0) { 03857 /* save the initial mouse co */ 03858 G.editBMesh->imval[0] = t->imval[0]; 03859 G.editBMesh->imval[1] = t->imval[1]; 03860 } 03861 else { 03862 /* restore the mouse co from a previous call to initTransform() */ 03863 t->imval[0] = G.editBMesh->imval[0]; 03864 t->imval[1] = G.editBMesh->imval[1]; 03865 } 03866 } 03867 03868 int handleEventBevel(TransInfo *t, wmEvent *event) 03869 { 03870 if (event->val==KM_PRESS) { 03871 if(!G.editBMesh) return 0; 03872 03873 switch (event->type) { 03874 case MIDDLEMOUSE: 03875 G.editBMesh->options ^= BME_BEVEL_VERT; 03876 t->state = TRANS_CANCEL; 03877 return 1; 03878 //case PADPLUSKEY: 03879 // G.editBMesh->options ^= BME_BEVEL_RES; 03880 // G.editBMesh->res += 1; 03881 // if (G.editBMesh->res > 4) { 03882 // G.editBMesh->res = 4; 03883 // } 03884 // t->state = TRANS_CANCEL; 03885 // return 1; 03886 //case PADMINUS: 03887 // G.editBMesh->options ^= BME_BEVEL_RES; 03888 // G.editBMesh->res -= 1; 03889 // if (G.editBMesh->res < 0) { 03890 // G.editBMesh->res = 0; 03891 // } 03892 // t->state = TRANS_CANCEL; 03893 // return 1; 03894 default: 03895 return 0; 03896 } 03897 } 03898 return 0; 03899 } 03900 03901 int Bevel(TransInfo *t, const int UNUSED(mval[2])) 03902 { 03903 float distance,d; 03904 int i; 03905 char str[128]; 03906 const char *mode; 03907 TransData *td = t->data; 03908 03909 mode = (G.editBMesh->options & BME_BEVEL_VERT) ? "verts only" : "normal"; 03910 distance = t->values[0] / 4; /* 4 just seemed a nice value to me, nothing special */ 03911 03912 distance = fabs(distance); 03913 03914 snapGrid(t, &distance); 03915 03916 applyNumInput(&t->num, &distance); 03917 03918 /* header print for NumInput */ 03919 if (hasNumInput(&t->num)) { 03920 char c[20]; 03921 03922 outputNumInput(&(t->num), c); 03923 03924 sprintf(str, "Bevel - Dist: %s, Mode: %s (MMB to toggle))", c, mode); 03925 } 03926 else { 03927 /* default header print */ 03928 sprintf(str, "Bevel - Dist: %.4f, Mode: %s (MMB to toggle))", distance, mode); 03929 } 03930 03931 if (distance < 0) distance = -distance; 03932 for(i = 0 ; i < t->total; i++, td++) { 03933 if (td->axismtx[1][0] > 0 && distance > td->axismtx[1][0]) { 03934 d = td->axismtx[1][0]; 03935 } 03936 else { 03937 d = distance; 03938 } 03939 madd_v3_v3v3fl(td->loc, td->center, td->axismtx[0], (*td->val) * d); 03940 } 03941 03942 recalcData(t); 03943 03944 ED_area_headerprint(t->sa, str); 03945 03946 return 1; 03947 } 03948 03949 /* ************************** BEVEL WEIGHT *************************** */ 03950 03951 void initBevelWeight(TransInfo *t) 03952 { 03953 t->mode = TFM_BWEIGHT; 03954 t->transform = BevelWeight; 03955 03956 initMouseInputMode(t, &t->mouse, INPUT_SPRING); 03957 03958 t->idx_max = 0; 03959 t->num.idx_max = 0; 03960 t->snap[0] = 0.0f; 03961 t->snap[1] = 0.1f; 03962 t->snap[2] = t->snap[1] * 0.1f; 03963 03964 t->num.increment = t->snap[1]; 03965 03966 t->flag |= T_NO_CONSTRAINT|T_NO_PROJECT; 03967 } 03968 03969 int BevelWeight(TransInfo *t, const int UNUSED(mval[2])) 03970 { 03971 TransData *td = t->data; 03972 float weight; 03973 int i; 03974 char str[50]; 03975 03976 weight = t->values[0]; 03977 03978 weight -= 1.0f; 03979 if (weight > 1.0f) weight = 1.0f; 03980 03981 snapGrid(t, &weight); 03982 03983 applyNumInput(&t->num, &weight); 03984 03985 /* header print for NumInput */ 03986 if (hasNumInput(&t->num)) { 03987 char c[20]; 03988 03989 outputNumInput(&(t->num), c); 03990 03991 if (weight >= 0.0f) 03992 sprintf(str, "Bevel Weight: +%s %s", c, t->proptext); 03993 else 03994 sprintf(str, "Bevel Weight: %s %s", c, t->proptext); 03995 } 03996 else { 03997 /* default header print */ 03998 if (weight >= 0.0f) 03999 sprintf(str, "Bevel Weight: +%.3f %s", weight, t->proptext); 04000 else 04001 sprintf(str, "Bevel Weight: %.3f %s", weight, t->proptext); 04002 } 04003 04004 for(i = 0 ; i < t->total; i++, td++) { 04005 if (td->flag & TD_NOACTION) 04006 break; 04007 04008 if (td->val) { 04009 *td->val = td->ival + weight * td->factor; 04010 if (*td->val < 0.0f) *td->val = 0.0f; 04011 if (*td->val > 1.0f) *td->val = 1.0f; 04012 } 04013 } 04014 04015 recalcData(t); 04016 04017 ED_area_headerprint(t->sa, str); 04018 04019 return 1; 04020 } 04021 04022 /* ************************** CREASE *************************** */ 04023 04024 void initCrease(TransInfo *t) 04025 { 04026 t->mode = TFM_CREASE; 04027 t->transform = Crease; 04028 04029 initMouseInputMode(t, &t->mouse, INPUT_SPRING); 04030 04031 t->idx_max = 0; 04032 t->num.idx_max = 0; 04033 t->snap[0] = 0.0f; 04034 t->snap[1] = 0.1f; 04035 t->snap[2] = t->snap[1] * 0.1f; 04036 04037 t->num.increment = t->snap[1]; 04038 04039 t->flag |= T_NO_CONSTRAINT|T_NO_PROJECT; 04040 } 04041 04042 int Crease(TransInfo *t, const int UNUSED(mval[2])) 04043 { 04044 TransData *td = t->data; 04045 float crease; 04046 int i; 04047 char str[50]; 04048 04049 crease = t->values[0]; 04050 04051 crease -= 1.0f; 04052 if (crease > 1.0f) crease = 1.0f; 04053 04054 snapGrid(t, &crease); 04055 04056 applyNumInput(&t->num, &crease); 04057 04058 /* header print for NumInput */ 04059 if (hasNumInput(&t->num)) { 04060 char c[20]; 04061 04062 outputNumInput(&(t->num), c); 04063 04064 if (crease >= 0.0f) 04065 sprintf(str, "Crease: +%s %s", c, t->proptext); 04066 else 04067 sprintf(str, "Crease: %s %s", c, t->proptext); 04068 } 04069 else { 04070 /* default header print */ 04071 if (crease >= 0.0f) 04072 sprintf(str, "Crease: +%.3f %s", crease, t->proptext); 04073 else 04074 sprintf(str, "Crease: %.3f %s", crease, t->proptext); 04075 } 04076 04077 for(i = 0 ; i < t->total; i++, td++) { 04078 if (td->flag & TD_NOACTION) 04079 break; 04080 04081 if (td->flag & TD_SKIP) 04082 continue; 04083 04084 if (td->val) { 04085 *td->val = td->ival + crease * td->factor; 04086 if (*td->val < 0.0f) *td->val = 0.0f; 04087 if (*td->val > 1.0f) *td->val = 1.0f; 04088 } 04089 } 04090 04091 recalcData(t); 04092 04093 ED_area_headerprint(t->sa, str); 04094 04095 return 1; 04096 } 04097 04098 /* ******************** EditBone (B-bone) width scaling *************** */ 04099 04100 void initBoneSize(TransInfo *t) 04101 { 04102 t->mode = TFM_BONESIZE; 04103 t->transform = BoneSize; 04104 04105 initMouseInputMode(t, &t->mouse, INPUT_SPRING_FLIP); 04106 04107 t->idx_max = 2; 04108 t->num.idx_max = 2; 04109 t->num.flag |= NUM_NULL_ONE; 04110 t->num.flag |= NUM_AFFECT_ALL; 04111 t->snap[0] = 0.0f; 04112 t->snap[1] = 0.1f; 04113 t->snap[2] = t->snap[1] * 0.1f; 04114 04115 t->num.increment = t->snap[1]; 04116 } 04117 04118 static void headerBoneSize(TransInfo *t, float vec[3], char *str) 04119 { 04120 char tvec[60]; 04121 if (hasNumInput(&t->num)) { 04122 outputNumInput(&(t->num), tvec); 04123 } 04124 else { 04125 sprintf(&tvec[0], "%.4f", vec[0]); 04126 sprintf(&tvec[20], "%.4f", vec[1]); 04127 sprintf(&tvec[40], "%.4f", vec[2]); 04128 } 04129 04130 /* hmm... perhaps the y-axis values don't need to be shown? */ 04131 if (t->con.mode & CON_APPLY) { 04132 if (t->num.idx_max == 0) 04133 sprintf(str, "ScaleB: %s%s %s", &tvec[0], t->con.text, t->proptext); 04134 else 04135 sprintf(str, "ScaleB: %s : %s : %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext); 04136 } 04137 else { 04138 sprintf(str, "ScaleB X: %s Y: %s Z: %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext); 04139 } 04140 } 04141 04142 static void ElementBoneSize(TransInfo *t, TransData *td, float mat[3][3]) 04143 { 04144 float tmat[3][3], smat[3][3], oldy; 04145 float sizemat[3][3]; 04146 04147 mul_m3_m3m3(smat, mat, td->mtx); 04148 mul_m3_m3m3(tmat, td->smtx, smat); 04149 04150 if (t->con.applySize) { 04151 t->con.applySize(t, td, tmat); 04152 } 04153 04154 /* we've tucked the scale in loc */ 04155 oldy= td->iloc[1]; 04156 size_to_mat3( sizemat,td->iloc); 04157 mul_m3_m3m3(tmat, tmat, sizemat); 04158 mat3_to_size( td->loc,tmat); 04159 td->loc[1]= oldy; 04160 } 04161 04162 int BoneSize(TransInfo *t, const int mval[2]) 04163 { 04164 TransData *td = t->data; 04165 float size[3], mat[3][3]; 04166 float ratio; 04167 int i; 04168 char str[60]; 04169 04170 // TRANSFORM_FIX_ME MOVE TO MOUSE INPUT 04171 /* for manipulator, center handle, the scaling can't be done relative to center */ 04172 if( (t->flag & T_USES_MANIPULATOR) && t->con.mode==0) 04173 { 04174 ratio = 1.0f - ((t->imval[0] - mval[0]) + (t->imval[1] - mval[1]))/100.0f; 04175 } 04176 else 04177 { 04178 ratio = t->values[0]; 04179 } 04180 04181 size[0] = size[1] = size[2] = ratio; 04182 04183 snapGrid(t, size); 04184 04185 if (hasNumInput(&t->num)) { 04186 applyNumInput(&t->num, size); 04187 constraintNumInput(t, size); 04188 } 04189 04190 size_to_mat3( mat,size); 04191 04192 if (t->con.applySize) { 04193 t->con.applySize(t, NULL, mat); 04194 } 04195 04196 copy_m3_m3(t->mat, mat); // used in manipulator 04197 04198 headerBoneSize(t, size, str); 04199 04200 for(i = 0 ; i < t->total; i++, td++) { 04201 if (td->flag & TD_NOACTION) 04202 break; 04203 04204 if (td->flag & TD_SKIP) 04205 continue; 04206 04207 ElementBoneSize(t, td, mat); 04208 } 04209 04210 recalcData(t); 04211 04212 ED_area_headerprint(t->sa, str); 04213 04214 return 1; 04215 } 04216 04217 04218 /* ******************** EditBone envelope *************** */ 04219 04220 void initBoneEnvelope(TransInfo *t) 04221 { 04222 t->mode = TFM_BONE_ENVELOPE; 04223 t->transform = BoneEnvelope; 04224 04225 initMouseInputMode(t, &t->mouse, INPUT_SPRING); 04226 04227 t->idx_max = 0; 04228 t->num.idx_max = 0; 04229 t->snap[0] = 0.0f; 04230 t->snap[1] = 0.1f; 04231 t->snap[2] = t->snap[1] * 0.1f; 04232 04233 t->num.increment = t->snap[1]; 04234 04235 t->flag |= T_NO_CONSTRAINT|T_NO_PROJECT; 04236 } 04237 04238 int BoneEnvelope(TransInfo *t, const int UNUSED(mval[2])) 04239 { 04240 TransData *td = t->data; 04241 float ratio; 04242 int i; 04243 char str[50]; 04244 04245 ratio = t->values[0]; 04246 04247 snapGrid(t, &ratio); 04248 04249 applyNumInput(&t->num, &ratio); 04250 04251 /* header print for NumInput */ 04252 if (hasNumInput(&t->num)) { 04253 char c[20]; 04254 04255 outputNumInput(&(t->num), c); 04256 sprintf(str, "Envelope: %s", c); 04257 } 04258 else { 04259 sprintf(str, "Envelope: %3f", ratio); 04260 } 04261 04262 for(i = 0 ; i < t->total; i++, td++) { 04263 if (td->flag & TD_NOACTION) 04264 break; 04265 04266 if (td->flag & TD_SKIP) 04267 continue; 04268 04269 if (td->val) { 04270 /* if the old/original value was 0.0f, then just use ratio */ 04271 if (td->ival) 04272 *td->val= td->ival*ratio; 04273 else 04274 *td->val= ratio; 04275 } 04276 } 04277 04278 recalcData(t); 04279 04280 ED_area_headerprint(t->sa, str); 04281 04282 return 1; 04283 } 04284 04285 /* ******************** Edge Slide *************** */ 04286 04287 static int createSlideVerts(TransInfo *t) 04288 { 04289 Mesh *me = t->obedit->data; 04290 EditMesh *em = me->edit_mesh; 04291 EditFace *efa; 04292 EditEdge *eed,*first=NULL,*last=NULL, *temp = NULL; 04293 EditVert *ev, *nearest = NULL; 04294 LinkNode *edgelist = NULL, *vertlist=NULL, *look; 04295 GHash *vertgh; 04296 TransDataSlideVert *tempsv; 04297 int i, j, numsel, numadded=0, timesthrough = 0, vertsel=0; 04298 /* UV correction vars */ 04299 GHash **uvarray= NULL; 04300 SlideData *sld = MEM_callocN(sizeof(*sld), "sld"); 04301 const int uvlay_tot= (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) ? CustomData_number_of_layers(&em->fdata, CD_MTFACE) : 0; 04302 int uvlay_idx; 04303 TransDataSlideUv *slideuvs=NULL, *suv=NULL, *suv_last=NULL; 04304 RegionView3D *v3d = t->ar ? t->ar->regiondata : NULL; /* background mode support */ 04305 float projectMat[4][4]; 04306 float start[3] = {0.0f, 0.0f, 0.0f}, end[3] = {0.0f, 0.0f, 0.0f}; 04307 float vec[3]; 04308 float totvec=0.0; 04309 04310 if (!v3d) { 04311 /*ok, let's try to survive this*/ 04312 unit_m4(projectMat); 04313 } else { 04314 ED_view3d_ob_project_mat_get(v3d, t->obedit, projectMat); 04315 } 04316 04317 numsel =0; 04318 04319 // Get number of selected edges and clear some flags 04320 for(eed=em->edges.first;eed;eed=eed->next) { 04321 eed->f1 = 0; 04322 eed->f2 = 0; 04323 if(eed->f & SELECT) numsel++; 04324 } 04325 04326 for(ev=em->verts.first;ev;ev=ev->next) { 04327 ev->f1 = 0; 04328 } 04329 04330 //Make sure each edge only has 2 faces 04331 // make sure loop doesn't cross face 04332 for(efa=em->faces.first;efa;efa=efa->next) { 04333 int ct = 0; 04334 if(efa->e1->f & SELECT) { 04335 ct++; 04336 efa->e1->f1++; 04337 if(efa->e1->f1 > 2) { 04338 //BKE_report(op->reports, RPT_ERROR, "3+ face edge"); 04339 MEM_freeN(sld); 04340 return 0; 04341 } 04342 } 04343 if(efa->e2->f & SELECT) { 04344 ct++; 04345 efa->e2->f1++; 04346 if(efa->e2->f1 > 2) { 04347 //BKE_report(op->reports, RPT_ERROR, "3+ face edge"); 04348 MEM_freeN(sld); 04349 return 0; 04350 } 04351 } 04352 if(efa->e3->f & SELECT) { 04353 ct++; 04354 efa->e3->f1++; 04355 if(efa->e3->f1 > 2) { 04356 //BKE_report(op->reports, RPT_ERROR, "3+ face edge"); 04357 MEM_freeN(sld); 04358 return 0; 04359 } 04360 } 04361 if(efa->e4 && efa->e4->f & SELECT) { 04362 ct++; 04363 efa->e4->f1++; 04364 if(efa->e4->f1 > 2) { 04365 //BKE_report(op->reports, RPT_ERROR, "3+ face edge"); 04366 MEM_freeN(sld); 04367 return 0; 04368 } 04369 } 04370 // Make sure loop is not 2 edges of same face 04371 if(ct > 1) { 04372 //BKE_report(op->reports, RPT_ERROR, "Loop crosses itself"); 04373 MEM_freeN(sld); 04374 return 0; 04375 } 04376 } 04377 04378 // Get # of selected verts 04379 for(ev=em->verts.first;ev;ev=ev->next) { 04380 if(ev->f & SELECT) vertsel++; 04381 } 04382 04383 // Test for multiple segments 04384 if(vertsel > numsel+1) { 04385 //BKE_report(op->reports, RPT_ERROR, "Please choose a single edge loop"); 04386 MEM_freeN(sld); 04387 return 0; 04388 } 04389 04390 // Get the edgeloop in order - mark f1 with SELECT once added 04391 for(eed=em->edges.first;eed;eed=eed->next) { 04392 if((eed->f & SELECT) && !(eed->f1 & SELECT)) { 04393 // If this is the first edge added, just put it in 04394 if(!edgelist) { 04395 BLI_linklist_prepend(&edgelist,eed); 04396 numadded++; 04397 first = eed; 04398 last = eed; 04399 eed->f1 = SELECT; 04400 } else { 04401 if(editedge_getSharedVert(eed, last)) { 04402 BLI_linklist_append(&edgelist,eed); 04403 eed->f1 = SELECT; 04404 numadded++; 04405 last = eed; 04406 } else if(editedge_getSharedVert(eed, first)) { 04407 BLI_linklist_prepend(&edgelist,eed); 04408 eed->f1 = SELECT; 04409 numadded++; 04410 first = eed; 04411 } 04412 } 04413 } 04414 if(eed->next == NULL && numadded != numsel) { 04415 eed=em->edges.first; 04416 timesthrough++; 04417 } 04418 04419 // It looks like there was an unexpected case - Hopefully should not happen 04420 if(timesthrough >= numsel*2) { 04421 BLI_linklist_free(edgelist,NULL); 04422 //BKE_report(op->reports, RPT_ERROR, "Could not order loop"); 04423 MEM_freeN(sld); 04424 return 0; 04425 } 04426 } 04427 04428 // Put the verts in order in a linklist 04429 look = edgelist; 04430 while(look) { 04431 eed = look->link; 04432 if(!vertlist) { 04433 if(look->next) { 04434 temp = look->next->link; 04435 04436 //This is the first entry takes care of extra vert 04437 if(eed->v1 != temp->v1 && eed->v1 != temp->v2) { 04438 BLI_linklist_append(&vertlist,eed->v1); 04439 eed->v1->f1 = 1; 04440 } else { 04441 BLI_linklist_append(&vertlist,eed->v2); 04442 eed->v2->f1 = 1; 04443 } 04444 } else { 04445 //This is the case that we only have 1 edge 04446 BLI_linklist_append(&vertlist,eed->v1); 04447 eed->v1->f1 = 1; 04448 } 04449 } 04450 // for all the entries 04451 if(eed->v1->f1 != 1) { 04452 BLI_linklist_append(&vertlist,eed->v1); 04453 eed->v1->f1 = 1; 04454 } else if(eed->v2->f1 != 1) { 04455 BLI_linklist_append(&vertlist,eed->v2); 04456 eed->v2->f1 = 1; 04457 } 04458 look = look->next; 04459 } 04460 04461 // populate the SlideVerts 04462 04463 vertgh = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "createSlideVerts gh"); 04464 look = vertlist; 04465 while(look) { 04466 i=0; 04467 j=0; 04468 ev = look->link; 04469 tempsv = (struct TransDataSlideVert*)MEM_mallocN(sizeof(struct TransDataSlideVert),"SlideVert"); 04470 tempsv->up = NULL; 04471 tempsv->down = NULL; 04472 tempsv->origvert.co[0] = ev->co[0]; 04473 tempsv->origvert.co[1] = ev->co[1]; 04474 tempsv->origvert.co[2] = ev->co[2]; 04475 tempsv->origvert.no[0] = ev->no[0]; 04476 tempsv->origvert.no[1] = ev->no[1]; 04477 tempsv->origvert.no[2] = ev->no[2]; 04478 // i is total edges that vert is on 04479 // j is total selected edges that vert is on 04480 04481 for(eed=em->edges.first;eed;eed=eed->next) { 04482 if(eed->v1 == ev || eed->v2 == ev) { 04483 i++; 04484 if(eed->f & SELECT) { 04485 j++; 04486 } 04487 } 04488 } 04489 // If the vert is in the middle of an edge loop, it touches 2 selected edges and 2 unselected edges 04490 if(i == 4 && j == 2) { 04491 for(eed=em->edges.first;eed;eed=eed->next) { 04492 if(editedge_containsVert(eed, ev)) { 04493 if(!(eed->f & SELECT)) { 04494 if(!tempsv->up) { 04495 tempsv->up = eed; 04496 } else if (!(tempsv->down)) { 04497 tempsv->down = eed; 04498 } 04499 } 04500 } 04501 } 04502 } 04503 // If it is on the end of the loop, it touches 1 selected and as least 2 more unselected 04504 if(i >= 3 && j == 1) { 04505 for(eed=em->edges.first;eed;eed=eed->next) { 04506 if(editedge_containsVert(eed, ev) && eed->f & SELECT) { 04507 for(efa = em->faces.first;efa;efa=efa->next) { 04508 if(editface_containsEdge(efa, eed)) { 04509 if(editedge_containsVert(efa->e1, ev) && efa->e1 != eed) { 04510 if(!tempsv->up) { 04511 tempsv->up = efa->e1; 04512 } else if (!(tempsv->down)) { 04513 tempsv->down = efa->e1; 04514 } 04515 } 04516 if(editedge_containsVert(efa->e2, ev) && efa->e2 != eed) { 04517 if(!tempsv->up) { 04518 tempsv->up = efa->e2; 04519 } else if (!(tempsv->down)) { 04520 tempsv->down = efa->e2; 04521 } 04522 } 04523 if(editedge_containsVert(efa->e3, ev) && efa->e3 != eed) { 04524 if(!tempsv->up) { 04525 tempsv->up = efa->e3; 04526 } else if (!(tempsv->down)) { 04527 tempsv->down = efa->e3; 04528 } 04529 } 04530 if(efa->e4) { 04531 if(editedge_containsVert(efa->e4, ev) && efa->e4 != eed) { 04532 if(!tempsv->up) { 04533 tempsv->up = efa->e4; 04534 } else if (!(tempsv->down)) { 04535 tempsv->down = efa->e4; 04536 } 04537 } 04538 } 04539 04540 } 04541 } 04542 } 04543 } 04544 } 04545 if(i > 4 && j == 2) { 04546 BLI_ghash_free(vertgh, NULL, (GHashValFreeFP)MEM_freeN); 04547 BLI_linklist_free(vertlist,NULL); 04548 BLI_linklist_free(edgelist,NULL); 04549 return 0; 04550 } 04551 BLI_ghash_insert(vertgh,ev,tempsv); 04552 04553 look = look->next; 04554 } 04555 04556 // make sure the UPs and DOWNs are 'faceloops' 04557 // Also find the nearest slidevert to the cursor 04558 04559 look = vertlist; 04560 nearest = NULL; 04561 while(look) { 04562 tempsv = BLI_ghash_lookup(vertgh,(EditVert*)look->link); 04563 04564 if(!tempsv->up || !tempsv->down) { 04565 //BKE_report(op->reports, RPT_ERROR, "Missing rails"); 04566 BLI_ghash_free(vertgh, NULL, (GHashValFreeFP)MEM_freeN); 04567 BLI_linklist_free(vertlist,NULL); 04568 BLI_linklist_free(edgelist,NULL); 04569 return 0; 04570 } 04571 04572 if(me->drawflag & ME_DRAWEXTRA_EDGELEN) { 04573 if(!(tempsv->up->f & SELECT)) { 04574 tempsv->up->f |= SELECT; 04575 tempsv->up->f2 |= 16; 04576 } else { 04577 tempsv->up->f2 |= ~16; 04578 } 04579 if(!(tempsv->down->f & SELECT)) { 04580 tempsv->down->f |= SELECT; 04581 tempsv->down->f2 |= 16; 04582 } else { 04583 tempsv->down->f2 |= ~16; 04584 } 04585 } 04586 04587 if(look->next != NULL) { 04588 TransDataSlideVert *sv; 04589 04590 ev = (EditVert*)look->next->link; 04591 sv = BLI_ghash_lookup(vertgh, ev); 04592 04593 if(sv) { 04594 float co[3], co2[3], tvec[3]; 04595 04596 ev = (EditVert*)look->link; 04597 04598 if(!sharesFace(em, tempsv->up,sv->up)) { 04599 EditEdge *swap; 04600 swap = sv->up; 04601 sv->up = sv->down; 04602 sv->down = swap; 04603 } 04604 04605 if (v3d) { 04606 ED_view3d_project_float(t->ar, tempsv->up->v1->co, co, projectMat); 04607 ED_view3d_project_float(t->ar, tempsv->up->v2->co, co2, projectMat); 04608 } 04609 04610 if (ev == tempsv->up->v1) { 04611 sub_v3_v3v3(tvec, co, co2); 04612 } else { 04613 sub_v3_v3v3(tvec, co2, co); 04614 } 04615 04616 add_v3_v3(start, tvec); 04617 04618 if (v3d) { 04619 ED_view3d_project_float(t->ar, tempsv->down->v1->co, co, projectMat); 04620 ED_view3d_project_float(t->ar, tempsv->down->v2->co, co2, projectMat); 04621 } 04622 04623 if (ev == tempsv->down->v1) { 04624 sub_v3_v3v3(tvec, co2, co); 04625 } else { 04626 sub_v3_v3v3(tvec, co, co2); 04627 } 04628 04629 add_v3_v3(end, tvec); 04630 04631 totvec += 1.0f; 04632 nearest = (EditVert*)look->link; 04633 } 04634 } 04635 04636 04637 04638 look = look->next; 04639 } 04640 04641 add_v3_v3(start, end); 04642 mul_v3_fl(start, 0.5f*(1.0f/totvec)); 04643 copy_v3_v3(vec, start); 04644 start[0] = t->mval[0]; 04645 start[1] = t->mval[1]; 04646 add_v3_v3v3(end, start, vec); 04647 04648 04649 /* Ensure minimum screen distance, when looking top down on edge loops */ 04650 #define EDGE_SLIDE_MIN 30 04651 if (len_squared_v2v2(start, end) < (EDGE_SLIDE_MIN * EDGE_SLIDE_MIN)) { 04652 if(ABS(start[0]-end[0]) + ABS(start[1]-end[1]) < 4.0f) { 04653 /* even more exceptional case, points are ontop of each other */ 04654 end[0]= start[0]; 04655 end[1]= start[1] + EDGE_SLIDE_MIN; 04656 } 04657 else { 04658 sub_v2_v2(end, start); 04659 normalize_v2(end); 04660 mul_v2_fl(end, EDGE_SLIDE_MIN); 04661 add_v2_v2(end, start); 04662 } 04663 } 04664 #undef EDGE_SLIDE_MIN 04665 04666 04667 sld->start[0] = (int) start[0]; 04668 sld->start[1] = (int) start[1]; 04669 sld->end[0] = (int) end[0]; 04670 sld->end[1] = (int) end[1]; 04671 04672 if (uvlay_tot) { 04673 int maxnum = 0; 04674 04675 uvarray = MEM_callocN( uvlay_tot * sizeof(GHash *), "SlideUVs Array"); 04676 sld->totuv = uvlay_tot; 04677 suv_last = slideuvs = MEM_callocN( uvlay_tot * (numadded+1) * sizeof(TransDataSlideUv), "SlideUVs"); /* uvLayers * verts */ 04678 suv = NULL; 04679 04680 for (uvlay_idx=0; uvlay_idx<uvlay_tot; uvlay_idx++) { 04681 04682 uvarray[uvlay_idx] = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "createSlideVerts2 gh"); 04683 04684 for(ev=em->verts.first;ev;ev=ev->next) { 04685 ev->tmp.l = 0; 04686 } 04687 look = vertlist; 04688 while(look) { 04689 float *uv_new; 04690 tempsv = BLI_ghash_lookup(vertgh,(EditVert*)look->link); 04691 04692 ev = look->link; 04693 suv = NULL; 04694 for(efa = em->faces.first;efa;efa=efa->next) { 04695 if (ev->tmp.l != -1) { /* test for self, in this case its invalid */ 04696 int k=-1; /* face corner */ 04697 04698 /* Is this vert in the faces corner? */ 04699 if (efa->v1==ev) k=0; 04700 else if (efa->v2==ev) k=1; 04701 else if (efa->v3==ev) k=2; 04702 else if (efa->v4 && efa->v4==ev) k=3; 04703 04704 if (k != -1) { 04705 MTFace *tf = CustomData_em_get_n(&em->fdata, efa->data, CD_MTFACE, uvlay_idx); 04706 EditVert *ev_up, *ev_down; 04707 04708 uv_new = tf->uv[k]; 04709 04710 if (ev->tmp.l) { 04711 if (fabsf(suv->origuv[0]-uv_new[0]) > 0.0001f || fabsf(suv->origuv[1]-uv_new[1]) > 0.0001f) { 04712 ev->tmp.l = -1; /* Tag as invalid */ 04713 BLI_linklist_free(suv->fuv_list,NULL); 04714 suv->fuv_list = NULL; 04715 BLI_ghash_remove(uvarray[uvlay_idx],ev, NULL, NULL); 04716 suv = NULL; 04717 break; 04718 } 04719 } else { 04720 ev->tmp.l = 1; 04721 suv = suv_last; 04722 04723 suv->fuv_list = NULL; 04724 suv->uv_up = suv->uv_down = NULL; 04725 suv->origuv[0] = uv_new[0]; 04726 suv->origuv[1] = uv_new[1]; 04727 04728 BLI_linklist_prepend(&suv->fuv_list, uv_new); 04729 BLI_ghash_insert(uvarray[uvlay_idx],ev,suv); 04730 04731 suv_last++; /* advance to next slide UV */ 04732 maxnum++; 04733 } 04734 04735 /* Now get the uvs along the up or down edge if we can */ 04736 if (suv) { 04737 if (!suv->uv_up) { 04738 ev_up = editedge_getOtherVert(tempsv->up,ev); 04739 if (efa->v1==ev_up) suv->uv_up = tf->uv[0]; 04740 else if (efa->v2==ev_up) suv->uv_up = tf->uv[1]; 04741 else if (efa->v3==ev_up) suv->uv_up = tf->uv[2]; 04742 else if (efa->v4 && efa->v4==ev_up) suv->uv_up = tf->uv[3]; 04743 } 04744 if (!suv->uv_down) { /* if the first face was apart of the up edge, it cant be apart of the down edge */ 04745 ev_down = editedge_getOtherVert(tempsv->down,ev); 04746 if (efa->v1==ev_down) suv->uv_down = tf->uv[0]; 04747 else if (efa->v2==ev_down) suv->uv_down = tf->uv[1]; 04748 else if (efa->v3==ev_down) suv->uv_down = tf->uv[2]; 04749 else if (efa->v4 && efa->v4==ev_down) suv->uv_down = tf->uv[3]; 04750 } 04751 04752 /* Copy the pointers to the face UV's */ 04753 BLI_linklist_prepend(&suv->fuv_list, uv_new); 04754 } 04755 } 04756 } 04757 } 04758 look = look->next; 04759 } 04760 } /* end uv map loop */ 04761 } /* end uvlay_tot */ 04762 04763 sld->uvhash = uvarray; 04764 sld->slideuv = slideuvs; 04765 sld->vhash = vertgh; 04766 sld->nearest = nearest; 04767 sld->vertlist = vertlist; 04768 sld->edgelist = edgelist; 04769 sld->suv_last = suv_last; 04770 sld->uvlay_tot = uvlay_tot; 04771 04772 // we should have enough info now to slide 04773 04774 t->customData = sld; 04775 04776 return 1; 04777 } 04778 04779 void freeSlideVerts(TransInfo *t) 04780 { 04781 TransDataSlideUv *suv; 04782 SlideData *sld = t->customData; 04783 Mesh *me = t->obedit->data; 04784 int uvlay_idx; 04785 04786 if(me->drawflag & ME_DRAWEXTRA_EDGELEN) { 04787 TransDataSlideVert *tempsv; 04788 LinkNode *look = sld->vertlist; 04789 GHash *vertgh = sld->vhash; 04790 while(look) { 04791 tempsv = BLI_ghash_lookup(vertgh,(EditVert*)look->link); 04792 if(tempsv != NULL) { 04793 tempsv->up->f &= !SELECT; 04794 tempsv->down->f &= !SELECT; 04795 } 04796 look = look->next; 04797 } 04798 } 04799 04800 //BLI_ghash_free(edgesgh, freeGHash, NULL); 04801 BLI_ghash_free(sld->vhash, NULL, (GHashValFreeFP)MEM_freeN); 04802 BLI_linklist_free(sld->vertlist, NULL); 04803 BLI_linklist_free(sld->edgelist, NULL); 04804 04805 if (sld->uvlay_tot) { 04806 for (uvlay_idx=0; uvlay_idx<sld->uvlay_tot; uvlay_idx++) { 04807 BLI_ghash_free(sld->uvhash[uvlay_idx], NULL, NULL); 04808 } 04809 04810 suv = sld->suv_last-1; 04811 while (suv >= sld->slideuv) { 04812 if (suv->fuv_list) { 04813 BLI_linklist_free(suv->fuv_list,NULL); 04814 } 04815 suv--; 04816 } 04817 04818 MEM_freeN(sld->slideuv); 04819 MEM_freeN(sld->uvhash); 04820 } 04821 04822 MEM_freeN(sld); 04823 t->customData = NULL; 04824 } 04825 04826 void initEdgeSlide(TransInfo *t) 04827 { 04828 SlideData *sld; 04829 04830 t->mode = TFM_EDGE_SLIDE; 04831 t->transform = EdgeSlide; 04832 04833 if(!createSlideVerts(t)) { 04834 t->state= TRANS_CANCEL; 04835 return; 04836 } 04837 04838 sld = t->customData; 04839 04840 if (!sld) 04841 return; 04842 04843 t->customFree = freeSlideVerts; 04844 04845 /* set custom point first if you want value to be initialized by init */ 04846 setCustomPoints(t, &t->mouse, sld->end, sld->start); 04847 initMouseInputMode(t, &t->mouse, INPUT_CUSTOM_RATIO); 04848 04849 t->idx_max = 0; 04850 t->num.idx_max = 0; 04851 t->snap[0] = 0.0f; 04852 t->snap[1] = 0.1f; 04853 t->snap[2] = t->snap[1] * 0.1f; 04854 04855 t->num.increment = t->snap[1]; 04856 04857 t->flag |= T_NO_CONSTRAINT|T_NO_PROJECT; 04858 } 04859 04860 static int doEdgeSlide(TransInfo *t, float perc) 04861 { 04862 SlideData *sld = t->customData; 04863 EditVert *ev, *nearest = sld->nearest; 04864 EditVert *centerVert, *upVert, *downVert; 04865 LinkNode *vertlist=sld->vertlist, *look; 04866 GHash *vertgh = sld->vhash; 04867 TransDataSlideVert *tempsv; 04868 float len; 04869 int prop=1, flip=0; 04870 /* UV correction vars */ 04871 GHash **uvarray= sld->uvhash; 04872 const int uvlay_tot= sld->uvlay_tot; 04873 int uvlay_idx; 04874 TransDataSlideUv *suv; 04875 float uv_tmp[2]; 04876 LinkNode *fuv_link; 04877 04878 tempsv = BLI_ghash_lookup(vertgh,nearest); 04879 04880 centerVert = editedge_getSharedVert(tempsv->up, tempsv->down); 04881 upVert = editedge_getOtherVert(tempsv->up, centerVert); 04882 downVert = editedge_getOtherVert(tempsv->down, centerVert); 04883 04884 len = MIN2(perc, len_v3v3(upVert->co,downVert->co)); 04885 len = MAX2(len, 0); 04886 04887 //Adjust Edgeloop 04888 if(prop) { 04889 look = vertlist; 04890 while(look) { 04891 EditVert *tempev; 04892 ev = look->link; 04893 tempsv = BLI_ghash_lookup(vertgh,ev); 04894 04895 tempev = editedge_getOtherVert((perc>=0)?tempsv->up:tempsv->down, ev); 04896 interp_v3_v3v3(ev->co, tempsv->origvert.co, tempev->co, fabs(perc)); 04897 04898 if (uvlay_tot) { 04899 for (uvlay_idx=0; uvlay_idx<uvlay_tot; uvlay_idx++) { 04900 suv = BLI_ghash_lookup( uvarray[uvlay_idx], ev ); 04901 if (suv && suv->fuv_list && suv->uv_up && suv->uv_down) { 04902 interp_v2_v2v2(uv_tmp, suv->origuv, (perc>=0)?suv->uv_up:suv->uv_down, fabs(perc)); 04903 fuv_link = suv->fuv_list; 04904 while (fuv_link) { 04905 copy_v2_v2(((float *)fuv_link->link), uv_tmp); 04906 fuv_link = fuv_link->next; 04907 } 04908 } 04909 } 04910 } 04911 04912 look = look->next; 04913 } 04914 } 04915 else { 04916 //Non prop code 04917 look = vertlist; 04918 while(look) { 04919 float newlen, edgelen; 04920 ev = look->link; 04921 tempsv = BLI_ghash_lookup(vertgh,ev); 04922 edgelen = len_v3v3(editedge_getOtherVert(tempsv->up,ev)->co,editedge_getOtherVert(tempsv->down,ev)->co); 04923 newlen = (edgelen != 0.0f)? (len / edgelen): 0.0f; 04924 if(newlen > 1.0f) {newlen = 1.0;} 04925 if(newlen < 0.0f) {newlen = 0.0;} 04926 if(flip == 0) { 04927 interp_v3_v3v3(ev->co, editedge_getOtherVert(tempsv->down,ev)->co, editedge_getOtherVert(tempsv->up,ev)->co, fabs(newlen)); 04928 if (uvlay_tot) { 04929 /* dont do anything if no UVs */ 04930 for (uvlay_idx=0; uvlay_idx<uvlay_tot; uvlay_idx++) { 04931 suv = BLI_ghash_lookup( uvarray[uvlay_idx], ev ); 04932 if (suv && suv->fuv_list && suv->uv_up && suv->uv_down) { 04933 interp_v2_v2v2(uv_tmp, suv->uv_down, suv->uv_up, fabs(newlen)); 04934 fuv_link = suv->fuv_list; 04935 while (fuv_link) { 04936 copy_v2_v2(((float *)fuv_link->link), uv_tmp); 04937 fuv_link = fuv_link->next; 04938 } 04939 } 04940 } 04941 } 04942 } else{ 04943 interp_v3_v3v3(ev->co, editedge_getOtherVert(tempsv->up,ev)->co, editedge_getOtherVert(tempsv->down,ev)->co, fabs(newlen)); 04944 04945 if (uvlay_tot) { 04946 /* dont do anything if no UVs */ 04947 for (uvlay_idx=0; uvlay_idx<uvlay_tot; uvlay_idx++) { 04948 suv = BLI_ghash_lookup( uvarray[uvlay_idx], ev ); 04949 if (suv && suv->fuv_list && suv->uv_up && suv->uv_down) { 04950 interp_v2_v2v2(uv_tmp, suv->uv_up, suv->uv_down, fabs(newlen)); 04951 fuv_link = suv->fuv_list; 04952 while (fuv_link) { 04953 copy_v2_v2(((float *)fuv_link->link), uv_tmp); 04954 fuv_link = fuv_link->next; 04955 } 04956 } 04957 } 04958 } 04959 } 04960 look = look->next; 04961 } 04962 04963 } 04964 04965 return 1; 04966 } 04967 04968 int EdgeSlide(TransInfo *t, const int UNUSED(mval[2])) 04969 { 04970 char str[50]; 04971 float final; 04972 04973 final = t->values[0]; 04974 04975 snapGrid(t, &final); 04976 04977 /* only do this so out of range values are not displayed */ 04978 CLAMP(final, -1.0f, 1.0f); 04979 04980 if (hasNumInput(&t->num)) { 04981 char c[20]; 04982 04983 applyNumInput(&t->num, &final); 04984 04985 outputNumInput(&(t->num), c); 04986 04987 sprintf(str, "Edge Slide: %s", &c[0]); 04988 } 04989 else { 04990 sprintf(str, "Edge Slide: %.2f", final); 04991 } 04992 04993 CLAMP(final, -1.0f, 1.0f); 04994 04995 /*do stuff here*/ 04996 if (t->customData) 04997 doEdgeSlide(t, final); 04998 else { 04999 strcpy(str, "Invalid Edge Selection"); 05000 t->state = TRANS_CANCEL; 05001 } 05002 05003 recalcData(t); 05004 05005 ED_area_headerprint(t->sa, str); 05006 05007 return 1; 05008 } 05009 05010 /* ******************** EditBone roll *************** */ 05011 05012 void initBoneRoll(TransInfo *t) 05013 { 05014 t->mode = TFM_BONE_ROLL; 05015 t->transform = BoneRoll; 05016 05017 initMouseInputMode(t, &t->mouse, INPUT_ANGLE); 05018 05019 t->idx_max = 0; 05020 t->num.idx_max = 0; 05021 t->snap[0] = 0.0f; 05022 t->snap[1] = (float)((5.0/180)*M_PI); 05023 t->snap[2] = t->snap[1] * 0.2f; 05024 05025 t->num.increment = 1.0f; 05026 05027 t->flag |= T_NO_CONSTRAINT|T_NO_PROJECT; 05028 } 05029 05030 int BoneRoll(TransInfo *t, const int UNUSED(mval[2])) 05031 { 05032 TransData *td = t->data; 05033 int i; 05034 char str[50]; 05035 05036 float final; 05037 05038 final = t->values[0]; 05039 05040 snapGrid(t, &final); 05041 05042 if (hasNumInput(&t->num)) { 05043 char c[20]; 05044 05045 applyNumInput(&t->num, &final); 05046 05047 outputNumInput(&(t->num), c); 05048 05049 sprintf(str, "Roll: %s", &c[0]); 05050 05051 final = DEG2RADF(final); 05052 } 05053 else { 05054 sprintf(str, "Roll: %.2f", RAD2DEGF(final)); 05055 } 05056 05057 /* set roll values */ 05058 for (i = 0; i < t->total; i++, td++) { 05059 if (td->flag & TD_NOACTION) 05060 break; 05061 05062 if (td->flag & TD_SKIP) 05063 continue; 05064 05065 *(td->val) = td->ival - final; 05066 } 05067 05068 recalcData(t); 05069 05070 ED_area_headerprint(t->sa, str); 05071 05072 return 1; 05073 } 05074 05075 /* ************************** BAKE TIME ******************* */ 05076 05077 void initBakeTime(TransInfo *t) 05078 { 05079 t->transform = BakeTime; 05080 initMouseInputMode(t, &t->mouse, INPUT_NONE); 05081 05082 t->idx_max = 0; 05083 t->num.idx_max = 0; 05084 t->snap[0] = 0.0f; 05085 t->snap[1] = 1.0f; 05086 t->snap[2] = t->snap[1] * 0.1f; 05087 05088 t->num.increment = t->snap[1]; 05089 } 05090 05091 int BakeTime(TransInfo *t, const int mval[2]) 05092 { 05093 TransData *td = t->data; 05094 float time; 05095 int i; 05096 char str[50]; 05097 05098 float fac = 0.1f; 05099 05100 if(t->mouse.precision) { 05101 /* calculate ratio for shiftkey pos, and for total, and blend these for precision */ 05102 time= (float)(t->center2d[0] - t->mouse.precision_mval[0]) * fac; 05103 time+= 0.1f*((float)(t->center2d[0]*fac - mval[0]) -time); 05104 } 05105 else { 05106 time = (float)(t->center2d[0] - mval[0])*fac; 05107 } 05108 05109 snapGrid(t, &time); 05110 05111 applyNumInput(&t->num, &time); 05112 05113 /* header print for NumInput */ 05114 if (hasNumInput(&t->num)) { 05115 char c[20]; 05116 05117 outputNumInput(&(t->num), c); 05118 05119 if (time >= 0.0f) 05120 sprintf(str, "Time: +%s %s", c, t->proptext); 05121 else 05122 sprintf(str, "Time: %s %s", c, t->proptext); 05123 } 05124 else { 05125 /* default header print */ 05126 if (time >= 0.0f) 05127 sprintf(str, "Time: +%.3f %s", time, t->proptext); 05128 else 05129 sprintf(str, "Time: %.3f %s", time, t->proptext); 05130 } 05131 05132 for(i = 0 ; i < t->total; i++, td++) { 05133 if (td->flag & TD_NOACTION) 05134 break; 05135 05136 if (td->flag & TD_SKIP) 05137 continue; 05138 05139 if (td->val) { 05140 *td->val = td->ival + time * td->factor; 05141 if (td->ext->size && *td->val < *td->ext->size) *td->val = *td->ext->size; 05142 if (td->ext->quat && *td->val > *td->ext->quat) *td->val = *td->ext->quat; 05143 } 05144 } 05145 05146 recalcData(t); 05147 05148 ED_area_headerprint(t->sa, str); 05149 05150 return 1; 05151 } 05152 05153 /* ************************** MIRROR *************************** */ 05154 05155 void initMirror(TransInfo *t) 05156 { 05157 t->transform = Mirror; 05158 initMouseInputMode(t, &t->mouse, INPUT_NONE); 05159 05160 t->flag |= T_NULL_ONE; 05161 if (!t->obedit) { 05162 t->flag |= T_NO_ZERO; 05163 } 05164 } 05165 05166 int Mirror(TransInfo *t, const int UNUSED(mval[2])) 05167 { 05168 TransData *td; 05169 float size[3], mat[3][3]; 05170 int i; 05171 char str[200]; 05172 05173 /* 05174 * OPTIMISATION: 05175 * This still recalcs transformation on mouse move 05176 * while it should only recalc on constraint change 05177 * */ 05178 05179 /* if an axis has been selected */ 05180 if (t->con.mode & CON_APPLY) { 05181 size[0] = size[1] = size[2] = -1; 05182 05183 size_to_mat3( mat,size); 05184 05185 if (t->con.applySize) { 05186 t->con.applySize(t, NULL, mat); 05187 } 05188 05189 sprintf(str, "Mirror%s", t->con.text); 05190 05191 for(i = 0, td=t->data; i < t->total; i++, td++) { 05192 if (td->flag & TD_NOACTION) 05193 break; 05194 05195 if (td->flag & TD_SKIP) 05196 continue; 05197 05198 ElementResize(t, td, mat); 05199 } 05200 05201 recalcData(t); 05202 05203 ED_area_headerprint(t->sa, str); 05204 } 05205 else 05206 { 05207 size[0] = size[1] = size[2] = 1; 05208 05209 size_to_mat3( mat,size); 05210 05211 for(i = 0, td=t->data; i < t->total; i++, td++) { 05212 if (td->flag & TD_NOACTION) 05213 break; 05214 05215 if (td->flag & TD_SKIP) 05216 continue; 05217 05218 ElementResize(t, td, mat); 05219 } 05220 05221 recalcData(t); 05222 05223 if(t->flag & T_2D_EDIT) 05224 ED_area_headerprint(t->sa, "Select a mirror axis (X, Y)"); 05225 else 05226 ED_area_headerprint(t->sa, "Select a mirror axis (X, Y, Z)"); 05227 } 05228 05229 return 1; 05230 } 05231 05232 /* ************************** ALIGN *************************** */ 05233 05234 void initAlign(TransInfo *t) 05235 { 05236 t->flag |= T_NO_CONSTRAINT; 05237 05238 t->transform = Align; 05239 05240 initMouseInputMode(t, &t->mouse, INPUT_NONE); 05241 } 05242 05243 int Align(TransInfo *t, const int UNUSED(mval[2])) 05244 { 05245 TransData *td = t->data; 05246 float center[3]; 05247 int i; 05248 05249 /* saving original center */ 05250 copy_v3_v3(center, t->center); 05251 05252 for(i = 0 ; i < t->total; i++, td++) 05253 { 05254 float mat[3][3], invmat[3][3]; 05255 05256 if (td->flag & TD_NOACTION) 05257 break; 05258 05259 if (td->flag & TD_SKIP) 05260 continue; 05261 05262 /* around local centers */ 05263 if (t->flag & (T_OBJECT|T_POSE)) { 05264 copy_v3_v3(t->center, td->center); 05265 } 05266 else { 05267 if(t->settings->selectmode & SCE_SELECT_FACE) { 05268 copy_v3_v3(t->center, td->center); 05269 } 05270 } 05271 05272 invert_m3_m3(invmat, td->axismtx); 05273 05274 mul_m3_m3m3(mat, t->spacemtx, invmat); 05275 05276 ElementRotation(t, td, mat, t->around); 05277 } 05278 05279 /* restoring original center */ 05280 copy_v3_v3(t->center, center); 05281 05282 recalcData(t); 05283 05284 ED_area_headerprint(t->sa, "Align"); 05285 05286 return 1; 05287 } 05288 05289 /* ************************** SEQ SLIDE *************************** */ 05290 05291 void initSeqSlide(TransInfo *t) 05292 { 05293 t->transform = SeqSlide; 05294 05295 initMouseInputMode(t, &t->mouse, INPUT_VECTOR); 05296 05297 t->idx_max = 1; 05298 t->num.flag = 0; 05299 t->num.idx_max = t->idx_max; 05300 05301 t->snap[0] = 0.0f; 05302 t->snap[1] = floor(t->scene->r.frs_sec / t->scene->r.frs_sec_base); 05303 t->snap[2] = 10.0f; 05304 05305 t->num.increment = t->snap[1]; 05306 } 05307 05308 static void headerSeqSlide(TransInfo *t, float val[2], char *str) 05309 { 05310 char tvec[60]; 05311 05312 if (hasNumInput(&t->num)) { 05313 outputNumInput(&(t->num), tvec); 05314 } 05315 else { 05316 sprintf(&tvec[0], "%.0f, %.0f", val[0], val[1]); 05317 } 05318 05319 sprintf(str, "Sequence Slide: %s%s", &tvec[0], t->con.text); 05320 } 05321 05322 static void applySeqSlide(TransInfo *t, float val[2]) 05323 { 05324 TransData *td = t->data; 05325 int i; 05326 05327 for(i = 0 ; i < t->total; i++, td++) { 05328 float tvec[2]; 05329 05330 if (td->flag & TD_NOACTION) 05331 break; 05332 05333 if (td->flag & TD_SKIP) 05334 continue; 05335 05336 copy_v2_v2(tvec, val); 05337 05338 mul_v2_fl(tvec, td->factor); 05339 05340 td->loc[0] = td->iloc[0] + tvec[0]; 05341 td->loc[1] = td->iloc[1] + tvec[1]; 05342 } 05343 } 05344 05345 int SeqSlide(TransInfo *t, const int UNUSED(mval[2])) 05346 { 05347 char str[200]; 05348 05349 if (t->con.mode & CON_APPLY) { 05350 float pvec[3] = {0.0f, 0.0f, 0.0f}; 05351 float tvec[3]; 05352 t->con.applyVec(t, NULL, t->values, tvec, pvec); 05353 copy_v3_v3(t->values, tvec); 05354 } 05355 else { 05356 snapGrid(t, t->values); 05357 applyNumInput(&t->num, t->values); 05358 } 05359 05360 t->values[0] = floor(t->values[0] + 0.5f); 05361 t->values[1] = floor(t->values[1] + 0.5f); 05362 05363 headerSeqSlide(t, t->values, str); 05364 applySeqSlide(t, t->values); 05365 05366 recalcData(t); 05367 05368 ED_area_headerprint(t->sa, str); 05369 05370 return 1; 05371 } 05372 05373 /* ************************** ANIM EDITORS - TRANSFORM TOOLS *************************** */ 05374 05375 /* ---------------- Special Helpers for Various Settings ------------- */ 05376 05377 05378 /* This function returns the snapping 'mode' for Animation Editors only 05379 * We cannot use the standard snapping due to NLA-strip scaling complexities. 05380 */ 05381 // XXX these modifier checks should be keymappable 05382 static short getAnimEdit_SnapMode(TransInfo *t) 05383 { 05384 short autosnap= SACTSNAP_OFF; 05385 05386 if (t->spacetype == SPACE_ACTION) { 05387 SpaceAction *saction= (SpaceAction *)t->sa->spacedata.first; 05388 05389 if (saction) 05390 autosnap= saction->autosnap; 05391 } 05392 else if (t->spacetype == SPACE_IPO) { 05393 SpaceIpo *sipo= (SpaceIpo *)t->sa->spacedata.first; 05394 05395 if (sipo) 05396 autosnap= sipo->autosnap; 05397 } 05398 else if (t->spacetype == SPACE_NLA) { 05399 SpaceNla *snla= (SpaceNla *)t->sa->spacedata.first; 05400 05401 if (snla) 05402 autosnap= snla->autosnap; 05403 } 05404 else { 05405 autosnap= SACTSNAP_OFF; 05406 } 05407 05408 /* toggle autosnap on/off 05409 * - when toggling on, prefer nearest frame over 1.0 frame increments 05410 */ 05411 if (t->modifiers & MOD_SNAP_INVERT) { 05412 if (autosnap) 05413 autosnap= SACTSNAP_OFF; 05414 else 05415 autosnap= SACTSNAP_FRAME; 05416 } 05417 05418 return autosnap; 05419 } 05420 05421 /* This function is used for testing if an Animation Editor is displaying 05422 * its data in frames or seconds (and the data needing to be edited as such). 05423 * Returns 1 if in seconds, 0 if in frames 05424 */ 05425 static short getAnimEdit_DrawTime(TransInfo *t) 05426 { 05427 short drawtime; 05428 05429 if (t->spacetype == SPACE_ACTION) { 05430 SpaceAction *saction= (SpaceAction *)t->sa->spacedata.first; 05431 05432 drawtime = (saction->flag & SACTION_DRAWTIME)? 1 : 0; 05433 } 05434 else if (t->spacetype == SPACE_NLA) { 05435 SpaceNla *snla= (SpaceNla *)t->sa->spacedata.first; 05436 05437 drawtime = (snla->flag & SNLA_DRAWTIME)? 1 : 0; 05438 } 05439 else if (t->spacetype == SPACE_IPO) { 05440 SpaceIpo *sipo= (SpaceIpo *)t->sa->spacedata.first; 05441 05442 drawtime = (sipo->flag & SIPO_DRAWTIME)? 1 : 0; 05443 } 05444 else { 05445 drawtime = 0; 05446 } 05447 05448 return drawtime; 05449 } 05450 05451 05452 /* This function is used by Animation Editor specific transform functions to do 05453 * the Snap Keyframe to Nearest Frame/Marker 05454 */ 05455 static void doAnimEdit_SnapFrame(TransInfo *t, TransData *td, TransData2D *td2d, AnimData *adt, short autosnap) 05456 { 05457 /* snap key to nearest frame? */ 05458 if (autosnap == SACTSNAP_FRAME) { 05459 05460 #if 0 /* 'doTime' disabled for now */ 05461 05462 const Scene *scene= t->scene; 05463 const short doTime= 0; //getAnimEdit_DrawTime(t); // NOTE: this works, but may be confusing behaviour given the option's label, hence disabled 05464 const double secf= FPS; 05465 #endif 05466 double val; 05467 05468 /* convert frame to nla-action time (if needed) */ 05469 if (adt) 05470 val= BKE_nla_tweakedit_remap(adt, *(td->val), NLATIME_CONVERT_MAP); 05471 else 05472 val= *(td->val); 05473 05474 #if 0 /* 'doTime' disabled for now */ 05475 05476 /* do the snapping to nearest frame/second */ 05477 if (doTime) { 05478 val= (float)( floor((val/secf) + 0.5f) * secf ); 05479 } 05480 else 05481 #endif 05482 { 05483 val= floorf(val+0.5f); 05484 } 05485 05486 /* convert frame out of nla-action time */ 05487 if (adt) 05488 *(td->val)= BKE_nla_tweakedit_remap(adt, val, NLATIME_CONVERT_UNMAP); 05489 else 05490 *(td->val)= val; 05491 } 05492 /* snap key to nearest marker? */ 05493 else if (autosnap == SACTSNAP_MARKER) { 05494 float val; 05495 05496 /* convert frame to nla-action time (if needed) */ 05497 if (adt) 05498 val= BKE_nla_tweakedit_remap(adt, *(td->val), NLATIME_CONVERT_MAP); 05499 else 05500 val= *(td->val); 05501 05502 /* snap to nearest marker */ 05503 // TODO: need some more careful checks for where data comes from 05504 val= (float)ED_markers_find_nearest_marker_time(&t->scene->markers, val); 05505 05506 /* convert frame out of nla-action time */ 05507 if (adt) 05508 *(td->val)= BKE_nla_tweakedit_remap(adt, val, NLATIME_CONVERT_UNMAP); 05509 else 05510 *(td->val)= val; 05511 } 05512 05513 /* if the handles are to be moved too (as side-effect of keyframes moving, to keep the general effect) 05514 * offset them by the same amount so that the general angles are maintained (i.e. won't change while 05515 * handles are free-to-roam and keyframes are snap-locked) 05516 */ 05517 if ((td->flag & TD_MOVEHANDLE1) && td2d->h1) { 05518 td2d->h1[0] = td2d->ih1[0] + *td->val - td->ival; 05519 } 05520 if ((td->flag & TD_MOVEHANDLE2) && td2d->h2) { 05521 td2d->h2[0] = td2d->ih2[0] + *td->val - td->ival; 05522 } 05523 } 05524 05525 /* ----------------- Translation ----------------------- */ 05526 05527 void initTimeTranslate(TransInfo *t) 05528 { 05529 /* this tool is only really available in the Action Editor... */ 05530 if (!ELEM(t->spacetype, SPACE_ACTION, SPACE_SEQ)) { 05531 t->state = TRANS_CANCEL; 05532 } 05533 05534 t->mode = TFM_TIME_TRANSLATE; 05535 t->transform = TimeTranslate; 05536 05537 initMouseInputMode(t, &t->mouse, INPUT_NONE); 05538 05539 /* num-input has max of (n-1) */ 05540 t->idx_max = 0; 05541 t->num.flag = 0; 05542 t->num.idx_max = t->idx_max; 05543 05544 /* initialise snap like for everything else */ 05545 t->snap[0] = 0.0f; 05546 t->snap[1] = t->snap[2] = 1.0f; 05547 05548 t->num.increment = t->snap[1]; 05549 } 05550 05551 static void headerTimeTranslate(TransInfo *t, char *str) 05552 { 05553 char tvec[60]; 05554 05555 /* if numeric input is active, use results from that, otherwise apply snapping to result */ 05556 if (hasNumInput(&t->num)) { 05557 outputNumInput(&(t->num), tvec); 05558 } 05559 else { 05560 const Scene *scene = t->scene; 05561 const short autosnap= getAnimEdit_SnapMode(t); 05562 const short doTime = getAnimEdit_DrawTime(t); 05563 const double secf= FPS; 05564 float val = t->values[0]; 05565 05566 /* apply snapping + frame->seconds conversions */ 05567 if (autosnap == SACTSNAP_STEP) { 05568 if (doTime) 05569 val= floor((double)val/secf + 0.5f); 05570 else 05571 val= floor(val + 0.5f); 05572 } 05573 else { 05574 if (doTime) 05575 val= (float)((double)val / secf); 05576 } 05577 05578 if (autosnap == SACTSNAP_FRAME) 05579 sprintf(&tvec[0], "%d.00 (%.4f)", (int)val, val); 05580 else 05581 sprintf(&tvec[0], "%.4f", val); 05582 } 05583 05584 sprintf(str, "DeltaX: %s", &tvec[0]); 05585 } 05586 05587 static void applyTimeTranslate(TransInfo *t, float UNUSED(sval)) 05588 { 05589 TransData *td = t->data; 05590 TransData2D *td2d = t->data2d; 05591 Scene *scene = t->scene; 05592 int i; 05593 05594 const short doTime= getAnimEdit_DrawTime(t); 05595 const double secf= FPS; 05596 05597 const short autosnap= getAnimEdit_SnapMode(t); 05598 05599 float deltax, val /* , valprev */; 05600 05601 /* it doesn't matter whether we apply to t->data or t->data2d, but t->data2d is more convenient */ 05602 for (i = 0 ; i < t->total; i++, td++, td2d++) { 05603 /* it is assumed that td->extra is a pointer to the AnimData, 05604 * whose active action is where this keyframe comes from 05605 * (this is only valid when not in NLA) 05606 */ 05607 AnimData *adt= (t->spacetype != SPACE_NLA) ? td->extra : NULL; 05608 05609 /* valprev = *td->val; */ /* UNUSED */ 05610 05611 /* check if any need to apply nla-mapping */ 05612 if (adt && t->spacetype != SPACE_SEQ) { 05613 deltax = t->values[0]; 05614 05615 if (autosnap == SACTSNAP_STEP) { 05616 if (doTime) 05617 deltax= (float)( floor((deltax/secf) + 0.5f) * secf ); 05618 else 05619 deltax= (float)( floor(deltax + 0.5f) ); 05620 } 05621 05622 val = BKE_nla_tweakedit_remap(adt, td->ival, NLATIME_CONVERT_MAP); 05623 val += deltax; 05624 *(td->val) = BKE_nla_tweakedit_remap(adt, val, NLATIME_CONVERT_UNMAP); 05625 } 05626 else { 05627 deltax = val = t->values[0]; 05628 05629 if (autosnap == SACTSNAP_STEP) { 05630 if (doTime) 05631 val= (float)( floor((deltax/secf) + 0.5f) * secf ); 05632 else 05633 val= (float)( floor(val + 0.5f) ); 05634 } 05635 05636 *(td->val) = td->ival + val; 05637 } 05638 05639 /* apply nearest snapping */ 05640 doAnimEdit_SnapFrame(t, td, td2d, adt, autosnap); 05641 } 05642 } 05643 05644 int TimeTranslate(TransInfo *t, const int mval[2]) 05645 { 05646 View2D *v2d = (View2D *)t->view; 05647 float cval[2], sval[2]; 05648 char str[200]; 05649 05650 /* calculate translation amount from mouse movement - in 'time-grid space' */ 05651 UI_view2d_region_to_view(v2d, mval[0], mval[0], &cval[0], &cval[1]); 05652 UI_view2d_region_to_view(v2d, t->imval[0], t->imval[0], &sval[0], &sval[1]); 05653 05654 /* we only need to calculate effect for time (applyTimeTranslate only needs that) */ 05655 t->values[0] = cval[0] - sval[0]; 05656 05657 /* handle numeric-input stuff */ 05658 t->vec[0] = t->values[0]; 05659 applyNumInput(&t->num, &t->vec[0]); 05660 t->values[0] = t->vec[0]; 05661 headerTimeTranslate(t, str); 05662 05663 applyTimeTranslate(t, sval[0]); 05664 05665 recalcData(t); 05666 05667 ED_area_headerprint(t->sa, str); 05668 05669 return 1; 05670 } 05671 05672 /* ----------------- Time Slide ----------------------- */ 05673 05674 void initTimeSlide(TransInfo *t) 05675 { 05676 /* this tool is only really available in the Action Editor... */ 05677 if (t->spacetype == SPACE_ACTION) { 05678 SpaceAction *saction= (SpaceAction *)t->sa->spacedata.first; 05679 05680 /* set flag for drawing stuff */ 05681 saction->flag |= SACTION_MOVING; 05682 } else { 05683 t->state = TRANS_CANCEL; 05684 } 05685 05686 05687 t->mode = TFM_TIME_SLIDE; 05688 t->transform = TimeSlide; 05689 t->flag |= T_FREE_CUSTOMDATA; 05690 05691 initMouseInputMode(t, &t->mouse, INPUT_NONE); 05692 05693 /* num-input has max of (n-1) */ 05694 t->idx_max = 0; 05695 t->num.flag = 0; 05696 t->num.idx_max = t->idx_max; 05697 05698 /* initialise snap like for everything else */ 05699 t->snap[0] = 0.0f; 05700 t->snap[1] = t->snap[2] = 1.0f; 05701 05702 t->num.increment = t->snap[1]; 05703 } 05704 05705 static void headerTimeSlide(TransInfo *t, float sval, char *str) 05706 { 05707 char tvec[60]; 05708 05709 if (hasNumInput(&t->num)) { 05710 outputNumInput(&(t->num), tvec); 05711 } 05712 else { 05713 float minx= *((float *)(t->customData)); 05714 float maxx= *((float *)(t->customData) + 1); 05715 float cval= t->values[0]; 05716 float val; 05717 05718 val= 2.0f*(cval-sval) / (maxx-minx); 05719 CLAMP(val, -1.0f, 1.0f); 05720 05721 sprintf(&tvec[0], "%.4f", val); 05722 } 05723 05724 sprintf(str, "TimeSlide: %s", &tvec[0]); 05725 } 05726 05727 static void applyTimeSlide(TransInfo *t, float sval) 05728 { 05729 TransData *td = t->data; 05730 int i; 05731 05732 float minx= *((float *)(t->customData)); 05733 float maxx= *((float *)(t->customData) + 1); 05734 05735 /* set value for drawing black line */ 05736 if (t->spacetype == SPACE_ACTION) { 05737 SpaceAction *saction= (SpaceAction *)t->sa->spacedata.first; 05738 float cvalf = t->values[0]; 05739 05740 saction->timeslide= cvalf; 05741 } 05742 05743 /* it doesn't matter whether we apply to t->data or t->data2d, but t->data2d is more convenient */ 05744 for (i = 0 ; i < t->total; i++, td++) { 05745 /* it is assumed that td->extra is a pointer to the AnimData, 05746 * whose active action is where this keyframe comes from 05747 * (this is only valid when not in NLA) 05748 */ 05749 AnimData *adt= (t->spacetype != SPACE_NLA) ? td->extra : NULL; 05750 float cval = t->values[0]; 05751 05752 /* apply NLA-mapping to necessary values */ 05753 if (adt) 05754 cval= BKE_nla_tweakedit_remap(adt, cval, NLATIME_CONVERT_UNMAP); 05755 05756 /* only apply to data if in range */ 05757 if ((sval > minx) && (sval < maxx)) { 05758 float cvalc= CLAMPIS(cval, minx, maxx); 05759 float timefac; 05760 05761 /* left half? */ 05762 if (td->ival < sval) { 05763 timefac= (sval - td->ival) / (sval - minx); 05764 *(td->val)= cvalc - timefac * (cvalc - minx); 05765 } 05766 else { 05767 timefac= (td->ival - sval) / (maxx - sval); 05768 *(td->val)= cvalc + timefac * (maxx - cvalc); 05769 } 05770 } 05771 } 05772 } 05773 05774 int TimeSlide(TransInfo *t, const int mval[2]) 05775 { 05776 View2D *v2d = (View2D *)t->view; 05777 float cval[2], sval[2]; 05778 float minx= *((float *)(t->customData)); 05779 float maxx= *((float *)(t->customData) + 1); 05780 char str[200]; 05781 05782 /* calculate mouse co-ordinates */ 05783 UI_view2d_region_to_view(v2d, mval[0], mval[1], &cval[0], &cval[1]); 05784 UI_view2d_region_to_view(v2d, t->imval[0], t->imval[1], &sval[0], &sval[1]); 05785 05786 /* t->values[0] stores cval[0], which is the current mouse-pointer location (in frames) */ 05787 // XXX Need to be able to repeat this 05788 t->values[0] = cval[0]; 05789 05790 /* handle numeric-input stuff */ 05791 t->vec[0] = 2.0f*(cval[0]-sval[0]) / (maxx-minx); 05792 applyNumInput(&t->num, &t->vec[0]); 05793 t->values[0] = (maxx-minx) * t->vec[0] / 2.0f + sval[0]; 05794 05795 headerTimeSlide(t, sval[0], str); 05796 applyTimeSlide(t, sval[0]); 05797 05798 recalcData(t); 05799 05800 ED_area_headerprint(t->sa, str); 05801 05802 return 1; 05803 } 05804 05805 /* ----------------- Scaling ----------------------- */ 05806 05807 void initTimeScale(TransInfo *t) 05808 { 05809 int center[2]; 05810 05811 /* this tool is only really available in the Action Editor 05812 * AND NLA Editor (for strip scaling) 05813 */ 05814 if (ELEM(t->spacetype, SPACE_ACTION, SPACE_NLA) == 0) { 05815 t->state = TRANS_CANCEL; 05816 } 05817 05818 t->mode = TFM_TIME_SCALE; 05819 t->transform = TimeScale; 05820 05821 /* recalculate center2d to use CFRA and mouse Y, since that's 05822 * what is used in time scale */ 05823 t->center[0] = t->scene->r.cfra; 05824 projectIntView(t, t->center, center); 05825 center[1] = t->imval[1]; 05826 05827 /* force a reinit with the center2d used here */ 05828 initMouseInput(t, &t->mouse, center, t->imval); 05829 05830 initMouseInputMode(t, &t->mouse, INPUT_SPRING_FLIP); 05831 05832 t->flag |= T_NULL_ONE; 05833 t->num.flag |= NUM_NULL_ONE; 05834 05835 /* num-input has max of (n-1) */ 05836 t->idx_max = 0; 05837 t->num.flag = 0; 05838 t->num.idx_max = t->idx_max; 05839 05840 /* initialise snap like for everything else */ 05841 t->snap[0] = 0.0f; 05842 t->snap[1] = t->snap[2] = 1.0f; 05843 05844 t->num.increment = t->snap[1]; 05845 } 05846 05847 static void headerTimeScale(TransInfo *t, char *str) 05848 { 05849 char tvec[60]; 05850 05851 if (hasNumInput(&t->num)) 05852 outputNumInput(&(t->num), tvec); 05853 else 05854 sprintf(&tvec[0], "%.4f", t->values[0]); 05855 05856 sprintf(str, "ScaleX: %s", &tvec[0]); 05857 } 05858 05859 static void applyTimeScale(TransInfo *t) 05860 { 05861 Scene *scene = t->scene; 05862 TransData *td = t->data; 05863 TransData2D *td2d = t->data2d; 05864 int i; 05865 05866 const short autosnap= getAnimEdit_SnapMode(t); 05867 const short doTime= getAnimEdit_DrawTime(t); 05868 const double secf= FPS; 05869 05870 05871 for (i = 0 ; i < t->total; i++, td++, td2d++) { 05872 /* it is assumed that td->extra is a pointer to the AnimData, 05873 * whose active action is where this keyframe comes from 05874 * (this is only valid when not in NLA) 05875 */ 05876 AnimData *adt= (t->spacetype != SPACE_NLA) ? td->extra : NULL; 05877 float startx= CFRA; 05878 float fac= t->values[0]; 05879 05880 if (autosnap == SACTSNAP_STEP) { 05881 if (doTime) 05882 fac= (float)( floor(fac/secf + 0.5f) * secf ); 05883 else 05884 fac= (float)( floor(fac + 0.5f) ); 05885 } 05886 05887 /* check if any need to apply nla-mapping */ 05888 if (adt) 05889 startx= BKE_nla_tweakedit_remap(adt, startx, NLATIME_CONVERT_UNMAP); 05890 05891 /* now, calculate the new value */ 05892 *(td->val) = td->ival - startx; 05893 *(td->val) *= fac; 05894 *(td->val) += startx; 05895 05896 /* apply nearest snapping */ 05897 doAnimEdit_SnapFrame(t, td, td2d, adt, autosnap); 05898 } 05899 } 05900 05901 int TimeScale(TransInfo *t, const int UNUSED(mval[2])) 05902 { 05903 char str[200]; 05904 05905 /* handle numeric-input stuff */ 05906 t->vec[0] = t->values[0]; 05907 applyNumInput(&t->num, &t->vec[0]); 05908 t->values[0] = t->vec[0]; 05909 headerTimeScale(t, str); 05910 05911 applyTimeScale(t); 05912 05913 recalcData(t); 05914 05915 ED_area_headerprint(t->sa, str); 05916 05917 return 1; 05918 } 05919 05920 /* ************************************ */ 05921 05922 void BIF_TransformSetUndo(const char *UNUSED(str)) 05923 { 05924 // TRANSFORM_FIX_ME 05925 //Trans.undostr= str; 05926 }