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