Blender V2.61 - r43446

transform.c

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