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