bbb5e5149423fca29d74cad84443f5f2a0564dbe
[blender.git] / source / blender / src / transform.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. The Blender
10  * Foundation also sells licenses for use in proprietary software under
11  * the Blender License.  See http://www.blender.org/BL/ for information
12  * about this.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  *
23  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24  * All rights reserved.
25  *
26  * The Original Code is: all of this file.
27  *
28  * Contributor(s): none yet.
29  *
30  * ***** END GPL/BL DUAL LICENSE BLOCK *****
31  */
32
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <math.h>
37
38 #ifdef HAVE_CONFIG_H
39 #include <config.h>
40 #endif
41
42 #ifndef WIN32
43 #include <unistd.h>
44 #else
45 #include <io.h>
46 #endif
47
48 #include "MEM_guardedalloc.h"
49
50 #include "DNA_armature_types.h"
51 #include "DNA_action_types.h"  /* for some special action-editor settings */
52 #include "DNA_constraint_types.h"
53 #include "DNA_ipo_types.h"              /* some silly ipo flag  */
54 #include "DNA_listBase.h"
55 #include "DNA_meshdata_types.h"
56 #include "DNA_mesh_types.h"
57 #include "DNA_object_types.h"
58 #include "DNA_scene_types.h"            /* PET modes                    */
59 #include "DNA_screen_types.h"   /* area dimensions              */
60 #include "DNA_scene_types.h"
61 #include "DNA_screen_types.h"
62 #include "DNA_texture_types.h"
63 #include "DNA_userdef_types.h"
64 #include "DNA_view3d_types.h"
65 #include "DNA_space_types.h"
66
67 #include "BIF_editview.h"               /* arrows_move_cursor   */
68 #include "BIF_gl.h"
69 #include "BIF_glutil.h"
70 #include "BIF_mywindow.h"
71 #include "BIF_resources.h"
72 #include "BIF_screen.h"
73 #include "BIF_space.h"                  /* undo                                 */
74 #include "BIF_toets.h"                  /* persptoetsen                 */
75 #include "BIF_mywindow.h"               /* warp_pointer                 */
76 #include "BIF_toolbox.h"                        /* notice                               */
77 #include "BIF_editmesh.h"
78 #include "BIF_editsima.h"
79 #include "BIF_editparticle.h"
80 #include "BIF_drawimage.h"              /* uvco_to_areaco_noclip */
81 #include "BIF_editaction.h" 
82
83 #include "BKE_action.h" /* get_action_frame */
84 #include "BKE_constraint.h"
85 #include "BKE_global.h"
86 #include "BKE_utildefines.h"
87 #include "BKE_bad_level_calls.h"/* popmenu and error    */
88 #include "BKE_particle.h"
89
90 #include "BSE_drawipo.h"
91 #include "BSE_editnla_types.h"  /* for NLAWIDTH */
92 #include "BSE_editaction_types.h"
93 #include "BSE_time.h"
94 #include "BSE_view.h"
95
96 #include "BLI_arithb.h"
97 #include "BLI_blenlib.h"
98 #include "BLI_editVert.h"
99
100 #include "PIL_time.h"                   /* sleep                                */
101
102 #include "blendef.h"
103
104 #include "mydevice.h"
105
106 #include "transform.h"
107
108 /* GLOBAL VARIABLE THAT SHOULD MOVED TO SCREEN MEMBER OR SOMETHING  */
109 TransInfo Trans = {TFM_INIT, 0};        // enforce init on first usage
110
111 /******************************** Helper functions ************************************/
112
113 /* GLOBAL Wrapper Fonctions */
114
115 void BIF_drawSnap()
116 {
117         drawSnapping(&Trans);
118 }
119
120 /* ************************** Dashed help line **************************** */
121
122
123 /* bad frontbuffer call... because it is used in transform after force_draw() */
124 static void helpline(TransInfo *t, float *vec)
125 {
126         float vecrot[3], cent[2];
127         short mval[2];
128         
129         VECCOPY(vecrot, vec);
130         if(t->flag & T_EDIT) {
131                 Object *ob=G.obedit;
132                 if(ob) Mat4MulVecfl(ob->obmat, vecrot);
133         }
134         else if(t->flag & T_POSE) {
135                 Object *ob=t->poseobj;
136                 if(ob) Mat4MulVecfl(ob->obmat, vecrot);
137         }
138         
139         getmouseco_areawin(mval);
140         projectFloatView(t, vecrot, cent);      // no overflow in extreme cases
141         if(cent[0]!=IS_CLIPPED) {
142                 persp(PERSP_WIN);
143                 
144                 glDrawBuffer(GL_FRONT);
145                 
146                 BIF_ThemeColor(TH_WIRE);
147                 
148                 setlinestyle(3);
149                 glBegin(GL_LINE_STRIP); 
150                 glVertex2sv(mval); 
151                 glVertex2fv(cent); 
152                 glEnd();
153                 setlinestyle(0);
154                 
155                 persp(PERSP_VIEW);
156                 bglFlush(); // flush display for frontbuffer
157                 glDrawBuffer(GL_BACK);
158         }
159 }
160
161 /* *********************** TransSpace ************************** */
162  
163 void BIF_clearTransformOrientation(void)
164 {
165         ListBase *transform_spaces = &G.scene->transform_spaces;
166         BLI_freelistN(transform_spaces);
167         
168         if (G.vd->twmode >= V3D_MANIP_CUSTOM)
169                 G.vd->twmode = V3D_MANIP_GLOBAL;        /* fallback to global   */
170 }
171   
172 void BIF_manageTransformOrientation(int confirm, int set) {
173         int index = -1; 
174         
175         if (G.obedit) {
176                 if (G.obedit->type == OB_MESH)
177                         index = manageMeshSpace(confirm, set);
178         }
179         else {
180                 index = manageObjectSpace(confirm, set);
181         }
182         
183         if (set && index != -1)
184         {
185                 BIF_selectTransformOrientationFromIndex(index);
186         }
187 }
188
189 int manageObjectSpace(int confirm, int set) {
190         Base *base = BASACT;
191
192         if (base == NULL)
193                 return -1;
194
195         if (confirm == 0) {
196                 if (set && pupmenu("Custome Space %t|Add and Use Active Object%x1") != 1) {
197                         return -1;
198                 }
199                 else if (set == 0 && pupmenu("Custome Space %t|Add Active Object%x1") != 1) {
200                         return -1;
201                 }
202         }
203
204         return addObjectSpace(base->object);
205 }
206
207 int manageMeshSpace(int confirm, int set) {
208         EditMesh *em = G.editMesh;
209         float mat[3][3], vec[3] = {0.0f, 0.0f, 1.0f};
210         int index;
211         char name[36] = "";
212
213         if (G.scene->selectmode & SCE_SELECT_VERTEX && G.totvertsel == 1) {
214                 EditVert *eve;
215
216                 if (confirm == 0) {
217                         if (set && pupmenu("Custome Space %t|Add and Use Vertex%x1") != 1) {
218                                 return -1;
219                         }
220                         else if (set == 0 && pupmenu("Custome Space %t|Add Vertex%x1") != 1) {
221                                 return -1;
222                         }
223                 }
224
225                 for(eve = em->verts.first; eve; eve= eve->next) {
226                         if(eve->h == 0 && (eve->f & SELECT)) 
227                                 break;
228                 }
229                 
230                 if (eve == NULL)
231                         return -1;
232
233                 VECCOPY(mat[2], eve->no);
234                 if (Normalize(mat[2]) == 0.0f) {
235                         error("Cannot use vertex with zero-length normal");
236                         return -1;
237                 }
238
239                 strcpy(name, "Vertex");
240         }
241         else if(G.scene->selectmode & SCE_SELECT_EDGE && G.totedgesel == 1) {
242                 EditEdge *eed;
243
244                 if (confirm == 0) {
245                         if (set && pupmenu("Custome Space %t|Add and Use Edge%x1") != 1) {
246                                 return -1;
247                         }
248                         else if (set == 0 && pupmenu("Custome Space %t|Add Edge%x1") != 1) {
249                                 return -1;
250                         }
251                 }
252
253                 for(eed = em->edges.first; eed; eed= eed->next) {
254                         if(eed->h == 0 && (eed->f & SELECT))
255                                 break;
256                 }
257
258                 if (eed == NULL)
259                         return -1;
260
261                 VecSubf(mat[2], eed->v2->co, eed->v1->co);
262                 if (Normalize(mat[2]) == 0.0f) {
263                         error("Cannot use zero-length edges");
264                         return -1;
265                 }
266
267                 strcpy(name, "Edge");
268         }
269         else if(G.scene->selectmode & SCE_SELECT_FACE && G.totfacesel == 1) {
270                 EditFace *efa;
271
272                 if (confirm == 0) {
273                         if (set && pupmenu("Custome Space %t|Add and Use Face%x1") != 1) {
274                                 return -1;
275                         }
276                         else if (set == 0 && pupmenu("Custome Space %t|Add Face%x1") != 1) {
277                                 return -1;
278                         }
279                 }
280
281                 for(efa = em->faces.first; efa; efa= efa->next) {
282                         if(efa->h == 0 && (efa->f & SELECT))
283                                 break;
284                 }
285
286                 if (efa == NULL)
287                         return -1;
288
289                 VECCOPY(mat[2], efa->n);
290                 if (Normalize(mat[2]) == 0.0f) {
291                         error("Cannot use face with zero-length normal");
292                         return -1;
293                 }
294
295                 VecSubf(vec, efa->v2->co, efa->v1->co);
296
297                 strcpy(name, "Face");
298         }
299         else {
300                 notice("You need to select only one vertex, edge or face");
301                 return -1;
302         }
303
304         /* Applying matrix for global space */
305         Mat4Mul3Vecfl(G.obedit->obmat, mat[2]);
306         Mat4Mul3Vecfl(G.obedit->obmat, vec);
307
308         /* Calculating the other axis */
309         
310         Crossf(mat[0], mat[2], vec);
311         if (Normalize(mat[0]) == 0.0f) {
312                 vec[0] = 1.0f;
313                 vec[1] = vec[2] = 0.0f;
314                 Crossf(mat[0], vec, mat[2]);
315         }
316
317         Crossf(mat[1], mat[2], mat[0]);
318
319         Mat3Ortho(mat);
320
321         /* Input name */
322         sbutton(name, 1, 35, "name: ");
323
324         index = addMatrixSpace(mat, name);
325         return index;
326 }
327
328 int addObjectSpace(Object *ob) {
329         float mat[3][3];
330         char name[36] = "";
331
332         Mat3CpyMat4(mat, ob->obmat);
333         Mat3Ortho(mat);
334
335         strncpy(name, ob->id.name+2, 35);
336
337         /* Input name */
338         sbutton(name, 1, 35, "name: ");
339
340         return addMatrixSpace(mat, name);
341 }
342
343 int addMatrixSpace(float mat[3][3], char name[]) {
344         ListBase *transform_spaces = &G.scene->transform_spaces;
345         TransformOrientation *ts;
346         int index = 0;
347
348         /* if name is found in list, reuse that transform space */      
349         for (index = 0, ts = transform_spaces->first; ts; ts = ts->next, index++) {
350                 if (strncmp(ts->name, name, 35) == 0) {
351                         break;
352                 }
353         }
354
355         /* if not, create a new one */
356         if (ts == NULL)
357         {
358                 ts = MEM_callocN(sizeof(TransformOrientation), "UserTransSpace from matrix");
359                 BLI_addtail(transform_spaces, ts);
360                 strncpy(ts->name, name, 35);
361         }
362
363         /* copy matrix into transform space */
364         Mat3CpyMat3(ts->mat, mat);
365
366         BIF_undo_push("Add/Update Transform Orientation");
367         
368         return index;
369 }
370
371 void BIF_removeTransformOrientation(TransformOrientation *target) {
372         ListBase *transform_spaces = &G.scene->transform_spaces;
373         TransformOrientation *ts = transform_spaces->first;
374         int selected_index = (G.vd->twmode - V3D_MANIP_CUSTOM);
375         int i;
376         
377         for (i = 0, ts = transform_spaces->first; ts; ts = ts->next, i++) {
378                 if (ts == target) {
379                         if (selected_index == i) {
380                                 G.vd->twmode = V3D_MANIP_GLOBAL;        /* fallback to global   */
381                         }
382                         else if (selected_index > i)
383                                 G.vd->twmode--;
384
385                         BLI_freelinkN(transform_spaces, ts);
386                         break;
387                 }
388         }
389         BIF_undo_push("Remove Transform Orientation");
390 }
391
392 void BIF_selectTransformOrientation(TransformOrientation *target) {
393         ListBase *transform_spaces = &G.scene->transform_spaces;
394         TransformOrientation *ts = transform_spaces->first;
395         int i;
396         
397         for (i = 0, ts = transform_spaces->first; ts; ts = ts->next, i++) {
398                 if (ts == target) {
399                         G.vd->twmode = V3D_MANIP_CUSTOM + i;
400                         break;
401                 }
402         }
403 }
404
405 void BIF_selectTransformOrientationFromIndex(int index) {
406         G.vd->twmode = V3D_MANIP_CUSTOM + index;
407 }
408
409 char * BIF_menustringTransformOrientation() {
410         char menu[] = "Orientation%t|Global%x0|Local%x1|Normal%x2|View%x3";
411         ListBase *transform_spaces = &G.scene->transform_spaces;
412         TransformOrientation *ts;
413         int i = V3D_MANIP_CUSTOM;
414         char *str_menu, *p;
415         
416         
417         str_menu = MEM_callocN(strlen(menu) + 40 * BIF_countTransformOrientation(), "UserTransSpace from matrix");
418         p = str_menu;
419         
420         p += sprintf(str_menu, "%s", menu);
421         
422         for (ts = transform_spaces->first; ts; ts = ts->next) {
423                 p += sprintf(p, "|%s%%x%d", ts->name, i++);
424         }
425         
426         return str_menu;
427 }
428
429 int BIF_countTransformOrientation() {
430         ListBase *transform_spaces = &G.scene->transform_spaces;
431         TransformOrientation *ts;
432         int count = 0;
433
434         for (ts = transform_spaces->first; ts; ts = ts->next) {
435                 count++;
436         }
437         
438         return count;
439 }
440
441 void applyTransformOrientation() {
442         TransInfo *t = BIF_GetTransInfo();
443         TransformOrientation *ts;
444         int selected_index = (G.vd->twmode - V3D_MANIP_CUSTOM);
445         int i;
446         
447         if (selected_index >= 0) {
448                 for (i = 0, ts = G.scene->transform_spaces.first; ts; ts = ts->next, i++) {
449                         if (selected_index == i) {
450                                 strcpy(t->spacename, ts->name);
451                                 Mat3CpyMat3(t->spacemtx, ts->mat);
452                                 Mat4CpyMat3(G.vd->twmat, ts->mat);
453                                 break;
454                         }
455                 }
456         }
457 }
458   
459 /* ************************** INPUT FROM MOUSE *************************** */
460
461 float InputScaleRatio(TransInfo *t, short mval[2]) {
462         float ratio, dx, dy;
463         if(t->flag & T_SHIFT_MOD) {
464                 /* calculate ratio for shiftkey pos, and for total, and blend these for precision */
465                 dx = (float)(t->center2d[0] - t->shiftmval[0]);
466                 dy = (float)(t->center2d[1] - t->shiftmval[1]);
467                 ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
468                 
469                 dx= (float)(t->center2d[0] - mval[0]);
470                 dy= (float)(t->center2d[1] - mval[1]);
471                 ratio+= 0.1f*(float)(sqrt( dx*dx + dy*dy)/t->fac -ratio);
472         }
473         else {
474                 dx = (float)(t->center2d[0] - mval[0]);
475                 dy = (float)(t->center2d[1] - mval[1]);
476                 ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
477         }
478         return ratio;
479 }
480
481 float InputHorizontalRatio(TransInfo *t, short mval[2]) {
482         float x, pad;
483
484         pad = curarea->winx / 10;
485
486         if (t->flag & T_SHIFT_MOD) {
487                 /* deal with Shift key by adding motion / 10 to motion before shift press */
488                 x = t->shiftmval[0] + (float)(mval[0] - t->shiftmval[0]) / 10.0f;
489         }
490         else {
491                 x = mval[0];
492         }
493         return (x - pad) / (curarea->winx - 2 * pad);
494 }
495
496 float InputHorizontalAbsolute(TransInfo *t, short mval[2]) {
497         float vec[3];
498         if(t->flag & T_SHIFT_MOD) {
499                 float dvec[3];
500                 /* calculate the main translation and the precise one separate */
501                 convertViewVec(t, dvec, (short)(mval[0] - t->shiftmval[0]), (short)(mval[1] - t->shiftmval[1]));
502                 VecMulf(dvec, 0.1f);
503                 convertViewVec(t, t->vec, (short)(t->shiftmval[0] - t->imval[0]), (short)(t->shiftmval[1] - t->imval[1]));
504                 VecAddf(t->vec, t->vec, dvec);
505         }
506         else {
507                 convertViewVec(t, t->vec, (short)(mval[0] - t->imval[0]), (short)(mval[1] - t->imval[1]));
508         }
509         Projf(vec, t->vec, t->viewinv[0]);
510         return Inpf(t->viewinv[0], vec) * 2.0f;
511 }
512
513 float InputVerticalRatio(TransInfo *t, short mval[2]) {
514         float y, pad;
515
516         pad = curarea->winy / 10;
517
518         if (t->flag & T_SHIFT_MOD) {
519                 /* deal with Shift key by adding motion / 10 to motion before shift press */
520                 y = t->shiftmval[1] + (float)(mval[1] - t->shiftmval[1]) / 10.0f;
521         }
522         else {
523                 y = mval[0];
524         }
525         return (y - pad) / (curarea->winy - 2 * pad);
526 }
527
528 float InputVerticalAbsolute(TransInfo *t, short mval[2]) {
529         float vec[3];
530         if(t->flag & T_SHIFT_MOD) {
531                 float dvec[3];
532                 /* calculate the main translation and the precise one separate */
533                 convertViewVec(t, dvec, (short)(mval[0] - t->shiftmval[0]), (short)(mval[1] - t->shiftmval[1]));
534                 VecMulf(dvec, 0.1f);
535                 convertViewVec(t, t->vec, (short)(t->shiftmval[0] - t->imval[0]), (short)(t->shiftmval[1] - t->imval[1]));
536                 VecAddf(t->vec, t->vec, dvec);
537         }
538         else {
539                 convertViewVec(t, t->vec, (short)(mval[0] - t->imval[0]), (short)(mval[1] - t->imval[1]));
540         }
541         Projf(vec, t->vec, t->viewinv[1]);
542         return Inpf(t->viewinv[1], vec) * 2.0f;
543 }
544
545 /* ************************** SPACE DEPENDANT CODE **************************** */
546
547 void setTransformViewMatrices(TransInfo *t)
548 {
549         if(t->spacetype==SPACE_VIEW3D) {
550                 Mat4CpyMat4(t->viewmat, G.vd->viewmat);
551                 Mat4CpyMat4(t->viewinv, G.vd->viewinv);
552                 Mat4CpyMat4(t->persmat, G.vd->persmat);
553                 Mat4CpyMat4(t->persinv, G.vd->persinv);
554                 t->persp= G.vd->persp;
555         }
556         else {
557                 Mat4One(t->viewmat);
558                 Mat4One(t->viewinv);
559                 Mat4One(t->persmat);
560                 Mat4One(t->persinv);
561                 t->persp = 0; // ortho
562         }
563         
564         calculateCenter2D(t);
565         
566 }
567
568 void convertViewVec(TransInfo *t, float *vec, short dx, short dy)
569 {
570         if (t->spacetype==SPACE_VIEW3D) {
571                 window_to_3d(vec, dx, dy);
572         }
573         else if(t->spacetype==SPACE_IMAGE) {
574                 float divx, divy, aspx, aspy;
575                 
576                 transform_aspect_ratio_tface_uv(&aspx, &aspy);
577                 
578                 divx= G.v2d->mask.xmax-G.v2d->mask.xmin;
579                 divy= G.v2d->mask.ymax-G.v2d->mask.ymin;
580                 
581                 vec[0]= aspx*(G.v2d->cur.xmax-G.v2d->cur.xmin)*(dx)/divx;
582                 vec[1]= aspy*(G.v2d->cur.ymax-G.v2d->cur.ymin)*(dy)/divy;
583                 vec[2]= 0.0f;
584         }
585         else if(t->spacetype==SPACE_IPO) {
586                 float divx, divy;
587                 
588                 divx= G.v2d->mask.xmax-G.v2d->mask.xmin;
589                 divy= G.v2d->mask.ymax-G.v2d->mask.ymin;
590                 
591                 vec[0]= (G.v2d->cur.xmax-G.v2d->cur.xmin)*(dx) / (divx);
592                 vec[1]= (G.v2d->cur.ymax-G.v2d->cur.ymin)*(dy) / (divy);
593                 vec[2]= 0.0f;
594         }
595 }
596
597 void projectIntView(TransInfo *t, float *vec, int *adr)
598 {
599         if (t->spacetype==SPACE_VIEW3D)
600                 project_int(vec, adr);
601         else if(t->spacetype==SPACE_IMAGE) {
602                 float aspx, aspy, v[2];
603                 
604                 transform_aspect_ratio_tface_uv(&aspx, &aspy);
605                 v[0]= vec[0]/aspx;
606                 v[1]= vec[1]/aspy;
607                 
608                 uvco_to_areaco_noclip(v, adr);
609         }
610         else if(t->spacetype==SPACE_IPO) {
611                 short out[2] = {0.0f, 0.0f};
612                 
613                 ipoco_to_areaco(G.v2d, vec, out);
614                 adr[0]= out[0];
615                 adr[1]= out[1];
616         }
617 }
618
619 void projectFloatView(TransInfo *t, float *vec, float *adr)
620 {
621         if (t->spacetype==SPACE_VIEW3D)
622                 project_float(vec, adr);
623         else if(t->spacetype==SPACE_IMAGE) {
624                 int a[2];
625                 
626                 projectIntView(t, vec, a);
627                 adr[0]= a[0];
628                 adr[1]= a[1];
629         }
630         else if(t->spacetype==SPACE_IPO) {
631                 int a[2];
632                 
633                 projectIntView(t, vec, a);
634                 adr[0]= a[0];
635                 adr[1]= a[1];
636         }
637 }
638
639 void convertVecToDisplayNum(float *vec, float *num)
640 {
641         TransInfo *t= BIF_GetTransInfo();
642
643         VECCOPY(num, vec);
644
645         if ((t->spacetype==SPACE_IMAGE) && (t->mode==TFM_TRANSLATION)) {
646                 float aspx, aspy;
647
648                 if((G.sima->flag & SI_COORDFLOATS)==0) {
649                         int width, height;
650                         transform_width_height_tface_uv(&width, &height);
651
652                         num[0] *= width;
653                         num[1] *= height;
654                 }
655
656                 transform_aspect_ratio_tface_uv(&aspx, &aspy);
657                 num[0] /= aspx;
658                 num[1] /= aspy;
659         }
660 }
661
662 void convertDisplayNumToVec(float *num, float *vec)
663 {
664         TransInfo *t= BIF_GetTransInfo();
665
666         VECCOPY(vec, num);
667
668         if ((t->spacetype==SPACE_IMAGE) && (t->mode==TFM_TRANSLATION)) {
669                 float aspx, aspy;
670
671                 if((G.sima->flag & SI_COORDFLOATS)==0) {
672                         int width, height;
673                         transform_width_height_tface_uv(&width, &height);
674
675                         vec[0] /= width;
676                         vec[1] /= height;
677                 }
678
679                 transform_aspect_ratio_tface_uv(&aspx, &aspy);
680                 vec[0] *= aspx;
681                 vec[1] *= aspy;
682         }
683 }
684
685 static void viewRedrawForce(TransInfo *t)
686 {
687         if (t->spacetype == SPACE_VIEW3D)
688                 force_draw(0);
689         else if (t->spacetype==SPACE_IMAGE) {
690                 if (G.sima->lock) force_draw_plus(SPACE_VIEW3D, 0);
691                 else force_draw(0);
692         }
693         else if (t->spacetype == SPACE_ACTION) {
694                 if (G.saction->lock) {
695                         short context;
696                         
697                         /* we ignore the pointer this function returns (not needed) */
698                         get_action_context(&context);
699                         
700                         if (context == ACTCONT_ACTION)
701                                 force_draw_plus(SPACE_VIEW3D, 0);
702                         else if (context == ACTCONT_SHAPEKEY) 
703                                 force_draw_all(0);
704                         else
705                                 force_draw(0);
706                 }
707                 else {
708                         force_draw(0);
709                 }
710         }
711         else if (t->spacetype == SPACE_NLA) {
712                 if (G.snla->lock)
713                         force_draw_all(0);
714                 else
715                         force_draw(0);
716         }
717         else if (t->spacetype == SPACE_IPO) {
718                 /* update realtime */
719                 if (G.sipo->lock) {
720                         if (G.sipo->blocktype==ID_MA || G.sipo->blocktype==ID_TE)
721                                 force_draw_plus(SPACE_BUTS, 0);
722                         else if (G.sipo->blocktype==ID_CA)
723                                 force_draw_plus(SPACE_VIEW3D, 0);
724                         else if (G.sipo->blocktype==ID_KE)
725                                 force_draw_plus(SPACE_VIEW3D, 0);
726                         else if (G.sipo->blocktype==ID_PO)
727                                 force_draw_plus(SPACE_VIEW3D, 0);
728                         else if (G.sipo->blocktype==ID_OB) 
729                                 force_draw_plus(SPACE_VIEW3D, 0);
730                         else if (G.sipo->blocktype==ID_SEQ) 
731                                 force_draw_plus(SPACE_SEQ, 0);
732                         else 
733                                 force_draw(0);
734                 }
735                 else {
736                         force_draw(0);
737                 }
738         }
739 }
740
741 static void viewRedrawPost(TransInfo *t)
742 {
743         if(t->spacetype==SPACE_VIEW3D) {
744                 allqueue(REDRAWBUTSOBJECT, 0);
745                 allqueue(REDRAWVIEW3D, 0);
746         }
747         else if(t->spacetype==SPACE_IMAGE) {
748                 allqueue(REDRAWIMAGE, 0);
749                 allqueue(REDRAWVIEW3D, 0);
750         }
751         else if(ELEM3(t->spacetype, SPACE_ACTION, SPACE_NLA, SPACE_IPO)) {
752                 allqueue(REDRAWVIEW3D, 0);
753                 allqueue(REDRAWACTION, 0);
754                 allqueue(REDRAWNLA, 0);
755                 allqueue(REDRAWIPO, 0);
756                 allqueue(REDRAWTIME, 0);
757                 allqueue(REDRAWBUTSOBJECT, 0);
758         }
759
760         scrarea_queue_headredraw(curarea);
761 }
762
763 /* ************************** TRANSFORMATIONS **************************** */
764
765 void BIF_selectOrientation() {
766         short val;
767         char *str_menu = BIF_menustringTransformOrientation();
768         val= pupmenu(str_menu);
769         MEM_freeN(str_menu);
770         
771         if(val >= 0) {
772                 G.vd->twmode = val;
773         }
774 }
775
776 static void view_editmove(unsigned short event)
777 {
778         int refresh = 0;
779         /* Regular:   Zoom in */
780         /* Shift:     Scroll up */
781         /* Ctrl:      Scroll right */
782         /* Alt-Shift: Rotate up */
783         /* Alt-Ctrl:  Rotate right */
784         
785         /* only work in 3D window for now
786          * In the end, will have to send to event to a 2D window handler instead
787          */
788         if (Trans.flag & T_2D_EDIT)
789                 return;
790         
791         switch(event) {
792                 case WHEELUPMOUSE:
793                         
794                         if( G.qual & LR_SHIFTKEY ) {
795                                 if( G.qual & LR_ALTKEY ) { 
796                                         G.qual &= ~LR_SHIFTKEY;
797                                         persptoetsen(PAD2);
798                                         G.qual |= LR_SHIFTKEY;
799                                 } else {
800                                         persptoetsen(PAD2);
801                                 }
802                         } else if( G.qual & LR_CTRLKEY ) {
803                                 if( G.qual & LR_ALTKEY ) { 
804                                         G.qual &= ~LR_CTRLKEY;
805                                         persptoetsen(PAD4);
806                                         G.qual |= LR_CTRLKEY;
807                                 } else {
808                                         persptoetsen(PAD4);
809                                 }
810                         } else if(U.uiflag & USER_WHEELZOOMDIR) 
811                                 persptoetsen(PADMINUS);
812                         else
813                                 persptoetsen(PADPLUSKEY);
814                         
815                         refresh = 1;
816                         break;
817                 case WHEELDOWNMOUSE:
818                         if( G.qual & LR_SHIFTKEY ) {
819                                 if( G.qual & LR_ALTKEY ) { 
820                                         G.qual &= ~LR_SHIFTKEY;
821                                         persptoetsen(PAD8);
822                                         G.qual |= LR_SHIFTKEY;
823                                 } else {
824                                         persptoetsen(PAD8);
825                                 }
826                         } else if( G.qual & LR_CTRLKEY ) {
827                                 if( G.qual & LR_ALTKEY ) { 
828                                         G.qual &= ~LR_CTRLKEY;
829                                         persptoetsen(PAD6);
830                                         G.qual |= LR_CTRLKEY;
831                                 } else {
832                                         persptoetsen(PAD6);
833                                 }
834                         } else if(U.uiflag & USER_WHEELZOOMDIR) 
835                                 persptoetsen(PADPLUSKEY);
836                         else
837                                 persptoetsen(PADMINUS);
838                         
839                         refresh = 1;
840                         break;
841         }
842
843         if (refresh)
844                 setTransformViewMatrices(&Trans);
845 }
846
847 void checkFirstTime() {
848         if(Trans.mode==TFM_INIT) {
849                 memset(&Trans, 0, sizeof(TransInfo));
850                 Trans.propsize = 1.0;
851         }
852 }
853
854 static char *transform_to_undostr(TransInfo *t)
855 {
856         switch (t->mode) {
857                 case TFM_TRANSLATION:
858                         return "Translate";
859                 case TFM_ROTATION:
860                         return "Rotate";
861                 case TFM_RESIZE:
862                         return "Scale";
863                 case TFM_TOSPHERE:
864                         return "To Sphere";
865                 case TFM_SHEAR:
866                         return "Shear";
867                 case TFM_WARP:
868                         return "Warp";
869                 case TFM_SHRINKFATTEN:
870                         return "Shrink/Fatten";
871                 case TFM_TILT:
872                         return "Tilt";
873                 case TFM_TRACKBALL:
874                         return "Trackball";
875                 case TFM_PUSHPULL:
876                         return "Push/Pull";
877                 case TFM_CREASE:
878                         return "Crease";
879                 case TFM_BONESIZE:
880                         return "Bone Width";
881                 case TFM_BONE_ENVELOPE:
882                         return "Bone Envelope";
883                 case TFM_TIME_TRANSLATE:
884                         return "Translate Anim. Data";
885                 case TFM_TIME_SCALE:
886                         return "Scale Anim. Data";
887                 case TFM_TIME_SLIDE:
888                         return "Time Slide";
889                 case TFM_BAKE_TIME:
890                         return "Key Time";
891         }
892         return "Transform";
893 }
894
895 /* ************************************************* */
896
897 static void transformEvent(unsigned short event, short val) {
898         float mati[3][3] = {{1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 1.0f}};
899         char cmode = constraintModeToChar(&Trans);
900
901         if (val) {
902                 switch (event){
903                 /* enforce redraw of transform when modifiers are used */
904                 case LEFTCTRLKEY:
905                 case RIGHTCTRLKEY:
906                         Trans.redraw = 1;
907                         break;
908                 case LEFTSHIFTKEY:
909                 case RIGHTSHIFTKEY:
910                         /* shift is modifier for higher resolution transform, works nice to store this mouse position */
911                         getmouseco_areawin(Trans.shiftmval);
912                         Trans.flag |= T_SHIFT_MOD;
913                         Trans.redraw = 1;
914                         break;
915                         
916                 case SPACEKEY:
917                         if ((Trans.spacetype==SPACE_VIEW3D) && (G.qual & LR_ALTKEY)) {
918                                 short mval[2];
919                                 
920                                 getmouseco_sc(mval);
921                                 BIF_selectOrientation();
922                                 calc_manipulator_stats(curarea);
923                                 Mat3CpyMat4(Trans.spacemtx, G.vd->twmat);
924                                 warp_pointer(mval[0], mval[1]);
925                         }
926                         else {
927                                 Trans.state = TRANS_CONFIRM;
928                         }
929                         break;
930                         
931                         
932                 case MIDDLEMOUSE:
933                         if ((Trans.flag & T_NO_CONSTRAINT)==0) {
934                                 /* exception for switching to dolly, or trackball, in camera view */
935                                 if (Trans.flag & T_CAMERA) {
936                                         if (Trans.mode==TFM_TRANSLATION)
937                                                 setLocalConstraint(&Trans, (CON_AXIS2), "along local Z");
938                                         else if (Trans.mode==TFM_ROTATION) {
939                                                 restoreTransObjects(&Trans);
940                                                 initTrackball(&Trans);
941                                         }
942                                 }
943                                 else {
944                                         Trans.flag |= T_MMB_PRESSED;
945                                         if (Trans.con.mode & CON_APPLY) {
946                                                 stopConstraint(&Trans);
947                                         }
948                                         else {
949                                                 if (G.qual & LR_CTRLKEY) {
950                                                         initSelectConstraint(&Trans, Trans.spacemtx);
951                                                 }
952                                                 else {
953                                                         /* bit hackish... but it prevents mmb select to print the orientation from menu */
954                                                         strcpy(Trans.spacename, "global");
955                                                         initSelectConstraint(&Trans, mati);
956                                                 }
957                                                 postSelectConstraint(&Trans);
958                                         }
959                                 }
960                                 Trans.redraw = 1;
961                         }
962                         break;
963                 case ESCKEY:
964                 case RIGHTMOUSE:
965                         Trans.state = TRANS_CANCEL;
966                         break;
967                 case LEFTMOUSE:
968                 case PADENTER:
969                 case RETKEY:
970                         Trans.state = TRANS_CONFIRM;
971                         break;
972                 case GKEY:
973                         /* only switch when... */
974                         if( ELEM3(Trans.mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL) ) { 
975                                 restoreTransObjects(&Trans);
976                                 initTranslation(&Trans);
977                                 Trans.redraw = 1;
978                         }
979                         break;
980                 case SKEY:
981                         /* only switch when... */
982                         if( ELEM3(Trans.mode, TFM_ROTATION, TFM_TRANSLATION, TFM_TRACKBALL) ) { 
983                                 restoreTransObjects(&Trans);
984                                 initResize(&Trans);
985                                 Trans.redraw = 1;
986                         }
987                         break;
988                 case RKEY:
989                         /* only switch when... */
990                         if( ELEM4(Trans.mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION) ) { 
991                                 
992                                 if (Trans.mode == TFM_ROTATION) {
993                                         restoreTransObjects(&Trans);
994                                         initTrackball(&Trans);
995                                 }
996                                 else {
997                                         restoreTransObjects(&Trans);
998                                         initRotation(&Trans);
999                                 }
1000                                 Trans.redraw = 1;
1001                         }
1002                         break;
1003                 case CKEY:
1004                         if (G.qual & LR_ALTKEY) {
1005                                 Trans.flag ^= T_PROP_CONNECTED;
1006                                 sort_trans_data_dist(&Trans);
1007                                 calculatePropRatio(&Trans);
1008                                 Trans.redraw= 1;
1009                         }
1010                         else {
1011                                 stopConstraint(&Trans);
1012                                 Trans.redraw = 1;
1013                         }
1014                         break;
1015                 case XKEY:
1016                         if ((Trans.flag & T_NO_CONSTRAINT)==0) {
1017                                 if (cmode == 'X') {
1018                                         if (Trans.flag & T_2D_EDIT) {
1019                                                 stopConstraint(&Trans);
1020                                         }
1021                                         else {
1022                                                 if (Trans.con.mode & CON_USER) {
1023                                                         stopConstraint(&Trans);
1024                                                 }
1025                                                 else {
1026                                                         if (G.qual == 0)
1027                                                                 setUserConstraint(&Trans, (CON_AXIS0), "along %s X");
1028                                                         else if (G.qual == LR_SHIFTKEY)
1029                                                                 setUserConstraint(&Trans, (CON_AXIS1|CON_AXIS2), "locking %s X");
1030                                                 }
1031                                         }
1032                                 }
1033                                 else {
1034                                         if (Trans.flag & T_2D_EDIT) {
1035                                                 setConstraint(&Trans, mati, (CON_AXIS0), "along X axis");
1036                                         }
1037                                         else {
1038                                                 if (G.qual == 0)
1039                                                         setConstraint(&Trans, mati, (CON_AXIS0), "along global X");
1040                                                 else if (G.qual == LR_SHIFTKEY)
1041                                                         setConstraint(&Trans, mati, (CON_AXIS1|CON_AXIS2), "locking global X");
1042                                         }
1043                                 }
1044                                 Trans.redraw = 1;
1045                         }
1046                         break;
1047                 case YKEY:
1048                         if ((Trans.flag & T_NO_CONSTRAINT)==0) {
1049                                 if (cmode == 'Y') {
1050                                         if (Trans.flag & T_2D_EDIT) {
1051                                                 stopConstraint(&Trans);
1052                                         }
1053                                         else {
1054                                                 if (Trans.con.mode & CON_USER) {
1055                                                         stopConstraint(&Trans);
1056                                                 }
1057                                                 else {
1058                                                         if (G.qual == 0)
1059                                                                 setUserConstraint(&Trans, (CON_AXIS1), "along %s Y");
1060                                                         else if (G.qual == LR_SHIFTKEY)
1061                                                                 setUserConstraint(&Trans, (CON_AXIS0|CON_AXIS2), "locking %s Y");
1062                                                 }
1063                                         }
1064                                 }
1065                                 else {
1066                                         if (Trans.flag & T_2D_EDIT) {
1067                                                 setConstraint(&Trans, mati, (CON_AXIS1), "along Y axis");
1068                                         }
1069                                         else {
1070                                                 if (G.qual == 0)
1071                                                         setConstraint(&Trans, mati, (CON_AXIS1), "along global Y");
1072                                                 else if (G.qual == LR_SHIFTKEY)
1073                                                         setConstraint(&Trans, mati, (CON_AXIS0|CON_AXIS2), "locking global Y");
1074                                         }
1075                                 }
1076                                 Trans.redraw = 1;
1077                         }
1078                         break;
1079                 case ZKEY:
1080                         if ((Trans.flag & T_NO_CONSTRAINT)==0) {
1081                                 if (cmode == 'Z') {
1082                                         if (Trans.con.mode & CON_USER) {
1083                                                 stopConstraint(&Trans);
1084                                         }
1085                                         else {
1086                                                 if (G.qual == 0)
1087                                                         setUserConstraint(&Trans, (CON_AXIS2), "along %s Z");
1088                                                 else if ((G.qual == LR_SHIFTKEY) && ((Trans.flag & T_2D_EDIT)==0))
1089                                                         setUserConstraint(&Trans, (CON_AXIS0|CON_AXIS1), "locking %s Z");
1090                                         }
1091                                 }
1092                                 else if ((Trans.flag & T_2D_EDIT)==0) {
1093                                         if (G.qual == 0)
1094                                                 setConstraint(&Trans, mati, (CON_AXIS2), "along global Z");
1095                                         else if (G.qual == LR_SHIFTKEY)
1096                                                 setConstraint(&Trans, mati, (CON_AXIS0|CON_AXIS1), "locking global Z");
1097                                 }
1098                                 Trans.redraw = 1;
1099                         }
1100                         break;
1101                 case OKEY:
1102                         if (Trans.flag & T_PROP_EDIT && G.qual==LR_SHIFTKEY) {
1103                                 G.scene->prop_mode = (G.scene->prop_mode+1)%6;
1104                                 calculatePropRatio(&Trans);
1105                                 Trans.redraw= 1;
1106                         }
1107                         break;
1108                 case PADPLUSKEY:
1109                         if(G.qual & LR_ALTKEY && Trans.flag & T_PROP_EDIT) {
1110                                 Trans.propsize*= 1.1f;
1111                                 calculatePropRatio(&Trans);
1112                         }
1113                         Trans.redraw= 1;
1114                         break;
1115                 case PAGEUPKEY:
1116                 case WHEELDOWNMOUSE:
1117                         if (Trans.flag & T_AUTOIK) {
1118                                 transform_autoik_update(&Trans, 1);
1119                         }
1120                         else if(Trans.flag & T_PROP_EDIT) {
1121                                 Trans.propsize*= 1.1f;
1122                                 calculatePropRatio(&Trans);
1123                         }
1124                         else view_editmove(event);
1125                         Trans.redraw= 1;
1126                         break;
1127                 case PADMINUS:
1128                         if(G.qual & LR_ALTKEY && Trans.flag & T_PROP_EDIT) {
1129                                 Trans.propsize*= 0.90909090f;
1130                                 calculatePropRatio(&Trans);
1131                         }
1132                         Trans.redraw= 1;
1133                         break;
1134                 case PAGEDOWNKEY:
1135                 case WHEELUPMOUSE:
1136                         if (Trans.flag & T_AUTOIK) {
1137                                 transform_autoik_update(&Trans, -1);
1138                         }
1139                         else if (Trans.flag & T_PROP_EDIT) {
1140                                 Trans.propsize*= 0.90909090f;
1141                                 calculatePropRatio(&Trans);
1142                         }
1143                         else view_editmove(event);
1144                         Trans.redraw= 1;
1145                         break;
1146                 }
1147                 
1148                 // Numerical input events
1149                 Trans.redraw |= handleNumInput(&(Trans.num), event);
1150                 
1151                 // Snapping events
1152                 Trans.redraw |= handleSnapping(&Trans, event);
1153                 
1154                 arrows_move_cursor(event);
1155         }
1156         else {
1157                 switch (event){
1158                 /* no redraw on release modifier keys! this makes sure you can assign the 'grid' still 
1159                    after releasing modifer key */
1160                 case MIDDLEMOUSE:
1161                         if ((Trans.flag & T_NO_CONSTRAINT)==0) {
1162                                 Trans.flag &= ~T_MMB_PRESSED;
1163                                 postSelectConstraint(&Trans);
1164                                 Trans.redraw = 1;
1165                         }
1166                         break;
1167                 case LEFTMOUSE:
1168                 case RIGHTMOUSE:
1169                         if (Trans.context & CTX_TWEAK)
1170                                 Trans.state = TRANS_CONFIRM;
1171                         break;
1172                 case LEFTSHIFTKEY:
1173                 case RIGHTSHIFTKEY:
1174                         /* shift is modifier for higher resolution transform */
1175                         Trans.flag &= ~T_SHIFT_MOD;
1176                         break;
1177                 }
1178         }
1179         
1180         // Per transform event, if present
1181         if (Trans.handleEvent)
1182                 Trans.redraw |= Trans.handleEvent(&Trans, event, val);
1183 }
1184
1185 int calculateTransformCenter(int centerMode, float *vec)
1186 {
1187         int success = 1;
1188         checkFirstTime();
1189
1190         Trans.state = TRANS_RUNNING;
1191
1192         Trans.context = CTX_NONE;
1193         
1194         Trans.mode = TFM_DUMMY;
1195
1196         initTrans(&Trans);                                      // internal data, mouse, vectors
1197
1198         createTransData(&Trans);                        // make TransData structs from selection
1199
1200         Trans.around = centerMode;                      // override userdefined mode
1201
1202         if (Trans.total == 0) {
1203                 success = 0;
1204         }
1205         else {
1206                 success = 1;
1207                 
1208                 calculateCenter(&Trans);
1209         
1210                 // Copy center from constraint center. Transform center can be local    
1211                 VECCOPY(vec, Trans.con.center);
1212         }
1213
1214         postTrans(&Trans);
1215
1216         /* aftertrans does insert ipos and action channels, and clears base flags, doesnt read transdata */
1217         special_aftertrans_update(&Trans);
1218         
1219         return success;
1220 }
1221
1222 void initTransform(int mode, int context) {
1223         /* added initialize, for external calls to set stuff in TransInfo, like undo string */
1224         checkFirstTime();
1225
1226         Trans.state = TRANS_RUNNING;
1227
1228         Trans.context = context;
1229         
1230         Trans.mode = mode;
1231
1232         initTrans(&Trans);                                      // internal data, mouse, vectors
1233
1234         if(Trans.spacetype==SPACE_VIEW3D) {
1235                 calc_manipulator_stats(curarea);
1236                 Mat3CpyMat4(Trans.spacemtx, G.vd->twmat);
1237         }
1238         else
1239                 Mat3One(Trans.spacemtx);
1240
1241         createTransData(&Trans);                        // make TransData structs from selection
1242
1243         initSnapping(&Trans); // Initialize snapping data AFTER mode flags
1244
1245         if (Trans.total == 0) {
1246                 postTrans(&Trans);
1247                 return;
1248         }
1249
1250         /* EVIL! posemode code can switch translation to rotate when 1 bone is selected. will be removed (ton) */
1251         /* EVIL2: we gave as argument also texture space context bit... was cleared */
1252         /* EVIL3: extend mode for animation editors also switches modes... but is best way to avoid duplicate code */
1253         mode = Trans.mode;
1254         
1255         calculatePropRatio(&Trans);
1256         calculateCenter(&Trans);
1257
1258         switch (mode) {
1259         case TFM_TRANSLATION:
1260                 initTranslation(&Trans);
1261                 break;
1262         case TFM_ROTATION:
1263                 initRotation(&Trans);
1264                 break;
1265         case TFM_RESIZE:
1266                 initResize(&Trans);
1267                 break;
1268         case TFM_TOSPHERE:
1269                 initToSphere(&Trans);
1270                 break;
1271         case TFM_SHEAR:
1272                 initShear(&Trans);
1273                 break;
1274         case TFM_WARP:
1275                 initWarp(&Trans);
1276                 break;
1277         case TFM_SHRINKFATTEN:
1278                 initShrinkFatten(&Trans);
1279                 break;
1280         case TFM_TILT:
1281                 initTilt(&Trans);
1282                 break;
1283         case TFM_CURVE_SHRINKFATTEN:
1284                 initCurveShrinkFatten(&Trans);
1285                 break;
1286         case TFM_TRACKBALL:
1287                 initTrackball(&Trans);
1288                 break;
1289         case TFM_PUSHPULL:
1290                 initPushPull(&Trans);
1291                 break;
1292         case TFM_CREASE:
1293                 initCrease(&Trans);
1294                 break;
1295         case TFM_BONESIZE:
1296                 {       /* used for both B-Bone width (bonesize) as for deform-dist (envelope) */
1297                         bArmature *arm= Trans.poseobj->data;
1298                         if(arm->drawtype==ARM_ENVELOPE)
1299                                 initBoneEnvelope(&Trans);
1300                         else
1301                                 initBoneSize(&Trans);
1302                 }
1303                 break;
1304         case TFM_BONE_ENVELOPE:
1305                 initBoneEnvelope(&Trans);
1306                 break;
1307         case TFM_BONE_ROLL:
1308                 initBoneRoll(&Trans);
1309                 break;
1310         case TFM_TIME_TRANSLATE:
1311                 initTimeTranslate(&Trans);
1312                 break;
1313         case TFM_TIME_SLIDE:
1314                 initTimeSlide(&Trans);
1315                 break;
1316         case TFM_TIME_SCALE:
1317                 initTimeScale(&Trans);
1318                 break;
1319         case TFM_TIME_EXTEND: 
1320                 /* now that transdata has been made, do like for TFM_TIME_TRANSLATE */
1321                 initTimeTranslate(&Trans);
1322                 break;
1323         case TFM_BAKE_TIME:
1324                 initBakeTime(&Trans);
1325                 break;
1326         }
1327 }
1328
1329 void Transform() 
1330 {
1331         short pmval[2] = {0, 0}, mval[2], val;
1332         unsigned short event;
1333
1334         if(Trans.total==0) return;      // added, can happen now! (ton)
1335         
1336         // Emptying event queue
1337         while( qtest() ) {
1338                 event= extern_qread(&val);
1339         }
1340
1341         Trans.redraw = 1; /* initial draw */
1342
1343         while (Trans.state == TRANS_RUNNING) {
1344
1345                 getmouseco_areawin(mval);
1346                 
1347                 if (mval[0] != pmval[0] || mval[1] != pmval[1]) {
1348                         if (Trans.flag & T_MMB_PRESSED)
1349                                 Trans.con.mode |= CON_SELECT;
1350                         Trans.redraw = 1;
1351                 }
1352                 if (Trans.redraw) {
1353                         pmval[0] = mval[0];
1354                         pmval[1] = mval[1];
1355
1356                         selectConstraint(&Trans);
1357                         if (Trans.transform) {
1358                                 Trans.transform(&Trans, mval);  // calls recalcData()
1359                         }
1360                         Trans.redraw = 0;
1361                 }
1362                 
1363                 /* essential for idling subloop */
1364                 if( qtest()==0) PIL_sleep_ms(2);
1365
1366                 while( qtest() ) {
1367                         event= extern_qread(&val);
1368                         transformEvent(event, val);
1369                 }
1370         }
1371         
1372         
1373         /* handle restoring objects */
1374         if(Trans.state == TRANS_CANCEL)
1375                 restoreTransObjects(&Trans);    // calls recalcData()
1376         
1377         /* free data */
1378         postTrans(&Trans);
1379
1380         /* aftertrans does insert ipos and action channels, and clears base flags, doesnt read transdata */
1381         special_aftertrans_update(&Trans);
1382
1383         /* send events out for redraws */
1384         viewRedrawPost(&Trans);
1385
1386         /*  Undo as last, certainly after special_trans_update! */
1387         if(Trans.state == TRANS_CANCEL) {
1388                 if(Trans.undostr) BIF_undo_push(Trans.undostr);
1389         }
1390         else {
1391                 if(Trans.undostr) BIF_undo_push(Trans.undostr);
1392                 else BIF_undo_push(transform_to_undostr(&Trans));
1393         }
1394         Trans.undostr= NULL;
1395         
1396 }
1397
1398 /* ************************** Manipulator init and main **************************** */
1399
1400 void initManipulator(int mode)
1401 {
1402         Trans.state = TRANS_RUNNING;
1403
1404         Trans.context = CTX_NONE;
1405         
1406         Trans.mode = mode;
1407         
1408         /* automatic switch to scaling bone envelopes */
1409         if(mode==TFM_RESIZE && G.obedit && G.obedit->type==OB_ARMATURE) {
1410                 bArmature *arm= G.obedit->data;
1411                 if(arm->drawtype==ARM_ENVELOPE)
1412                         mode= TFM_BONE_ENVELOPE;
1413         }
1414
1415         initTrans(&Trans);                                      // internal data, mouse, vectors
1416
1417         G.moving |= G_TRANSFORM_MANIP;          // signal to draw manipuls while transform
1418         createTransData(&Trans);                        // make TransData structs from selection
1419
1420         if (Trans.total == 0)
1421                 return;
1422
1423         initSnapping(&Trans); // Initialize snapping data AFTER mode flags
1424
1425         /* EVIL! posemode code can switch translation to rotate when 1 bone is selected. will be removed (ton) */
1426         /* EVIL2: we gave as argument also texture space context bit... was cleared */
1427         mode = Trans.mode;
1428         
1429         calculatePropRatio(&Trans);
1430         calculateCenter(&Trans);
1431
1432         switch (mode) {
1433         case TFM_TRANSLATION:
1434                 initTranslation(&Trans);
1435                 break;
1436         case TFM_ROTATION:
1437                 initRotation(&Trans);
1438                 break;
1439         case TFM_RESIZE:
1440                 initResize(&Trans);
1441                 break;
1442         case TFM_TRACKBALL:
1443                 initTrackball(&Trans);
1444                 break;
1445         }
1446
1447         Trans.flag |= T_USES_MANIPULATOR;
1448 }
1449
1450 void ManipulatorTransform() 
1451 {
1452         int mouse_moved = 0;
1453         short pmval[2] = {0, 0}, mval[2], val;
1454         unsigned short event;
1455
1456         if (Trans.total == 0)
1457                 return;
1458
1459         Trans.redraw = 1; /* initial draw */
1460
1461         while (Trans.state == TRANS_RUNNING) {
1462                 
1463                 getmouseco_areawin(mval);
1464                 
1465                 if (mval[0] != pmval[0] || mval[1] != pmval[1]) {
1466                         Trans.redraw = 1;
1467                 }
1468                 if (Trans.redraw) {
1469                         pmval[0] = mval[0];
1470                         pmval[1] = mval[1];
1471
1472                         //selectConstraint(&Trans);  needed?
1473                         if (Trans.transform) {
1474                                 Trans.transform(&Trans, mval);
1475                         }
1476                         Trans.redraw = 0;
1477                 }
1478                 
1479                 /* essential for idling subloop */
1480                 if( qtest()==0) PIL_sleep_ms(2);
1481
1482                 while( qtest() ) {
1483                         event= extern_qread(&val);
1484
1485                         switch (event){
1486                         case MOUSEX:
1487                         case MOUSEY:
1488                                 mouse_moved = 1;
1489                                 break;
1490                         /* enforce redraw of transform when modifiers are used */
1491                         case LEFTCTRLKEY:
1492                         case RIGHTCTRLKEY:
1493                                 if(val) Trans.redraw = 1;
1494                                 break;
1495                         case LEFTSHIFTKEY:
1496                         case RIGHTSHIFTKEY:
1497                                 /* shift is modifier for higher resolution transform, works nice to store this mouse position */
1498                                 if(val) {
1499                                         getmouseco_areawin(Trans.shiftmval);
1500                                         Trans.flag |= T_SHIFT_MOD;
1501                                         Trans.redraw = 1;
1502                                 }
1503                                 else Trans.flag &= ~T_SHIFT_MOD; 
1504                                 break;
1505                                 
1506                         case ESCKEY:
1507                         case RIGHTMOUSE:
1508                                 Trans.state = TRANS_CANCEL;
1509                                 break;
1510                         case LEFTMOUSE:
1511                                 if(mouse_moved==0 && val==0) break;
1512                                 // else we pass on event to next, which cancels
1513                         case SPACEKEY:
1514                         case PADENTER:
1515                         case RETKEY:
1516                                 Trans.state = TRANS_CONFIRM;
1517                                 break;
1518                         }
1519                         if(val) {
1520                                 switch(event) {
1521                                 case WHEELDOWNMOUSE:
1522                                 case PADPLUSKEY:
1523                                         if(Trans.flag & T_PROP_EDIT) {
1524                                                 Trans.propsize*= 1.1f;
1525                                                 calculatePropRatio(&Trans);
1526                                                 Trans.redraw= 1;
1527                                         }
1528                                         break;
1529                                 case WHEELUPMOUSE:
1530                                 case PADMINUS:
1531                                         if(Trans.flag & T_PROP_EDIT) {
1532                                                 Trans.propsize*= 0.90909090f;
1533                                                 calculatePropRatio(&Trans);
1534                                                 Trans.redraw= 1;
1535                                         }
1536                                         break;
1537                                 }                       
1538                         }
1539                 }
1540         }
1541         
1542         if(Trans.state == TRANS_CANCEL) {
1543                 restoreTransObjects(&Trans);
1544         }
1545         
1546         /* free data, reset vars */
1547         postTrans(&Trans);
1548         
1549         /* aftertrans does insert ipos and action channels, and clears base flags */
1550         special_aftertrans_update(&Trans);
1551         
1552         /* send events out for redraws */
1553         viewRedrawPost(&Trans);
1554
1555         if(Trans.state != TRANS_CANCEL) {
1556                 BIF_undo_push(transform_to_undostr(&Trans));
1557         }
1558         
1559 }
1560
1561 /* ************************** TRANSFORM LOCKS **************************** */
1562
1563 static void protectedTransBits(short protectflag, float *vec)
1564 {
1565         if(protectflag & OB_LOCK_LOCX)
1566                 vec[0]= 0.0f;
1567         if(protectflag & OB_LOCK_LOCY)
1568                 vec[1]= 0.0f;
1569         if(protectflag & OB_LOCK_LOCZ)
1570                 vec[2]= 0.0f;
1571 }
1572
1573 static void protectedSizeBits(short protectflag, float *size)
1574 {
1575         if(protectflag & OB_LOCK_SCALEX)
1576                 size[0]= 1.0f;
1577         if(protectflag & OB_LOCK_SCALEY)
1578                 size[1]= 1.0f;
1579         if(protectflag & OB_LOCK_SCALEZ)
1580                 size[2]= 1.0f;
1581 }
1582
1583 static void protectedRotateBits(short protectflag, float *eul, float *oldeul)
1584 {
1585         if(protectflag & OB_LOCK_ROTX)
1586                 eul[0]= oldeul[0];
1587         if(protectflag & OB_LOCK_ROTY)
1588                 eul[1]= oldeul[1];
1589         if(protectflag & OB_LOCK_ROTZ)
1590                 eul[2]= oldeul[2];
1591 }
1592
1593 static void protectedQuaternionBits(short protectflag, float *quat, float *oldquat)
1594 {
1595         /* quaternions get limited with euler... */
1596         /* this function only does the delta rotation */
1597         
1598         if(protectflag) {
1599                 float eul[3], oldeul[3], quat1[4];
1600                 
1601                 QUATCOPY(quat1, quat);
1602                 QuatToEul(quat, eul);
1603                 QuatToEul(oldquat, oldeul);
1604                 
1605                 if(protectflag & OB_LOCK_ROTX)
1606                         eul[0]= oldeul[0];
1607                 if(protectflag & OB_LOCK_ROTY)
1608                         eul[1]= oldeul[1];
1609                 if(protectflag & OB_LOCK_ROTZ)
1610                         eul[2]= oldeul[2];
1611                 
1612                 EulToQuat(eul, quat);
1613                 /* quaternions flip w sign to accumulate rotations correctly */
1614                 if( (quat1[0]<0.0f && quat[0]>0.0f) || (quat1[0]>0.0f && quat[0]<0.0f) ) {
1615                         QuatMulf(quat, -1.0f);
1616                 }
1617         }
1618 }
1619
1620 /* ******************* TRANSFORM LIMITS ********************** */
1621
1622 static void constraintTransLim(TransInfo *t, TransData *td)
1623 {
1624         if (td->con) {
1625                 bConstraintTypeInfo *cti= get_constraint_typeinfo(CONSTRAINT_TYPE_LOCLIMIT);
1626                 bConstraintOb cob;
1627                 bConstraint *con;
1628                 
1629                 /* Make a temporary bConstraintOb for using these limit constraints 
1630                  *      - they only care that cob->matrix is correctly set ;-)
1631                  *      - current space should be local
1632                  */
1633                 memset(&cob, 0, sizeof(bConstraintOb));
1634                 Mat4One(cob.matrix);
1635                 if (td->tdi) {
1636                         TransDataIpokey *tdi= td->tdi;
1637                         cob.matrix[3][0]= tdi->locx[0];
1638                         cob.matrix[3][1]= tdi->locy[0];
1639                         cob.matrix[3][2]= tdi->locz[0];
1640                 }
1641                 else {
1642                         VECCOPY(cob.matrix[3], td->loc);
1643                 }
1644                 
1645                 /* Evaluate valid constraints */
1646                 for (con= td->con; con; con= con->next) {
1647                         float tmat[4][4];
1648                                 
1649                         /* only use it if it's tagged for this purpose (and the right type) */
1650                         if (con->type == CONSTRAINT_TYPE_LOCLIMIT) {
1651                                 bLocLimitConstraint *data= con->data;
1652                                 if ((data->flag2 & LIMIT_TRANSFORM)==0) 
1653                                         continue;
1654                         }
1655                         else if (con->type == CONSTRAINT_TYPE_ROTLIMIT) {
1656                                 bRotLimitConstraint *data= con->data;
1657                                 if ((data->flag2 & LIMIT_TRANSFORM)==0) 
1658                                         continue;
1659                         }
1660                         else if (con->type == CONSTRAINT_TYPE_SIZELIMIT) {
1661                                 bSizeLimitConstraint *data= con->data;
1662                                 if ((data->flag2 & LIMIT_TRANSFORM)==0) 
1663                                         continue;
1664                         }
1665                         else {
1666                                 /* not supported */
1667                                 continue;
1668                         }
1669                                 
1670                         /* do space conversions */
1671                         if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
1672                                 /* just multiply by td->mtx (this should be ok) */
1673                                 Mat4CpyMat4(tmat, cob.matrix);
1674                                 Mat4MulMat34(cob.matrix, td->mtx, tmat);
1675                         }
1676                         else if (con->ownspace != CONSTRAINT_SPACE_LOCAL) {
1677                                 /* skip... incompatable spacetype */
1678                                 continue;
1679                         }
1680                         
1681                         /* do constraint */
1682                         cti->evaluate_constraint(con, &cob, NULL);
1683                         
1684                         /* convert spaces again */
1685                         if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
1686                                 /* just multiply by td->mtx (this should be ok) */
1687                                 Mat4CpyMat4(tmat, cob.matrix);
1688                                 Mat4MulMat34(cob.matrix, td->smtx, tmat);
1689                         }
1690                 }
1691                 
1692                 /* copy results from cob->matrix */
1693                 if (td->tdi) {
1694                         TransDataIpokey *tdi= td->tdi;
1695                         tdi->locx[0]= cob.matrix[3][0];
1696                         tdi->locy[0]= cob.matrix[3][1];
1697                         tdi->locz[0]= cob.matrix[3][2];
1698                 }
1699                 else {
1700                         VECCOPY(td->loc, cob.matrix[3]);
1701                 }
1702         }
1703 }
1704
1705 static void constraintRotLim(TransInfo *t, TransData *td)
1706 {
1707         if (td->con) {
1708                 bConstraintTypeInfo *cti= get_constraint_typeinfo(CONSTRAINT_TYPE_ROTLIMIT);
1709                 bConstraintOb cob;
1710                 bConstraint *con;
1711                 
1712                 /* Make a temporary bConstraintOb for using these limit constraints 
1713                  *      - they only care that cob->matrix is correctly set ;-)
1714                  *      - current space should be local
1715                  */
1716                 memset(&cob, 0, sizeof(bConstraintOb));
1717                 if (td->flag & TD_USEQUAT) {
1718                         /* quats */
1719                         if (td->ext)
1720                                 QuatToMat4(td->ext->quat, cob.matrix);
1721                         else
1722                                 return;
1723                 }
1724                 else if (td->tdi) {
1725                         /* ipo-keys eulers */
1726                         TransDataIpokey *tdi= td->tdi;
1727                         float eul[3];
1728                         
1729                         eul[0]= tdi->rotx[0];
1730                         eul[1]= tdi->roty[0];
1731                         eul[2]= tdi->rotz[0];
1732                         
1733                         EulToMat4(eul, cob.matrix);
1734                 }
1735                 else {
1736                         /* eulers */
1737                         if (td->ext)
1738                                 EulToMat4(td->ext->rot, cob.matrix);
1739                         else
1740                                 return;
1741                 }
1742                         
1743                 /* Evaluate valid constraints */
1744                 for (con= td->con; con; con= con->next) {
1745                         /* we're only interested in Limit-Scale constraints */
1746                         if (con->type == CONSTRAINT_TYPE_ROTLIMIT) {
1747                                 bRotLimitConstraint *data= con->data;
1748                                 float tmat[4][4];
1749                                 
1750                                 /* only use it if it's tagged for this purpose */
1751                                 if ((data->flag2 & LIMIT_TRANSFORM)==0) 
1752                                         continue;
1753                                         
1754                                 /* do space conversions */
1755                                 if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
1756                                         /* just multiply by td->mtx (this should be ok) */
1757                                         Mat4CpyMat4(tmat, cob.matrix);
1758                                         Mat4MulMat34(cob.matrix, td->mtx, tmat);
1759                                 }
1760                                 else if (con->ownspace != CONSTRAINT_SPACE_LOCAL) {
1761                                         /* skip... incompatable spacetype */
1762                                         continue;
1763                                 }
1764                                 
1765                                 /* do constraint */
1766                                 cti->evaluate_constraint(con, &cob, NULL);
1767                                 
1768                                 /* convert spaces again */
1769                                 if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
1770                                         /* just multiply by td->mtx (this should be ok) */
1771                                         Mat4CpyMat4(tmat, cob.matrix);
1772                                         Mat4MulMat34(cob.matrix, td->smtx, tmat);
1773                                 }
1774                         }
1775                 }
1776                 
1777                 /* copy results from cob->matrix */
1778                 if (td->flag & TD_USEQUAT) {
1779                         /* quats */
1780                         Mat4ToQuat(cob.matrix, td->ext->quat);
1781                 }
1782                 else if (td->tdi) {
1783                         /* ipo-keys eulers */
1784                         TransDataIpokey *tdi= td->tdi;
1785                         float eul[3];
1786                         
1787                         Mat4ToEul(cob.matrix, eul);
1788                         
1789                         tdi->rotx[0]= eul[0];
1790                         tdi->roty[0]= eul[1];
1791                         tdi->rotz[0]= eul[2];
1792                 }
1793                 else {
1794                         /* eulers */
1795                         Mat4ToEul(cob.matrix, td->ext->rot);
1796                 }
1797         }
1798 }
1799
1800 static void constraintSizeLim(TransInfo *t, TransData *td)
1801 {
1802         if (td->con && td->ext) {
1803                 bConstraintTypeInfo *cti= get_constraint_typeinfo(CONSTRAINT_TYPE_SIZELIMIT);
1804                 bConstraintOb cob;
1805                 bConstraint *con;
1806                 
1807                 /* Make a temporary bConstraintOb for using these limit constraints 
1808                  *      - they only care that cob->matrix is correctly set ;-)
1809                  *      - current space should be local
1810                  */
1811                 memset(&cob, 0, sizeof(bConstraintOb));
1812                 if (td->tdi) {
1813                         TransDataIpokey *tdi= td->tdi;
1814                         float size[3];
1815                         
1816                         size[0]= tdi->sizex[0];
1817                         size[1]= tdi->sizey[0];
1818                         size[2]= tdi->sizez[0];
1819                         SizeToMat4(size, cob.matrix);
1820                 } 
1821                 else if ((td->flag & TD_SINGLESIZE) && !(t->con.mode & CON_APPLY)) {
1822                         /* scale val and reset size */
1823                         return; // TODO: fix this case
1824                 }
1825                 else {
1826                         /* Reset val if SINGLESIZE but using a constraint */
1827                         if (td->flag & TD_SINGLESIZE)
1828                                 return;
1829                         
1830                         SizeToMat4(td->ext->size, cob.matrix);
1831                 }
1832                         
1833                 /* Evaluate valid constraints */
1834                 for (con= td->con; con; con= con->next) {
1835                         /* we're only interested in Limit-Scale constraints */
1836                         if (con->type == CONSTRAINT_TYPE_SIZELIMIT) {
1837                                 bSizeLimitConstraint *data= con->data;
1838                                 float tmat[4][4];
1839                                 
1840                                 /* only use it if it's tagged for this purpose */
1841                                 if ((data->flag2 & LIMIT_TRANSFORM)==0) 
1842                                         continue;
1843                                         
1844                                 /* do space conversions */
1845                                 if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
1846                                         /* just multiply by td->mtx (this should be ok) */
1847                                         Mat4CpyMat4(tmat, cob.matrix);
1848                                         Mat4MulMat34(cob.matrix, td->mtx, tmat);
1849                                 }
1850                                 else if (con->ownspace != CONSTRAINT_SPACE_LOCAL) {
1851                                         /* skip... incompatable spacetype */
1852                                         continue;
1853                                 }
1854                                 
1855                                 /* do constraint */
1856                                 cti->evaluate_constraint(con, &cob, NULL);
1857                                 
1858                                 /* convert spaces again */
1859                                 if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
1860                                         /* just multiply by td->mtx (this should be ok) */
1861                                         Mat4CpyMat4(tmat, cob.matrix);
1862                                         Mat4MulMat34(cob.matrix, td->smtx, tmat);
1863                                 }
1864                         }
1865                 }
1866                 
1867                 /* copy results from cob->matrix */
1868                 if (td->tdi) {
1869                         TransDataIpokey *tdi= td->tdi;
1870                         float size[3];
1871                         
1872                         Mat4ToSize(cob.matrix, size);
1873                         
1874                         tdi->sizex[0]= size[0];
1875                         tdi->sizey[0]= size[1];
1876                         tdi->sizez[0]= size[2];
1877                 } 
1878                 else if ((td->flag & TD_SINGLESIZE) && !(t->con.mode & CON_APPLY)) {
1879                         /* scale val and reset size */
1880                         return; // TODO: fix this case
1881                 }
1882                 else {
1883                         /* Reset val if SINGLESIZE but using a constraint */
1884                         if (td->flag & TD_SINGLESIZE)
1885                                 return;
1886                                 
1887                         Mat4ToSize(cob.matrix, td->ext->size);
1888                 }
1889         }
1890 }
1891
1892 /* ************************** WARP *************************** */
1893
1894 void initWarp(TransInfo *t) 
1895 {
1896         float max[3], min[3];
1897         int i;
1898         
1899         t->mode = TFM_WARP;
1900         t->transform = Warp;
1901         t->handleEvent = handleEventWarp;
1902         
1903         t->idx_max = 0;
1904         t->num.idx_max = 0;
1905         t->snap[0] = 0.0f;
1906         t->snap[1] = 5.0f;
1907         t->snap[2] = 1.0f;
1908         
1909         t->flag |= T_NO_CONSTRAINT;
1910
1911 /* warp is done fully in view space */
1912         calculateCenterCursor(t);
1913         t->fac = (float)(t->center2d[0] - t->imval[0]);
1914         
1915         /* we need min/max in view space */
1916         for(i = 0; i < t->total; i++) {
1917                 float center[3];
1918                 VECCOPY(center, t->data[i].center);
1919                 Mat3MulVecfl(t->data[i].mtx, center);
1920                 Mat4MulVecfl(t->viewmat, center);
1921                 VecSubf(center, center, t->viewmat[3]);
1922                 if (i)
1923                         MinMax3(min, max, center);
1924                 else {
1925                         VECCOPY(max, center);
1926                         VECCOPY(min, center);
1927                 }
1928         }
1929         
1930         t->center[0]= (min[0]+max[0])/2.0f;
1931         t->center[1]= (min[1]+max[1])/2.0f;
1932         t->center[2]= (min[2]+max[2])/2.0f;
1933         
1934         if (max[0] == min[0]) max[0] += 0.1; /* not optimal, but flipping is better than invalid garbage (i.e. division by zero!) */
1935         t->val= (max[0]-min[0])/2.0f; /* t->val is X dimension projected boundbox */
1936 }
1937
1938 int handleEventWarp(TransInfo *t, unsigned short event, short val)
1939 {
1940         int status = 0;
1941         
1942         if (event == MIDDLEMOUSE && val)
1943         {
1944                 // Use customData pointer to signal warp direction
1945                 if      (t->customData == 0)
1946                         t->customData = (void*)1;
1947                 else
1948                         t->customData = 0;
1949                         
1950                 status = 1;
1951         }
1952         
1953         return status;
1954 }
1955
1956 int Warp(TransInfo *t, short mval[2])
1957 {
1958         TransData *td = t->data;
1959         float vec[3], circumfac, dist, phi0, co, si, *curs, cursor[3], gcursor[3];
1960         int i;
1961         char str[50];
1962         
1963         curs= give_cursor();
1964         /*
1965          * gcursor is the one used for helpline.
1966          * It has to be in the same space as the drawing loop
1967          * (that means it needs to be in the object's space when in edit mode and
1968          *  in global space in object mode)
1969          *
1970          * cursor is used for calculations.
1971          * It needs to be in view space, but we need to take object's offset
1972          * into account if in Edit mode.
1973          */
1974         VECCOPY(cursor, curs);
1975         VECCOPY(gcursor, cursor);       
1976         if (t->flag & T_EDIT) {
1977                 VecSubf(cursor, cursor, G.obedit->obmat[3]);
1978                 VecSubf(gcursor, gcursor, G.obedit->obmat[3]);
1979                 Mat3MulVecfl(t->data->smtx, gcursor);
1980         }
1981         Mat4MulVecfl(t->viewmat, cursor);
1982         VecSubf(cursor, cursor, t->viewmat[3]);
1983
1984         /* amount of degrees for warp */
1985         circumfac= 360.0f * InputHorizontalRatio(t, mval);
1986         
1987         if (t->customData) /* non-null value indicates reversed input */
1988         {
1989                 circumfac *= -1;
1990         }
1991
1992         snapGrid(t, &circumfac);
1993         applyNumInput(&t->num, &circumfac);
1994         
1995         /* header print for NumInput */
1996         if (hasNumInput(&t->num)) {
1997                 char c[20];
1998                 
1999                 outputNumInput(&(t->num), c);
2000                 
2001                 sprintf(str, "Warp: %s", c);
2002         }
2003         else {
2004                 /* default header print */
2005                 sprintf(str, "Warp: %.3f", circumfac);
2006         }
2007         
2008         circumfac*= (float)(-M_PI/360.0);
2009         
2010         for(i = 0; i < t->total; i++, td++) {
2011                 float loc[3];
2012                 if (td->flag & TD_NOACTION)
2013                         break;
2014
2015                 if (td->flag & TD_SKIP)
2016                         continue;
2017                 
2018                 /* translate point to center, rotate in such a way that outline==distance */
2019                 VECCOPY(vec, td->iloc);
2020                 Mat3MulVecfl(td->mtx, vec);
2021                 Mat4MulVecfl(t->viewmat, vec);
2022                 VecSubf(vec, vec, t->viewmat[3]);
2023                 
2024                 dist= vec[0]-cursor[0];
2025                 
2026                 /* t->val is X dimension projected boundbox */
2027                 phi0= (circumfac*dist/t->val);  
2028                 
2029                 vec[1]= (vec[1]-cursor[1]);
2030                 
2031                 co= (float)cos(phi0);
2032                 si= (float)sin(phi0);
2033                 loc[0]= -si*vec[1]+cursor[0];
2034                 loc[1]= co*vec[1]+cursor[1];
2035                 loc[2]= vec[2];
2036                 
2037                 Mat4MulVecfl(t->viewinv, loc);
2038                 VecSubf(loc, loc, t->viewinv[3]);
2039                 Mat3MulVecfl(td->smtx, loc);
2040                 
2041                 VecSubf(loc, loc, td->iloc);
2042                 VecMulf(loc, td->factor);
2043                 VecAddf(td->loc, td->iloc, loc);
2044         }
2045
2046         recalcData(t);
2047         
2048         headerprint(str);
2049         
2050         viewRedrawForce(t);
2051         
2052         helpline(t, gcursor);
2053         
2054         return 1;
2055 }
2056
2057 /* ************************** SHEAR *************************** */
2058
2059 void initShear(TransInfo *t) 
2060 {
2061         t->mode = TFM_SHEAR;
2062         t->transform = Shear;
2063         t->handleEvent = handleEventShear;
2064         
2065         t->idx_max = 0;
2066         t->num.idx_max = 0;
2067         t->snap[0] = 0.0f;
2068         t->snap[1] = 0.1f;
2069         t->snap[2] = t->snap[1] * 0.1f;
2070         
2071         t->flag |= T_NO_CONSTRAINT;
2072 }
2073
2074 int handleEventShear(TransInfo *t, unsigned short event, short val)
2075 {
2076         int status = 0;
2077         
2078         if (event == MIDDLEMOUSE && val)
2079         {
2080                 // Use customData pointer to signal Shear direction
2081                 if      (t->customData == 0)
2082                         t->customData = (void*)1;
2083                 else
2084                         t->customData = 0;
2085                         
2086                 status = 1;
2087         }
2088         
2089         return status;
2090 }
2091
2092
2093 int Shear(TransInfo *t, short mval[2]) 
2094 {
2095         TransData *td = t->data;
2096         float vec[3];
2097         float smat[3][3], tmat[3][3], totmat[3][3], persmat[3][3], persinv[3][3];
2098         float value;
2099         int i;
2100         char str[50];
2101
2102         Mat3CpyMat4(persmat, t->viewmat);
2103         Mat3Inv(persinv, persmat);
2104
2105         // Custom data signals shear direction
2106         if (t->customData == 0)
2107                 value = 0.05f * InputHorizontalAbsolute(t, mval);
2108         else
2109                 value = 0.05f * InputVerticalAbsolute(t, mval);
2110
2111         snapGrid(t, &value);
2112
2113         applyNumInput(&t->num, &value);
2114
2115         /* header print for NumInput */
2116         if (hasNumInput(&t->num)) {
2117                 char c[20];
2118
2119                 outputNumInput(&(t->num), c);
2120
2121                 sprintf(str, "Shear: %s %s", c, t->proptext);
2122         }
2123         else {
2124                 /* default header print */
2125                 sprintf(str, "Shear: %.3f %s", value, t->proptext);
2126         }
2127         
2128         Mat3One(smat);
2129         
2130         // Custom data signals shear direction
2131         if (t->customData == 0)
2132                 smat[1][0] = value;
2133         else
2134                 smat[0][1] = value;
2135         
2136         Mat3MulMat3(tmat, smat, persmat);
2137         Mat3MulMat3(totmat, persinv, tmat);
2138         
2139         for(i = 0 ; i < t->total; i++, td++) {
2140                 if (td->flag & TD_NOACTION)
2141                         break;
2142
2143                 if (td->flag & TD_SKIP)
2144                         continue;
2145
2146                 if (G.obedit) {
2147                         float mat3[3][3];
2148                         Mat3MulMat3(mat3, totmat, td->mtx);
2149                         Mat3MulMat3(tmat, td->smtx, mat3);
2150                 }
2151                 else {
2152                         Mat3CpyMat3(tmat, totmat);
2153                 }
2154                 VecSubf(vec, td->center, t->center);
2155
2156                 Mat3MulVecfl(tmat, vec);
2157
2158                 VecAddf(vec, vec, t->center);
2159                 VecSubf(vec, vec, td->center);
2160
2161                 VecMulf(vec, td->factor);
2162
2163                 VecAddf(td->loc, td->iloc, vec);
2164         }
2165
2166         recalcData(t);
2167
2168         headerprint(str);
2169
2170         viewRedrawForce(t);
2171
2172         helpline (t, t->center);
2173
2174         return 1;
2175 }
2176
2177 /* ************************** RESIZE *************************** */
2178
2179 void initResize(TransInfo *t) 
2180 {
2181         t->mode = TFM_RESIZE;
2182         t->transform = Resize;
2183         
2184         t->flag |= T_NULL_ONE;
2185         t->num.flag |= NUM_NULL_ONE;
2186         t->num.flag |= NUM_AFFECT_ALL;
2187         if (!G.obedit) {
2188                 t->flag |= T_NO_ZERO;
2189                 t->num.flag |= NUM_NO_ZERO;
2190         }
2191         
2192         t->idx_max = 2;
2193         t->num.idx_max = 2;
2194         t->snap[0] = 0.0f;
2195         t->snap[1] = 0.1f;
2196         t->snap[2] = t->snap[1] * 0.1f;
2197
2198         t->fac = (float)sqrt(
2199                 (
2200                         ((float)(t->center2d[1] - t->imval[1]))*((float)(t->center2d[1] - t->imval[1]))
2201                 +
2202                         ((float)(t->center2d[0] - t->imval[0]))*((float)(t->center2d[0] - t->imval[0]))
2203                 ) );
2204
2205         if(t->fac==0.0f) t->fac= 1.0f;  // prevent Inf
2206 }
2207
2208 static void headerResize(TransInfo *t, float vec[3], char *str) {
2209         char tvec[60];
2210         if (hasNumInput(&t->num)) {
2211                 outputNumInput(&(t->num), tvec);
2212         }
2213         else {
2214                 sprintf(&tvec[0], "%.4f", vec[0]);
2215                 sprintf(&tvec[20], "%.4f", vec[1]);
2216                 sprintf(&tvec[40], "%.4f", vec[2]);
2217         }
2218
2219         if (t->con.mode & CON_APPLY) {
2220                 switch(t->num.idx_max) {
2221                 case 0:
2222                         sprintf(str, "Scale: %s%s %s", &tvec[0], t->con.text, t->proptext);
2223                         break;
2224                 case 1:
2225                         sprintf(str, "Scale: %s : %s%s %s", &tvec[0], &tvec[20], t->con.text, t->proptext);
2226                         break;
2227                 case 2:
2228                         sprintf(str, "Scale: %s : %s : %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext);
2229                 }
2230         }
2231         else {
2232                 if (t->flag & T_2D_EDIT)
2233                         sprintf(str, "Scale X: %s   Y: %s%s %s", &tvec[0], &tvec[20], t->con.text, t->proptext);
2234                 else
2235                         sprintf(str, "Scale X: %s   Y: %s  Z: %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext);
2236         }
2237 }
2238
2239 #define SIGN(a)         (a<-FLT_EPSILON?1:a>FLT_EPSILON?2:3)
2240 #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)
2241
2242 /* smat is reference matrix, only scaled */
2243 static void TransMat3ToSize( float mat[][3], float smat[][3], float *size)
2244 {
2245         float vec[3];
2246         
2247         VecCopyf(vec, mat[0]);
2248         size[0]= Normalize(vec);
2249         VecCopyf(vec, mat[1]);
2250         size[1]= Normalize(vec);
2251         VecCopyf(vec, mat[2]);
2252         size[2]= Normalize(vec);
2253         
2254         /* first tried with dotproduct... but the sign flip is crucial */
2255         if( VECSIGNFLIP(mat[0], smat[0]) ) size[0]= -size[0]; 
2256         if( VECSIGNFLIP(mat[1], smat[1]) ) size[1]= -size[1]; 
2257         if( VECSIGNFLIP(mat[2], smat[2]) ) size[2]= -size[2]; 
2258 }
2259
2260
2261 static void ElementResize(TransInfo *t, TransData *td, float mat[3][3]) {
2262         float tmat[3][3], smat[3][3], center[3];
2263         float vec[3];
2264
2265         if (t->flag & T_EDIT) {
2266                 Mat3MulMat3(smat, mat, td->mtx);
2267                 Mat3MulMat3(tmat, td->smtx, smat);
2268         }
2269         else {
2270                 Mat3CpyMat3(tmat, mat);
2271         }
2272
2273         if (t->con.applySize) {
2274                 t->con.applySize(t, td, tmat);
2275         }
2276
2277         /* local constraint shouldn't alter center */
2278         if (t->around == V3D_LOCAL) {
2279                 if (t->flag & T_OBJECT) {
2280                         VECCOPY(center, td->center);
2281                 }
2282                 else if (t->flag & T_EDIT) {
2283                         
2284                         if(G.vd->around==V3D_LOCAL && (G.scene->selectmode & SCE_SELECT_FACE)) {
2285                                 VECCOPY(center, td->center);
2286                         }
2287                         else {
2288                                 VECCOPY(center, t->center);
2289                         }
2290                 }
2291                 else {
2292                         VECCOPY(center, t->center);
2293                 }
2294         }
2295         else {
2296                 VECCOPY(center, t->center);
2297         }
2298
2299         if (td->ext) {
2300                 float fsize[3];
2301                 
2302                 if (t->flag & (T_OBJECT|T_TEXTURE|T_POSE)) {
2303                         float obsizemat[3][3];
2304                         // Reorient the size mat to fit the oriented object.
2305                         Mat3MulMat3(obsizemat, tmat, td->axismtx);
2306                         //printmatrix3("obsizemat", obsizemat);
2307                         TransMat3ToSize(obsizemat, td->axismtx, fsize);
2308                         //printvecf("fsize", fsize);
2309                 }
2310                 else {
2311                         Mat3ToSize(tmat, fsize);
2312                 }
2313                 
2314                 protectedSizeBits(td->protectflag, fsize);
2315                 
2316                 if ((t->flag & T_V3D_ALIGN)==0) {       // align mode doesn't resize objects itself
2317                         /* handle ipokeys? */
2318                         if(td->tdi) {
2319                                 TransDataIpokey *tdi= td->tdi;
2320                                 /* calculate delta size (equal for size and dsize) */
2321                                 
2322                                 vec[0]= (tdi->oldsize[0])*(fsize[0] -1.0f) * td->factor;
2323                                 vec[1]= (tdi->oldsize[1])*(fsize[1] -1.0f) * td->factor;
2324                                 vec[2]= (tdi->oldsize[2])*(fsize[2] -1.0f) * td->factor;
2325                                 
2326                                 add_tdi_poin(tdi->sizex, tdi->oldsize,   vec[0]);
2327                                 add_tdi_poin(tdi->sizey, tdi->oldsize+1, vec[1]);
2328                                 add_tdi_poin(tdi->sizez, tdi->oldsize+2, vec[2]);
2329                                 
2330                         } 
2331                         else if((td->flag & TD_SINGLESIZE) && !(t->con.mode & CON_APPLY)){
2332                                 /* scale val and reset size */
2333                                 *td->val = td->ival * fsize[0] * td->factor;
2334                                 
2335                                 td->ext->size[0] = td->ext->isize[0];
2336                                 td->ext->size[1] = td->ext->isize[1];
2337                                 td->ext->size[2] = td->ext->isize[2];
2338                         }
2339                         else {
2340                                 /* Reset val if SINGLESIZE but using a constraint */
2341                                 if (td->flag & TD_SINGLESIZE)
2342                                         *td->val = td->ival;
2343                                 
2344                                 td->ext->size[0] = td->ext->isize[0] * (fsize[0]) * td->factor;
2345                                 td->ext->size[1] = td->ext->isize[1] * (fsize[1]) * td->factor;
2346                                 td->ext->size[2] = td->ext->isize[2] * (fsize[2]) * td->factor;
2347                         }
2348                 }
2349                 
2350                 constraintSizeLim(t, td);
2351         }
2352         
2353         /* For individual element center, Editmode need to use iloc */
2354         if (t->flag & T_POINTS)
2355                 VecSubf(vec, td->iloc, center);
2356         else
2357                 VecSubf(vec, td->center, center);
2358
2359         Mat3MulVecfl(tmat, vec);
2360
2361         VecAddf(vec, vec, center);
2362         if (t->flag & T_POINTS)
2363                 VecSubf(vec, vec, td->iloc);
2364         else
2365                 VecSubf(vec, vec, td->center);
2366
2367         VecMulf(vec, td->factor);
2368
2369         if (t->flag & T_OBJECT) {
2370                 Mat3MulVecfl(td->smtx, vec);
2371         }
2372
2373         protectedTransBits(td->protectflag, vec);
2374
2375         if(td->tdi) {
2376                 TransDataIpokey *tdi= td->tdi;
2377                 add_tdi_poin(tdi->locx, tdi->oldloc, vec[0]);
2378                 add_tdi_poin(tdi->locy, tdi->oldloc+1, vec[1]);
2379                 add_tdi_poin(tdi->locz, tdi->oldloc+2, vec[2]);
2380         }
2381         else VecAddf(td->loc, td->iloc, vec);
2382         
2383         constraintTransLim(t, td);
2384 }
2385
2386 int Resize(TransInfo *t, short mval[2]) 
2387 {
2388         TransData *td;
2389         float size[3], mat[3][3];
2390         float ratio;
2391         int i;
2392         char str[200];
2393
2394         /* for manipulator, center handle, the scaling can't be done relative to center */
2395         if( (t->flag & T_USES_MANIPULATOR) && t->con.mode==0) {
2396                 ratio = 1.0f - ((t->imval[0] - mval[0]) + (t->imval[1] - mval[1]))/100.0f;
2397         }
2398         else {
2399                 ratio = InputScaleRatio(t, mval);
2400                 
2401                 /* flip scale, but not for manipulator center handle */
2402                 if      ((t->center2d[0] - mval[0]) * (t->center2d[0] - t->imval[0]) + 
2403                          (t->center2d[1] - mval[1]) * (t->center2d[1] - t->imval[1]) < 0)
2404                                 ratio *= -1.0f;
2405         }
2406         
2407         size[0] = size[1] = size[2] = ratio;
2408
2409         snapGrid(t, size);
2410
2411         if (hasNumInput(&t->num)) {
2412                 applyNumInput(&t->num, size);
2413                 constraintNumInput(t, size);
2414         }
2415
2416         SizeToMat3(size, mat);
2417
2418         if (t->con.applySize) {
2419                 t->con.applySize(t, NULL, mat);
2420         }
2421
2422         Mat3CpyMat3(t->mat, mat);       // used in manipulator
2423         
2424         headerResize(t, size, str);
2425
2426         for(i = 0, td=t->data; i < t->total; i++, td++) {
2427                 if (td->flag & TD_NOACTION)
2428                         break;
2429
2430                 if (td->flag & TD_SKIP)
2431                         continue;
2432                 
2433                 ElementResize(t, td, mat);
2434         }
2435
2436         /* evil hack - redo resize if cliping needed */
2437         if (t->flag & T_CLIP_UV && clipUVTransform(t, size, 1)) {
2438                 SizeToMat3(size, mat);
2439
2440                 if (t->con.applySize)
2441                         t->con.applySize(t, NULL, mat);
2442
2443                 for(i = 0, td=t->data; i < t->total; i++, td++)
2444                         ElementResize(t, td, mat);
2445         }
2446
2447         recalcData(t);
2448
2449         headerprint(str);
2450
2451         viewRedrawForce(t);
2452
2453         if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
2454
2455         return 1;
2456 }
2457
2458 /* ************************** TOSPHERE *************************** */
2459
2460 void initToSphere(TransInfo *t) 
2461 {
2462         TransData *td = t->data;
2463         int i;
2464
2465         t->mode = TFM_TOSPHERE;
2466         t->transform = ToSphere;
2467
2468         t->idx_max = 0;
2469         t->num.idx_max = 0;
2470         t->snap[0] = 0.0f;
2471         t->snap[1] = 0.1f;
2472         t->snap[2] = t->snap[1] * 0.1f;
2473         
2474         t->num.flag |= NUM_NULL_ONE | NUM_NO_NEGATIVE;
2475         t->flag |= T_NO_CONSTRAINT;
2476
2477         // Calculate average radius
2478         for(i = 0 ; i < t->total; i++, td++) {
2479                 t->val += VecLenf(t->center, td->iloc);
2480         }
2481
2482         t->val /= (float)t->total;
2483 }
2484
2485 int ToSphere(TransInfo *t, short mval[2]) 
2486 {
2487         float vec[3];
2488         float ratio, radius;
2489         int i;
2490         char str[64];
2491         TransData *td = t->data;
2492
2493         ratio = InputHorizontalRatio(t, mval);
2494
2495         snapGrid(t, &ratio);
2496
2497         applyNumInput(&t->num, &ratio);
2498
2499         if (ratio < 0)
2500                 ratio = 0.0f;
2501         else if (ratio > 1)
2502                 ratio = 1.0f;
2503
2504         /* header print for NumInput */
2505         if (hasNumInput(&t->num)) {
2506                 char c[20];
2507
2508                 outputNumInput(&(t->num), c);
2509
2510                 sprintf(str, "To Sphere: %s %s", c, t->proptext);
2511         }
2512         else {
2513                 /* default header print */
2514                 sprintf(str, "To Sphere: %.4f %s", ratio, t->proptext);
2515         }
2516         
2517         
2518         for(i = 0 ; i < t->total; i++, td++) {
2519                 float tratio;
2520                 if (td->flag & TD_NOACTION)
2521                         break;
2522
2523                 if (td->flag & TD_SKIP)
2524                         continue;
2525
2526                 VecSubf(vec, td->iloc, t->center);
2527
2528                 radius = Normalize(vec);
2529
2530                 tratio = ratio * td->factor;
2531
2532                 VecMulf(vec, radius * (1.0f - tratio) + t->val * tratio);
2533
2534                 VecAddf(td->loc, t->center, vec);
2535         }
2536         
2537
2538         recalcData(t);
2539
2540         headerprint(str);
2541
2542         viewRedrawForce(t);
2543
2544         return 1;
2545 }
2546
2547 /* ************************** ROTATION *************************** */
2548
2549
2550 void initRotation(TransInfo *t) 
2551 {
2552         t->mode = TFM_ROTATION;
2553         t->transform = Rotation;
2554         
2555         t->idx_max = 0;
2556         t->num.idx_max = 0;
2557         t->snap[0] = 0.0f;
2558         t->snap[1] = (float)((5.0/180)*M_PI);
2559         t->snap[2] = t->snap[1] * 0.2f;
2560         t->fac = 0;
2561         
2562         if (t->flag & T_2D_EDIT)
2563                 t->flag |= T_NO_CONSTRAINT;
2564 }
2565
2566 static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3]) {
2567         float vec[3], totmat[3][3], smat[3][3];
2568         float eul[3], fmat[3][3], quat[4];
2569
2570         if (t->flag & T_POINTS) {
2571                 Mat3MulMat3(totmat, mat, td->mtx);
2572                 Mat3MulMat3(smat, td->smtx, totmat);
2573                 
2574                 VecSubf(vec, td->iloc, t->center);
2575                 Mat3MulVecfl(smat, vec);
2576                 
2577                 VecAddf(td->loc, vec, t->center);
2578
2579                 VecSubf(vec,td->loc,td->iloc);
2580                 protectedTransBits(td->protectflag, vec);
2581                 VecAddf(td->loc, td->iloc, vec);
2582
2583                 if(td->flag & TD_USEQUAT) {
2584                         Mat3MulSerie(fmat, td->mtx, mat, td->smtx, 0, 0, 0, 0, 0);
2585                         Mat3ToQuat(fmat, quat); // Actual transform
2586                         
2587                         if(td->ext->quat){
2588                                 QuatMul(td->ext->quat, quat, td->ext->iquat);
2589                                 
2590                                 /* is there a reason not to have this here? -jahka */
2591                                 protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat);
2592                         }
2593                 }
2594         }
2595         /**
2596          * HACK WARNING
2597          * 
2598          * This is some VERY ugly special case to deal with pose mode.
2599          * 
2600          * The problem is that mtx and smtx include each bone orientation.
2601          * 
2602          * That is needed to rotate each bone properly, HOWEVER, to calculate
2603          * the translation component, we only need the actual armature object's
2604          * matrix (and inverse). That is not all though. Once the proper translation
2605          * has been computed, it has to be converted back into the bone's space.
2606          */
2607         else if (t->flag & T_POSE) {
2608                 float pmtx[3][3], imtx[3][3];
2609
2610                 // Extract and invert armature object matrix            
2611                 Mat3CpyMat4(pmtx, t->poseobj->obmat);
2612                 Mat3Inv(imtx, pmtx);
2613                 
2614                 VecSubf(vec, td->center, t->center);
2615                 
2616                 Mat3MulVecfl(pmtx, vec);        // To Global space
2617                 Mat3MulVecfl(mat, vec);         // Applying rotation
2618                 Mat3MulVecfl(imtx, vec);        // To Local space
2619
2620                 VecAddf(vec, vec, t->center);
2621                 /* vec now is the location where the object has to be */
2622                 
2623                 VecSubf(vec, vec, td->center); // Translation needed from the initial location
2624                 
2625                 Mat3MulVecfl(pmtx, vec);        // To Global space
2626                 Mat3MulVecfl(td->smtx, vec);// To Pose space
2627
2628                 protectedTransBits(td->protectflag, vec);
2629
2630                 VecAddf(td->loc, td->iloc, vec);
2631                 
2632                 constraintTransLim(t, td);
2633                 
2634                 /* rotation */
2635                 if ((t->flag & T_V3D_ALIGN)==0) { // align mode doesn't rotate objects itself
2636                         Mat3MulSerie(fmat, td->mtx, mat, td->smtx, 0, 0, 0, 0, 0);
2637                         
2638                         Mat3ToQuat(fmat, quat); // Actual transform
2639                         
2640                         QuatMul(td->ext->quat, quat, td->ext->iquat);
2641                         /* this function works on end result */
2642                         protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat);
2643                         
2644                         constraintRotLim(t, td);
2645                 }
2646         }
2647         else {
2648                 /* translation */
2649                 VecSubf(vec, td->center, t->center);
2650                 Mat3MulVecfl(mat, vec);
2651                 VecAddf(vec, vec, t->center);
2652                 /* vec now is the location where the object has to be */
2653                 VecSubf(vec, vec, td->center);
2654                 Mat3MulVecfl(td->smtx, vec);
2655                 
2656                 protectedTransBits(td->protectflag, vec);
2657                 
2658                 if(td->tdi) {
2659                         TransDataIpokey *tdi= td->tdi;
2660                         add_tdi_poin(tdi->locx, tdi->oldloc, vec[0]);
2661                         add_tdi_poin(tdi->locy, tdi->oldloc+1, vec[1]);
2662                         add_tdi_poin(tdi->locz, tdi->oldloc+2, vec[2]);
2663                 }
2664                 else VecAddf(td->loc, td->iloc, vec);
2665                 
2666                 constraintTransLim(t, td);
2667
2668                 /* rotation */
2669                 if ((t->flag & T_V3D_ALIGN)==0) { // align mode doesn't rotate objects itself
2670                         if(td->flag & TD_USEQUAT) {
2671                                 Mat3MulSerie(fmat, td->mtx, mat, td->smtx, 0, 0, 0, 0, 0);
2672                                 Mat3ToQuat(fmat, quat); // Actual transform
2673                                 
2674                                 QuatMul(td->ext->quat, quat, td->ext->iquat);
2675                                 /* this function works on end result */
2676                                 protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat);
2677                         }
2678                         else {
2679                                 float obmat[3][3];
2680                                 
2681                                 /* are there ipo keys? */
2682                                 if(td->tdi) {
2683                                         TransDataIpokey *tdi= td->tdi;
2684                                         float rot[3];
2685                                         
2686                                         /* calculate the total rotatation in eulers */
2687                                         VecAddf(eul, td->ext->irot, td->ext->drot);
2688                                         EulToMat3(eul, obmat);
2689                                         /* mat = transform, obmat = object rotation */
2690                                         Mat3MulMat3(fmat, mat, obmat);
2691                                         
2692                                         Mat3ToCompatibleEul(fmat, eul, td->ext->irot);
2693                                         
2694                                         /* correct back for delta rot */
2695                                         if(tdi->flag & TOB_IPODROT) {
2696                                                 VecSubf(rot, eul, td->ext->irot);
2697                                         }
2698                                         else {
2699                                                 VecSubf(rot, eul, td->ext->drot);
2700                                         }
2701                                         
2702                                         VecMulf(rot, (float)(9.0/M_PI_2));
2703                                         VecSubf(rot, rot, tdi->oldrot);
2704                                         
2705                                         protectedRotateBits(td->protectflag, rot, tdi->oldrot);
2706                                         
2707                                         add_tdi_poin(tdi->rotx, tdi->oldrot, rot[0]);
2708                                         add_tdi_poin(tdi->roty, tdi->oldrot+1, rot[1]);
2709                                         add_tdi_poin(tdi->rotz, tdi->oldrot+2, rot[2]);
2710                                 }
2711                                 else {
2712                                         Mat3MulMat3(totmat, mat, td->mtx);
2713                                         Mat3MulMat3(smat, td->smtx, totmat);
2714                                         
2715                                         /* calculate the total rotatation in eulers */
2716                                         VecAddf(eul, td->ext->irot, td->ext->drot); /* we have to correct for delta rot */
2717                                         EulToMat3(eul, obmat);
2718                                         /* mat = transform, obmat = object rotation */
2719                                         Mat3MulMat3(fmat, smat, obmat);
2720                                         
2721                                         Mat3ToCompatibleEul(fmat, eul, td->ext->irot);
2722                                         
2723                                         /* correct back for delta rot */
2724                                         VecSubf(eul, eul, td->ext->drot);
2725                                         
2726                                         /* and apply */
2727                                         protectedRotateBits(td->protectflag, eul, td->ext->irot);
2728                                         VECCOPY(td->ext->rot, eul);
2729                                 }
2730                         }
2731                         
2732                         constraintRotLim(t, td);
2733                 }
2734         }
2735 }
2736
2737 static void applyRotation(TransInfo *t, float angle, float axis[3]) 
2738 {
2739         TransData *td = t->data;
2740         float mat[3][3], center[3];
2741         int i;
2742
2743         /* saving original center */
2744         if (t->around == V3D_LOCAL) {
2745                 VECCOPY(center, t->center);
2746         }
2747         else {
2748                 center[0] = center[1] = center[2] = 0.0f;
2749         }
2750
2751         VecRotToMat3(axis, angle, mat);
2752         
2753         for(i = 0 ; i < t->total; i++, td++) {
2754
2755                 if (td->flag & TD_NOACTION)
2756                         break;
2757
2758                 if (td->flag & TD_SKIP)
2759                         continue;
2760                 
2761                 /* local constraint shouldn't alter center */
2762                 if (t->around == V3D_LOCAL) {
2763                         if (t->flag & (T_OBJECT|T_POSE)) {
2764                                 VECCOPY(t->center, td->center);
2765                         }
2766                         else {
2767                                 if(G.vd->around==V3D_LOCAL && (G.scene->selectmode & SCE_SELECT_FACE)) {
2768                                         VECCOPY(t->center, td->center);
2769                                 }
2770                         }
2771                 }
2772                 
2773                 if (t->con.applyRot) {
2774                         t->con.applyRot(t, td, axis);
2775                         VecRotToMat3(axis, angle * td->factor, mat);
2776                 }
2777                 else if (t->flag & T_PROP_EDIT) {
2778                         VecRotToMat3(axis, angle * td->factor, mat);
2779                 }
2780
2781                 ElementRotation(t, td, mat);
2782         }
2783
2784         /* restoring original center */
2785         if (t->around == V3D_LOCAL) {
2786                 VECCOPY(t->center, center);
2787         }
2788 }
2789
2790 int Rotation(TransInfo *t, short mval[2]) 
2791 {
2792         char str[64];
2793
2794         float final;
2795
2796         int dx2 = t->center2d[0] - mval[0];
2797         int dy2 = t->center2d[1] - mval[1];
2798         double B = sqrt(dx2*dx2+dy2*dy2);
2799
2800         int dx1 = t->center2d[0] - t->imval[0];
2801         int dy1 = t->center2d[1] - t->imval[1];
2802         double A = sqrt(dx1*dx1+dy1*dy1);
2803
2804         int dx3 = mval[0] - t->imval[0];
2805         int dy3 = mval[1] - t->imval[1];
2806                 /* use doubles here, to make sure a "1.0" (no rotation) doesnt become 9.999999e-01, which gives 0.02 for acos */
2807         double deler= ((double)((dx1*dx1+dy1*dy1)+(dx2*dx2+dy2*dy2)-(dx3*dx3+dy3*dy3) ))
2808                 / (2.0 * (A*B?A*B:1.0));
2809         /* (A*B?A*B:1.0f) this takes care of potential divide by zero errors */
2810
2811         float dphi;
2812
2813         float axis[3];
2814         float mat[3][3];
2815
2816         VECCOPY(axis, t->viewinv[2]);
2817         VecMulf(axis, -1.0f);
2818         Normalize(axis);
2819
2820         dphi = saacos((float)deler);
2821         if( (dx1*dy2-dx2*dy1)>0.0 ) dphi= -dphi;
2822
2823         if(t->flag & T_SHIFT_MOD) t->fac += dphi/30.0f;
2824         else t->fac += dphi;
2825
2826         /*
2827         clamping angle between -2 PI and 2 PI (not sure if useful so commented out - theeth)
2828         if (t->fac >= 2 * M_PI)
2829                 t->fac -= 2 * M_PI;
2830         else if (t->fac <= -2 * M_PI)
2831                 t->fac -= -2 * M_PI;
2832         */
2833
2834         final = t->fac;
2835
2836         snapGrid(t, &final);
2837
2838         t->imval[0] = mval[0];
2839         t->imval[1] = mval[1];
2840
2841         if (t->con.applyRot) {
2842                 t->con.applyRot(t, NULL, axis);
2843         }
2844         
2845         applySnapping(t, &final);
2846
2847         if (hasNumInput(&t->num)) {
2848                 char c[20];
2849
2850                 applyNumInput(&t->num, &final);
2851
2852                 outputNumInput(&(t->num), c);
2853
2854                 sprintf(str, "Rot: %s %s %s", &c[0], t->con.text, t->proptext);
2855
2856                 /* Clamp between -180 and 180 */
2857                 while (final >= 180.0)
2858                         final -= 360.0;
2859                 
2860                 while (final <= -180.0)
2861                         final += 360.0;
2862
2863                 final *= (float)(M_PI / 180.0);
2864         }
2865         else {
2866                 sprintf(str, "Rot: %.2f%s %s", 180.0*final/M_PI, t->con.text, t->proptext);
2867         }
2868
2869         VecRotToMat3(axis, final, mat);
2870
2871         t->val = final;                         // used in manipulator
2872         Mat3CpyMat3(t->mat, mat);       // used in manipulator
2873         
2874         applyRotation(t, final, axis);
2875         
2876         recalcData(t);
2877
2878         headerprint(str);
2879
2880         viewRedrawForce(t);
2881
2882         if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
2883
2884         return 1;
2885 }
2886
2887
2888 /* ************************** TRACKBALL *************************** */
2889
2890 void initTrackball(TransInfo *t) 
2891 {
2892         t->mode = TFM_TRACKBALL;
2893         t->transform = Trackball;
2894
2895         t->idx_max = 1;
2896         t->num.idx_max = 1;
2897         t->snap[0] = 0.0f;
2898         t->snap[1] = (float)((5.0/180)*M_PI);
2899         t->snap[2] = t->snap[1] * 0.2f;
2900         t->fac = 0;
2901         
2902         t->flag |= T_NO_CONSTRAINT;
2903 }
2904
2905 static void applyTrackball(TransInfo *t, float axis1[3], float axis2[3], float angles[2])
2906 {
2907         TransData *td = t->data;
2908         float mat[3][3], smat[3][3], totmat[3][3];
2909         float center[3];
2910         int i;
2911
2912         VecRotToMat3(axis1, angles[0], smat);
2913         VecRotToMat3(axis2, angles[1], totmat);
2914         
2915         Mat3MulMat3(mat, smat, totmat);
2916
2917         for(i = 0 ; i < t->total; i++, td++) {
2918                 if (td->flag & TD_NOACTION)
2919                         break;
2920
2921                 if (td->flag & TD_SKIP)
2922                         continue;
2923                 
2924                 VECCOPY(center, t->center);
2925                 
2926                 if (t->around == V3D_LOCAL) {
2927                         /* local-mode shouldn't change center */
2928                         if (t->flag & (T_OBJECT|T_POSE)) {
2929                                 VECCOPY(t->center, td->center);
2930                         }
2931                         else {
2932                                 if(G.vd->around==V3D_LOCAL && (G.scene->selectmode & SCE_SELECT_FACE)) {
2933                                         VECCOPY(t->center, td->center);
2934                                 }
2935                         }
2936                 }
2937                 
2938                 if (t->flag & T_PROP_EDIT) {
2939                         VecRotToMat3(axis1, td->factor * angles[0], smat);
2940                         VecRotToMat3(axis2, td->factor * angles[1], totmat);
2941                         
2942                         Mat3MulMat3(mat, smat, totmat);
2943                 }
2944                 
2945                 ElementRotation(t, td, mat);
2946                 
2947                 VECCOPY(t->center, center);
2948         }
2949 }
2950
2951 int Trackball(TransInfo *t, short mval[2]) 
2952 {
2953         char str[128];
2954         float axis1[3], axis2[3];
2955         float mat[3][3], totmat[3][3], smat[3][3];
2956         float phi[2];
2957         
2958         VECCOPY(axis1, t->persinv[0]);
2959         VECCOPY(axis2, t->persinv[1]);
2960         Normalize(axis1);
2961         Normalize(axis2);
2962         
2963         /* factore has to become setting or so */
2964         phi[0]= 0.01f*(float)( t->imval[1] - mval[1] );
2965         phi[1]= 0.01f*(float)( mval[0] - t->imval[0] );
2966                 
2967         snapGrid(t, phi);
2968         
2969         if (hasNumInput(&t->num)) {
2970                 char c[40];
2971                 
2972                 applyNumInput(&t->num, phi);
2973                 
2974                 outputNumInput(&(t->num), c);
2975                 
2976                 sprintf(str, "Trackball: %s %s %s", &c[0], &c[20], t->proptext);
2977                 
2978                 phi[0] *= (float)(M_PI / 180.0);
2979                 phi[1] *= (float)(M_PI / 180.0);
2980         }
2981         else {
2982                 sprintf(str, "Trackball: %.2f %.2f %s", 180.0*phi[0]/M_PI, 180.0*phi[1]/M_PI, t->proptext);
2983         
2984                 if(t->flag & T_SHIFT_MOD) {
2985                         if(phi[0] != 0.0) phi[0]/= 5.0f;
2986                         if(phi[1] != 0.0) phi[1]/= 5.0f;
2987                 }
2988         }
2989
2990         VecRotToMat3(axis1, phi[0], smat);
2991         VecRotToMat3(axis2, phi[1], totmat);
2992         
2993         Mat3MulMat3(mat, smat, totmat);
2994         
2995         Mat3CpyMat3(t->mat, mat);       // used in manipulator
2996         
2997         applyTrackball(t, axis1, axis2, phi);
2998         
2999         recalcData(t);
3000         
3001         headerprint(str);
3002         
3003         viewRedrawForce(t);
3004         
3005         if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
3006         
3007         return 1;
3008 }
3009
3010 /* ************************** TRANSLATION *************************** */
3011         
3012 void initTranslation(TransInfo *t) 
3013 {
3014         t->mode = TFM_TRANSLATION;
3015         t->transform = Translation;
3016
3017         t->idx_max = (t->flag & T_2D_EDIT)? 1: 2;
3018         t->num.flag = 0;
3019         t->num.idx_max = t->idx_max;
3020         
3021
3022         if(t->spacetype == SPACE_VIEW3D) {
3023                 /* initgrabz() defines a factor for perspective depth correction, used in window_to_3d() */
3024                 if(t->flag & (T_EDIT|T_POSE)) {
3025                         Object *ob= G.obedit?G.obedit:t->poseobj;
3026                         float vec[3];
3027                         
3028                         VECCOPY(vec, t->center);
3029                         Mat4MulVecfl(ob->obmat, vec);
3030                         initgrabz(vec[0], vec[1], vec[2]);
3031                 }
3032                 else {
3033                         initgrabz(t->center[0], t->center[1], t->center[2]);
3034                 } 
3035
3036                 t->snap[0] = 0.0f;
3037                 t->snap[1] = G.vd->gridview * 1.0f;
3038                 t->snap[2] = t->snap[1] * 0.1f;
3039         }
3040         else if(t->spacetype == SPACE_IMAGE) {
3041                 t->snap[0] = 0.0f;
3042                 t->snap[1] = 0.125f;
3043                 t->snap[2] = 0.0625f;
3044         }
3045         else {
3046                 t->snap[0] = 0.0f;
3047                 t->snap[1] = t->snap[2] = 1.0f;
3048         }
3049 }
3050
3051 static void headerTranslation(TransInfo *t, float vec[3], char *str) {
3052         char tvec[60];
3053         char distvec[20];
3054         char autoik[20];
3055         float dvec[3];
3056         float dist;
3057         
3058         convertVecToDisplayNum(vec, dvec);
3059
3060         if (hasNumInput(&t->num)) {
3061                 outputNumInput(&(t->num), tvec);
3062                 dist = VecLength(t->num.val);
3063         }
3064         else {
3065                 dist = VecLength(vec);
3066                 sprintf(&tvec[0], "%.4f", dvec[0]);
3067                 sprintf(&tvec[20], "%.4f", dvec[1]);
3068                 sprintf(&tvec[40], "%.4f", dvec[2]);
3069         }
3070
3071         if( dist > 1e10 || dist < -1e10 )       /* prevent string buffer overflow */
3072                 sprintf(distvec, "%.4e", dist);
3073         else
3074                 sprintf(distvec, "%.4f", dist);
3075                 
3076         if(t->flag & T_AUTOIK) {
3077                 short chainlen= G.scene->toolsettings->autoik_chainlen;
3078                 
3079                 if(chainlen)
3080                         sprintf(autoik, "AutoIK-Len: %d", chainlen);
3081                 else
3082                         strcpy(autoik, "");
3083         }
3084         else
3085                 strcpy(autoik, "");
3086
3087         if (t->con.mode & CON_APPLY) {
3088                 switch(t->num.idx_max) {
3089                 case 0:
3090                         sprintf(str, "D: %s (%s)%s %s  %s", &tvec[0], distvec, t->con.text, t->proptext, &autoik[0]);
3091                         break;
3092                 case 1:
3093                         sprintf(str, "D: %s   D: %s (%s)%s %s  %s", &tvec[0], &tvec[20], distvec, t->con.text, t->proptext, &autoik[0]);
3094                         break;
3095                 case 2:
3096                         sprintf(str, "D: %s   D: %s  D: %s (%s)%s %s  %s", &tvec[0], &tvec[20], &tvec[40], distvec, t->con.text, t->proptext, &autoik[0]);
3097                 }
3098         }
3099         else {
3100                 if(t->flag & T_2D_EDIT)
3101                         sprintf(str, "Dx: %s   Dy: %s (%s)%s %s", &tvec[0], &tvec[20], distvec, t->con.text, t->proptext);
3102                 else
3103                         sprintf(str, "Dx: %s   Dy: %s  Dz: %s (%s)%s %s  %s", &tvec[0], &tvec[20], &tvec[40], distvec, t->con.text, t->proptext, &autoik[0]);
3104         }
3105 }
3106
3107 static void applyTranslation(TransInfo *t, float vec[3]) {
3108         TransData *td = t->data;
3109         float tvec[3];
3110         int i;
3111
3112         for(i = 0 ; i < t->total; i++, td++) {
3113                 if (td->flag & TD_NOACTION)
3114                         break;
3115                 
3116                 if (td->flag & TD_SKIP)
3117                         continue;
3118                 
3119                 if (t->con.applyVec) {
3120                         float pvec[3];
3121                         t->con.applyVec(t, td, vec, tvec, pvec);
3122                 }
3123                 else {
3124                         VECCOPY(tvec, vec);
3125                 }
3126                 
3127                 Mat3MulVecfl(td->smtx, tvec);
3128                 VecMulf(tvec, td->factor);
3129                 
3130                 protectedTransBits(td->protectflag, tvec);
3131                 
3132                 /* transdata ipokey */
3133                 if(td->tdi) {
3134                         TransDataIpokey *tdi= td->tdi;
3135                         add_tdi_poin(tdi->locx, tdi->oldloc, tvec[0]);
3136                         add_tdi_poin(tdi->locy, tdi->oldloc+1, tvec[1]);
3137                         add_tdi_poin(tdi->locz, tdi->oldloc+2, tvec[2]);
3138                 }
3139                 else VecAddf(td->loc, td->iloc, tvec);
3140                 
3141                 constraintTransLim(t, td);
3142         }
3143 }
3144
3145 /* uses t->vec to store actual translation in */
3146 int Translation(TransInfo *t, short mval[2]) 
3147 {
3148         float tvec[3];
3149         char str[250];
3150         
3151         if(t->flag & T_SHIFT_MOD) {
3152                 float dvec[3];
3153                 /* calculate the main translation and the precise one separate */
3154                 convertViewVec(t, dvec, (short)(mval[0] - t->shiftmval[0]), (short)(mval[1] - t->shiftmval[1]));
3155                 VecMulf(dvec, 0.1f);
3156                 convertViewVec(t, t->vec, (short)(t->shiftmval[0] - t->imval[0]), (short)(t->shiftmval[1] - t->imval[1]));
3157                 VecAddf(t->vec, t->vec, dvec);
3158         }
3159         else convertViewVec(t, t->vec, (short)(mval[0] - t->imval[0]), (short)(mval[1] - t->imval[1]));
3160
3161         if (t->con.mode & CON_APPLY) {
3162                 float pvec[3] = {0.0f, 0.0f, 0.0f};
3163                 applySnapping(t, t->vec);
3164                 t->con.applyVec(t, NULL, t->vec, tvec, pvec);
3165                 VECCOPY(t->vec, tvec);
3166                 headerTranslation(t, pvec, str);
3167         }
3168         else {
3169                 snapGrid(t, t->vec);
3170                 applyNumInput(&t->num, t->vec);
3171                 applySnapping(t, t->vec);
3172                 headerTranslation(t, t->vec, str);
3173         }
3174         
3175         applyTranslation(t, t->vec);
3176
3177         /* evil hack - redo translation if cliiping needeed */
3178         if (t->flag & T_CLIP_UV && clipUVTransform(t, t->vec, 0))
3179                 applyTranslation(t, t->vec);
3180
3181