=== Mirror Tool ===
[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                 case TFM_MIRROR:
892                         return "Mirror";
893         }
894         return "Transform";
895 }
896
897 /* ************************************************* */
898
899 static void transformEvent(unsigned short event, short val) {
900         float mati[3][3] = {{1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 1.0f}};
901         char cmode = constraintModeToChar(&Trans);
902
903         if (val) {
904                 switch (event){
905                 /* enforce redraw of transform when modifiers are used */
906                 case LEFTCTRLKEY:
907                 case RIGHTCTRLKEY:
908                         Trans.redraw = 1;
909                         break;
910                 case LEFTSHIFTKEY:
911                 case RIGHTSHIFTKEY:
912                         /* shift is modifier for higher resolution transform, works nice to store this mouse position */
913                         getmouseco_areawin(Trans.shiftmval);
914                         Trans.flag |= T_SHIFT_MOD;
915                         Trans.redraw = 1;
916                         break;
917                         
918                 case SPACEKEY:
919                         if ((Trans.spacetype==SPACE_VIEW3D) && (G.qual & LR_ALTKEY)) {
920                                 short mval[2];
921                                 
922                                 getmouseco_sc(mval);
923                                 BIF_selectOrientation();
924                                 calc_manipulator_stats(curarea);
925                                 Mat3CpyMat4(Trans.spacemtx, G.vd->twmat);
926                                 warp_pointer(mval[0], mval[1]);
927                         }
928                         else {
929                                 Trans.state = TRANS_CONFIRM;
930                         }
931                         break;
932                         
933                         
934                 case MIDDLEMOUSE:
935                         if ((Trans.flag & T_NO_CONSTRAINT)==0) {
936                                 /* exception for switching to dolly, or trackball, in camera view */
937                                 if (Trans.flag & T_CAMERA) {
938                                         if (Trans.mode==TFM_TRANSLATION)
939                                                 setLocalConstraint(&Trans, (CON_AXIS2), "along local Z");
940                                         else if (Trans.mode==TFM_ROTATION) {
941                                                 restoreTransObjects(&Trans);
942                                                 initTrackball(&Trans);
943                                         }
944                                 }
945                                 else {
946                                         Trans.flag |= T_MMB_PRESSED;
947                                         if (Trans.con.mode & CON_APPLY) {
948                                                 stopConstraint(&Trans);
949                                         }
950                                         else {
951                                                 if (G.qual & LR_CTRLKEY) {
952                                                         initSelectConstraint(&Trans, Trans.spacemtx);
953                                                 }
954                                                 else {
955                                                         /* bit hackish... but it prevents mmb select to print the orientation from menu */
956                                                         strcpy(Trans.spacename, "global");
957                                                         initSelectConstraint(&Trans, mati);
958                                                 }
959                                                 postSelectConstraint(&Trans);
960                                         }
961                                 }
962                                 Trans.redraw = 1;
963                         }
964                         break;
965                 case ESCKEY:
966                 case RIGHTMOUSE:
967                         Trans.state = TRANS_CANCEL;
968                         break;
969                 case LEFTMOUSE:
970                 case PADENTER:
971                 case RETKEY:
972                         Trans.state = TRANS_CONFIRM;
973                         break;
974                 case GKEY:
975                         /* only switch when... */
976                         if( ELEM3(Trans.mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL) ) { 
977                                 restoreTransObjects(&Trans);
978                                 initTranslation(&Trans);
979                                 Trans.redraw = 1;
980                         }
981                         break;
982                 case SKEY:
983                         /* only switch when... */
984                         if( ELEM3(Trans.mode, TFM_ROTATION, TFM_TRANSLATION, TFM_TRACKBALL) ) { 
985                                 restoreTransObjects(&Trans);
986                                 initResize(&Trans);
987                                 Trans.redraw = 1;
988                         }
989                         break;
990                 case RKEY:
991                         /* only switch when... */
992                         if( ELEM4(Trans.mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION) ) { 
993                                 
994                                 if (Trans.mode == TFM_ROTATION) {
995                                         restoreTransObjects(&Trans);
996                                         initTrackball(&Trans);
997                                 }
998                                 else {
999                                         restoreTransObjects(&Trans);
1000                                         initRotation(&Trans);
1001                                 }
1002                                 Trans.redraw = 1;
1003                         }
1004                         break;
1005                 case CKEY:
1006                         if (G.qual & LR_ALTKEY) {
1007                                 Trans.flag ^= T_PROP_CONNECTED;
1008                                 sort_trans_data_dist(&Trans);
1009                                 calculatePropRatio(&Trans);
1010                                 Trans.redraw= 1;
1011                         }
1012                         else {
1013                                 stopConstraint(&Trans);
1014                                 Trans.redraw = 1;
1015                         }
1016                         break;
1017                 case XKEY:
1018                         if ((Trans.flag & T_NO_CONSTRAINT)==0) {
1019                                 if (cmode == 'X') {
1020                                         if (Trans.flag & T_2D_EDIT) {
1021                                                 stopConstraint(&Trans);
1022                                         }
1023                                         else {
1024                                                 if (Trans.con.mode & CON_USER) {
1025                                                         stopConstraint(&Trans);
1026                                                 }
1027                                                 else {
1028                                                         if (G.qual == 0)
1029                                                                 setUserConstraint(&Trans, (CON_AXIS0), "along %s X");
1030                                                         else if (G.qual == LR_SHIFTKEY)
1031                                                                 setUserConstraint(&Trans, (CON_AXIS1|CON_AXIS2), "locking %s X");
1032                                                 }
1033                                         }
1034                                 }
1035                                 else {
1036                                         if (Trans.flag & T_2D_EDIT) {
1037                                                 setConstraint(&Trans, mati, (CON_AXIS0), "along X axis");
1038                                         }
1039                                         else {
1040                                                 if (G.qual == 0)
1041                                                         setConstraint(&Trans, mati, (CON_AXIS0), "along global X");
1042                                                 else if (G.qual == LR_SHIFTKEY)
1043                                                         setConstraint(&Trans, mati, (CON_AXIS1|CON_AXIS2), "locking global X");
1044                                         }
1045                                 }
1046                                 Trans.redraw = 1;
1047                         }
1048                         break;
1049                 case YKEY:
1050                         if ((Trans.flag & T_NO_CONSTRAINT)==0) {
1051                                 if (cmode == 'Y') {
1052                                         if (Trans.flag & T_2D_EDIT) {
1053                                                 stopConstraint(&Trans);
1054                                         }
1055                                         else {
1056                                                 if (Trans.con.mode & CON_USER) {
1057                                                         stopConstraint(&Trans);
1058                                                 }
1059                                                 else {
1060                                                         if (G.qual == 0)
1061                                                                 setUserConstraint(&Trans, (CON_AXIS1), "along %s Y");
1062                                                         else if (G.qual == LR_SHIFTKEY)
1063                                                                 setUserConstraint(&Trans, (CON_AXIS0|CON_AXIS2), "locking %s Y");
1064                                                 }
1065                                         }
1066                                 }
1067                                 else {
1068                                         if (Trans.flag & T_2D_EDIT) {
1069                                                 setConstraint(&Trans, mati, (CON_AXIS1), "along Y axis");
1070                                         }
1071                                         else {
1072                                                 if (G.qual == 0)
1073                                                         setConstraint(&Trans, mati, (CON_AXIS1), "along global Y");
1074                                                 else if (G.qual == LR_SHIFTKEY)
1075                                                         setConstraint(&Trans, mati, (CON_AXIS0|CON_AXIS2), "locking global Y");
1076                                         }
1077                                 }
1078                                 Trans.redraw = 1;
1079                         }
1080                         break;
1081                 case ZKEY:
1082                         if ((Trans.flag & T_NO_CONSTRAINT)==0) {
1083                                 if (cmode == 'Z') {
1084                                         if (Trans.con.mode & CON_USER) {
1085                                                 stopConstraint(&Trans);
1086                                         }
1087                                         else {
1088                                                 if (G.qual == 0)
1089                                                         setUserConstraint(&Trans, (CON_AXIS2), "along %s Z");
1090                                                 else if ((G.qual == LR_SHIFTKEY) && ((Trans.flag & T_2D_EDIT)==0))
1091                                                         setUserConstraint(&Trans, (CON_AXIS0|CON_AXIS1), "locking %s Z");
1092                                         }
1093                                 }
1094                                 else if ((Trans.flag & T_2D_EDIT)==0) {
1095                                         if (G.qual == 0)
1096                                                 setConstraint(&Trans, mati, (CON_AXIS2), "along global Z");
1097                                         else if (G.qual == LR_SHIFTKEY)
1098                                                 setConstraint(&Trans, mati, (CON_AXIS0|CON_AXIS1), "locking global Z");
1099                                 }
1100                                 Trans.redraw = 1;
1101                         }
1102                         break;
1103                 case OKEY:
1104                         if (Trans.flag & T_PROP_EDIT && G.qual==LR_SHIFTKEY) {
1105                                 G.scene->prop_mode = (G.scene->prop_mode+1)%6;
1106                                 calculatePropRatio(&Trans);
1107                                 Trans.redraw= 1;
1108                         }
1109                         break;
1110                 case PADPLUSKEY:
1111                         if(G.qual & LR_ALTKEY && Trans.flag & T_PROP_EDIT) {
1112                                 Trans.propsize*= 1.1f;
1113                                 calculatePropRatio(&Trans);
1114                         }
1115                         Trans.redraw= 1;
1116                         break;
1117                 case PAGEUPKEY:
1118                 case WHEELDOWNMOUSE:
1119                         if (Trans.flag & T_AUTOIK) {
1120                                 transform_autoik_update(&Trans, 1);
1121                         }
1122                         else if(Trans.flag & T_PROP_EDIT) {
1123                                 Trans.propsize*= 1.1f;
1124                                 calculatePropRatio(&Trans);
1125                         }
1126                         else view_editmove(event);
1127                         Trans.redraw= 1;
1128                         break;
1129                 case PADMINUS:
1130                         if(G.qual & LR_ALTKEY && Trans.flag & T_PROP_EDIT) {
1131                                 Trans.propsize*= 0.90909090f;
1132                                 calculatePropRatio(&Trans);
1133                         }
1134                         Trans.redraw= 1;
1135                         break;
1136                 case PAGEDOWNKEY:
1137                 case WHEELUPMOUSE:
1138                         if (Trans.flag & T_AUTOIK) {
1139                                 transform_autoik_update(&Trans, -1);
1140                         }
1141                         else if (Trans.flag & T_PROP_EDIT) {
1142                                 Trans.propsize*= 0.90909090f;
1143                                 calculatePropRatio(&Trans);
1144                         }
1145                         else view_editmove(event);
1146                         Trans.redraw= 1;
1147                         break;
1148                 }
1149                 
1150                 // Numerical input events
1151                 Trans.redraw |= handleNumInput(&(Trans.num), event);
1152                 
1153                 // Snapping events
1154                 Trans.redraw |= handleSnapping(&Trans, event);
1155                 
1156                 arrows_move_cursor(event);
1157         }
1158         else {
1159                 switch (event){
1160                 /* no redraw on release modifier keys! this makes sure you can assign the 'grid' still 
1161                    after releasing modifer key */
1162                 case MIDDLEMOUSE:
1163                         if ((Trans.flag & T_NO_CONSTRAINT)==0) {
1164                                 Trans.flag &= ~T_MMB_PRESSED;
1165                                 postSelectConstraint(&Trans);
1166                                 Trans.redraw = 1;
1167                         }
1168                         break;
1169                 case LEFTMOUSE:
1170                 case RIGHTMOUSE:
1171                         if (Trans.context & CTX_TWEAK)
1172                                 Trans.state = TRANS_CONFIRM;
1173                         break;
1174                 case LEFTSHIFTKEY:
1175                 case RIGHTSHIFTKEY:
1176                         /* shift is modifier for higher resolution transform */
1177                         Trans.flag &= ~T_SHIFT_MOD;
1178                         break;
1179                 }
1180         }
1181         
1182         // Per transform event, if present
1183         if (Trans.handleEvent)
1184                 Trans.redraw |= Trans.handleEvent(&Trans, event, val);
1185 }
1186
1187 int calculateTransformCenter(int centerMode, float *vec)
1188 {
1189         int success = 1;
1190         checkFirstTime();
1191
1192         Trans.state = TRANS_RUNNING;
1193
1194         Trans.context = CTX_NONE;
1195         
1196         Trans.mode = TFM_DUMMY;
1197
1198         initTrans(&Trans);                                      // internal data, mouse, vectors
1199
1200         createTransData(&Trans);                        // make TransData structs from selection
1201
1202         Trans.around = centerMode;                      // override userdefined mode
1203
1204         if (Trans.total == 0) {
1205                 success = 0;
1206         }
1207         else {
1208                 success = 1;
1209                 
1210                 calculateCenter(&Trans);
1211         
1212                 // Copy center from constraint center. Transform center can be local    
1213                 VECCOPY(vec, Trans.con.center);
1214         }
1215
1216         postTrans(&Trans);
1217
1218         /* aftertrans does insert ipos and action channels, and clears base flags, doesnt read transdata */
1219         special_aftertrans_update(&Trans);
1220         
1221         return success;
1222 }
1223
1224 void initTransform(int mode, int context) {
1225         /* added initialize, for external calls to set stuff in TransInfo, like undo string */
1226         checkFirstTime();
1227
1228         Trans.state = TRANS_RUNNING;
1229
1230         Trans.context = context;
1231         
1232         Trans.mode = mode;
1233
1234         initTrans(&Trans);                                      // internal data, mouse, vectors
1235
1236         if(Trans.spacetype==SPACE_VIEW3D) {
1237                 calc_manipulator_stats(curarea);
1238                 Mat3CpyMat4(Trans.spacemtx, G.vd->twmat);
1239         }
1240         else
1241                 Mat3One(Trans.spacemtx);
1242
1243         createTransData(&Trans);                        // make TransData structs from selection
1244
1245         initSnapping(&Trans); // Initialize snapping data AFTER mode flags
1246
1247         if (Trans.total == 0) {
1248                 postTrans(&Trans);
1249                 return;
1250         }
1251
1252         /* EVIL! posemode code can switch translation to rotate when 1 bone is selected. will be removed (ton) */
1253         /* EVIL2: we gave as argument also texture space context bit... was cleared */
1254         /* EVIL3: extend mode for animation editors also switches modes... but is best way to avoid duplicate code */
1255         mode = Trans.mode;
1256         
1257         calculatePropRatio(&Trans);
1258         calculateCenter(&Trans);
1259
1260         switch (mode) {
1261         case TFM_TRANSLATION:
1262                 initTranslation(&Trans);
1263                 break;
1264         case TFM_ROTATION:
1265                 initRotation(&Trans);
1266                 break;
1267         case TFM_RESIZE:
1268                 initResize(&Trans);
1269                 break;
1270         case TFM_TOSPHERE:
1271                 initToSphere(&Trans);
1272                 break;
1273         case TFM_SHEAR:
1274                 initShear(&Trans);
1275                 break;
1276         case TFM_WARP:
1277                 initWarp(&Trans);
1278                 break;
1279         case TFM_SHRINKFATTEN:
1280                 initShrinkFatten(&Trans);
1281                 break;
1282         case TFM_TILT:
1283                 initTilt(&Trans);
1284                 break;
1285         case TFM_CURVE_SHRINKFATTEN:
1286                 initCurveShrinkFatten(&Trans);
1287                 break;
1288         case TFM_TRACKBALL:
1289                 initTrackball(&Trans);
1290                 break;
1291         case TFM_PUSHPULL:
1292                 initPushPull(&Trans);
1293                 break;
1294         case TFM_CREASE:
1295                 initCrease(&Trans);
1296                 break;
1297         case TFM_BONESIZE:
1298                 {       /* used for both B-Bone width (bonesize) as for deform-dist (envelope) */
1299                         bArmature *arm= Trans.poseobj->data;
1300                         if(arm->drawtype==ARM_ENVELOPE)
1301                                 initBoneEnvelope(&Trans);
1302                         else
1303                                 initBoneSize(&Trans);
1304                 }
1305                 break;
1306         case TFM_BONE_ENVELOPE:
1307                 initBoneEnvelope(&Trans);
1308                 break;
1309         case TFM_BONE_ROLL:
1310                 initBoneRoll(&Trans);
1311                 break;
1312         case TFM_TIME_TRANSLATE:
1313                 initTimeTranslate(&Trans);
1314                 break;
1315         case TFM_TIME_SLIDE:
1316                 initTimeSlide(&Trans);
1317                 break;
1318         case TFM_TIME_SCALE:
1319                 initTimeScale(&Trans);
1320                 break;
1321         case TFM_TIME_EXTEND: 
1322                 /* now that transdata has been made, do like for TFM_TIME_TRANSLATE */
1323                 initTimeTranslate(&Trans);
1324                 break;
1325         case TFM_BAKE_TIME:
1326                 initBakeTime(&Trans);
1327                 break;
1328         case TFM_MIRROR:
1329                 initMirror(&Trans);
1330                 break;
1331         }
1332 }
1333
1334 void Transform() 
1335 {
1336         short pmval[2] = {0, 0}, mval[2], val;
1337         unsigned short event;
1338
1339         if(Trans.total==0) return;      // added, can happen now! (ton)
1340         
1341         // Emptying event queue
1342         while( qtest() ) {
1343                 event= extern_qread(&val);
1344         }
1345
1346         Trans.redraw = 1; /* initial draw */
1347
1348         while (Trans.state == TRANS_RUNNING) {
1349
1350                 getmouseco_areawin(mval);
1351                 
1352                 if (mval[0] != pmval[0] || mval[1] != pmval[1]) {
1353                         if (Trans.flag & T_MMB_PRESSED)
1354                                 Trans.con.mode |= CON_SELECT;
1355                         Trans.redraw = 1;
1356                 }
1357                 if (Trans.redraw) {
1358                         pmval[0] = mval[0];
1359                         pmval[1] = mval[1];
1360
1361                         selectConstraint(&Trans);
1362                         if (Trans.transform) {
1363                                 Trans.transform(&Trans, mval);  // calls recalcData()
1364                         }
1365                         Trans.redraw = 0;
1366                 }
1367
1368                 /* If auto confirm is on, break after one pass */               
1369                 if (Trans.context & CTX_AUTOCONFIRM)
1370                 {
1371                         Trans.state = TRANS_CONFIRM;
1372                         break;
1373                 }
1374                 
1375                 /* essential for idling subloop */
1376                 if( qtest()==0) PIL_sleep_ms(2);
1377
1378                 while( qtest() ) {
1379                         event= extern_qread(&val);
1380                         transformEvent(event, val);
1381                 }
1382         }
1383         
1384         
1385         /* handle restoring objects */
1386         if(Trans.state == TRANS_CANCEL)
1387                 restoreTransObjects(&Trans);    // calls recalcData()
1388         
1389         /* free data */
1390         postTrans(&Trans);
1391
1392         /* aftertrans does insert ipos and action channels, and clears base flags, doesnt read transdata */
1393         special_aftertrans_update(&Trans);
1394
1395         /* send events out for redraws */
1396         viewRedrawPost(&Trans);
1397
1398         /*  Undo as last, certainly after special_trans_update! */
1399         if(Trans.state == TRANS_CANCEL) {
1400                 if(Trans.undostr) BIF_undo_push(Trans.undostr);
1401         }
1402         else {
1403                 if(Trans.undostr) BIF_undo_push(Trans.undostr);
1404                 else BIF_undo_push(transform_to_undostr(&Trans));
1405         }
1406         Trans.undostr= NULL;
1407         
1408 }
1409
1410 /* ************************** Manipulator init and main **************************** */
1411
1412 void initManipulator(int mode)
1413 {
1414         Trans.state = TRANS_RUNNING;
1415
1416         Trans.context = CTX_NONE;
1417         
1418         Trans.mode = mode;
1419         
1420         /* automatic switch to scaling bone envelopes */
1421         if(mode==TFM_RESIZE && G.obedit && G.obedit->type==OB_ARMATURE) {
1422                 bArmature *arm= G.obedit->data;
1423                 if(arm->drawtype==ARM_ENVELOPE)
1424                         mode= TFM_BONE_ENVELOPE;
1425         }
1426
1427         initTrans(&Trans);                                      // internal data, mouse, vectors
1428
1429         G.moving |= G_TRANSFORM_MANIP;          // signal to draw manipuls while transform
1430         createTransData(&Trans);                        // make TransData structs from selection
1431
1432         if (Trans.total == 0)
1433                 return;
1434
1435         initSnapping(&Trans); // Initialize snapping data AFTER mode flags
1436
1437         /* EVIL! posemode code can switch translation to rotate when 1 bone is selected. will be removed (ton) */
1438         /* EVIL2: we gave as argument also texture space context bit... was cleared */
1439         mode = Trans.mode;
1440         
1441         calculatePropRatio(&Trans);
1442         calculateCenter(&Trans);
1443
1444         switch (mode) {
1445         case TFM_TRANSLATION:
1446                 initTranslation(&Trans);
1447                 break;
1448         case TFM_ROTATION:
1449                 initRotation(&Trans);
1450                 break;
1451         case TFM_RESIZE:
1452                 initResize(&Trans);
1453                 break;
1454         case TFM_TRACKBALL:
1455                 initTrackball(&Trans);
1456                 break;
1457         }
1458
1459         Trans.flag |= T_USES_MANIPULATOR;
1460 }
1461
1462 void ManipulatorTransform() 
1463 {
1464         int mouse_moved = 0;
1465         short pmval[2] = {0, 0}, mval[2], val;
1466         unsigned short event;
1467
1468         if (Trans.total == 0)
1469                 return;
1470
1471         Trans.redraw = 1; /* initial draw */
1472
1473         while (Trans.state == TRANS_RUNNING) {
1474                 
1475                 getmouseco_areawin(mval);
1476                 
1477                 if (mval[0] != pmval[0] || mval[1] != pmval[1]) {
1478                         Trans.redraw = 1;
1479                 }
1480                 if (Trans.redraw) {
1481                         pmval[0] = mval[0];
1482                         pmval[1] = mval[1];
1483
1484                         //selectConstraint(&Trans);  needed?
1485                         if (Trans.transform) {
1486                                 Trans.transform(&Trans, mval);
1487                         }
1488                         Trans.redraw = 0;
1489                 }
1490                 
1491                 /* essential for idling subloop */
1492                 if( qtest()==0) PIL_sleep_ms(2);
1493
1494                 while( qtest() ) {
1495                         event= extern_qread(&val);
1496
1497                         switch (event){
1498                         case MOUSEX:
1499                         case MOUSEY:
1500                                 mouse_moved = 1;
1501                                 break;
1502                         /* enforce redraw of transform when modifiers are used */
1503                         case LEFTCTRLKEY:
1504                         case RIGHTCTRLKEY:
1505                                 if(val) Trans.redraw = 1;
1506                                 break;
1507                         case LEFTSHIFTKEY:
1508                         case RIGHTSHIFTKEY:
1509                                 /* shift is modifier for higher resolution transform, works nice to store this mouse position */
1510                                 if(val) {
1511                                         getmouseco_areawin(Trans.shiftmval);
1512                                         Trans.flag |= T_SHIFT_MOD;
1513                                         Trans.redraw = 1;
1514                                 }
1515                                 else Trans.flag &= ~T_SHIFT_MOD; 
1516                                 break;
1517                                 
1518                         case ESCKEY:
1519                         case RIGHTMOUSE:
1520                                 Trans.state = TRANS_CANCEL;
1521                                 break;
1522                         case LEFTMOUSE:
1523                                 if(mouse_moved==0 && val==0) break;
1524                                 // else we pass on event to next, which cancels
1525                         case SPACEKEY:
1526                         case PADENTER:
1527                         case RETKEY:
1528                                 Trans.state = TRANS_CONFIRM;
1529                                 break;
1530                         }
1531                         if(val) {
1532                                 switch(event) {
1533                                 case WHEELDOWNMOUSE:
1534                                 case PADPLUSKEY:
1535                                         if(Trans.flag & T_PROP_EDIT) {
1536                                                 Trans.propsize*= 1.1f;
1537                                                 calculatePropRatio(&Trans);
1538                                                 Trans.redraw= 1;
1539                                         }
1540                                         break;
1541                                 case WHEELUPMOUSE:
1542                                 case PADMINUS:
1543                                         if(Trans.flag & T_PROP_EDIT) {
1544                                                 Trans.propsize*= 0.90909090f;
1545                                                 calculatePropRatio(&Trans);
1546                                                 Trans.redraw= 1;
1547                                         }
1548                                         break;
1549                                 }                       
1550                         }
1551                 }
1552         }
1553         
1554         if(Trans.state == TRANS_CANCEL) {
1555                 restoreTransObjects(&Trans);
1556         }
1557         
1558         /* free data, reset vars */
1559         postTrans(&Trans);
1560         
1561         /* aftertrans does insert ipos and action channels, and clears base flags */
1562         special_aftertrans_update(&Trans);
1563         
1564         /* send events out for redraws */
1565         viewRedrawPost(&Trans);
1566
1567         if(Trans.state != TRANS_CANCEL) {
1568                 BIF_undo_push(transform_to_undostr(&Trans));
1569         }
1570         
1571 }
1572
1573 /* ************************** TRANSFORM LOCKS **************************** */
1574
1575 static void protectedTransBits(short protectflag, float *vec)
1576 {
1577         if(protectflag & OB_LOCK_LOCX)
1578                 vec[0]= 0.0f;
1579         if(protectflag & OB_LOCK_LOCY)
1580                 vec[1]= 0.0f;
1581         if(protectflag & OB_LOCK_LOCZ)
1582                 vec[2]= 0.0f;
1583 }
1584
1585 static void protectedSizeBits(short protectflag, float *size)
1586 {
1587         if(protectflag & OB_LOCK_SCALEX)
1588                 size[0]= 1.0f;
1589         if(protectflag & OB_LOCK_SCALEY)
1590                 size[1]= 1.0f;
1591         if(protectflag & OB_LOCK_SCALEZ)
1592                 size[2]= 1.0f;
1593 }
1594
1595 static void protectedRotateBits(short protectflag, float *eul, float *oldeul)
1596 {
1597         if(protectflag & OB_LOCK_ROTX)
1598                 eul[0]= oldeul[0];
1599         if(protectflag & OB_LOCK_ROTY)
1600                 eul[1]= oldeul[1];
1601         if(protectflag & OB_LOCK_ROTZ)
1602                 eul[2]= oldeul[2];
1603 }
1604
1605 static void protectedQuaternionBits(short protectflag, float *quat, float *oldquat)
1606 {
1607         /* quaternions get limited with euler... */
1608         /* this function only does the delta rotation */
1609         
1610         if(protectflag) {
1611                 float eul[3], oldeul[3], quat1[4];
1612                 
1613                 QUATCOPY(quat1, quat);
1614                 QuatToEul(quat, eul);
1615                 QuatToEul(oldquat, oldeul);
1616                 
1617                 if(protectflag & OB_LOCK_ROTX)
1618                         eul[0]= oldeul[0];
1619                 if(protectflag & OB_LOCK_ROTY)
1620                         eul[1]= oldeul[1];
1621                 if(protectflag & OB_LOCK_ROTZ)
1622                         eul[2]= oldeul[2];
1623                 
1624                 EulToQuat(eul, quat);
1625                 /* quaternions flip w sign to accumulate rotations correctly */
1626                 if( (quat1[0]<0.0f && quat[0]>0.0f) || (quat1[0]>0.0f && quat[0]<0.0f) ) {
1627                         QuatMulf(quat, -1.0f);
1628                 }
1629         }
1630 }
1631
1632 /* ******************* TRANSFORM LIMITS ********************** */
1633
1634 static void constraintTransLim(TransInfo *t, TransData *td)
1635 {
1636         if (td->con) {
1637                 bConstraintTypeInfo *cti= get_constraint_typeinfo(CONSTRAINT_TYPE_LOCLIMIT);
1638                 bConstraintOb cob;
1639                 bConstraint *con;
1640                 
1641                 /* Make a temporary bConstraintOb for using these limit constraints 
1642                  *      - they only care that cob->matrix is correctly set ;-)
1643                  *      - current space should be local
1644                  */
1645                 memset(&cob, 0, sizeof(bConstraintOb));
1646                 Mat4One(cob.matrix);
1647                 if (td->tdi) {
1648                         TransDataIpokey *tdi= td->tdi;
1649                         cob.matrix[3][0]= tdi->locx[0];
1650                         cob.matrix[3][1]= tdi->locy[0];
1651                         cob.matrix[3][2]= tdi->locz[0];
1652                 }
1653                 else {
1654                         VECCOPY(cob.matrix[3], td->loc);
1655                 }
1656                 
1657                 /* Evaluate valid constraints */
1658                 for (con= td->con; con; con= con->next) {
1659                         float tmat[4][4];
1660                                 
1661                         /* only use it if it's tagged for this purpose (and the right type) */
1662                         if (con->type == CONSTRAINT_TYPE_LOCLIMIT) {
1663                                 bLocLimitConstraint *data= con->data;
1664                                 if ((data->flag2 & LIMIT_TRANSFORM)==0) 
1665                                         continue;
1666                         }
1667                         else if (con->type == CONSTRAINT_TYPE_ROTLIMIT) {
1668                                 bRotLimitConstraint *data= con->data;
1669                                 if ((data->flag2 & LIMIT_TRANSFORM)==0) 
1670                                         continue;
1671                         }
1672                         else if (con->type == CONSTRAINT_TYPE_SIZELIMIT) {
1673                                 bSizeLimitConstraint *data= con->data;
1674                                 if ((data->flag2 & LIMIT_TRANSFORM)==0) 
1675                                         continue;
1676                         }
1677                         else {
1678                                 /* not supported */
1679                                 continue;
1680                         }
1681                                 
1682                         /* do space conversions */
1683                         if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
1684                                 /* just multiply by td->mtx (this should be ok) */
1685                                 Mat4CpyMat4(tmat, cob.matrix);
1686                                 Mat4MulMat34(cob.matrix, td->mtx, tmat);
1687                         }
1688                         else if (con->ownspace != CONSTRAINT_SPACE_LOCAL) {
1689                                 /* skip... incompatable spacetype */
1690                                 continue;
1691                         }
1692                         
1693                         /* do constraint */
1694                         cti->evaluate_constraint(con, &cob, NULL);
1695                         
1696                         /* convert spaces again */
1697                         if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
1698                                 /* just multiply by td->mtx (this should be ok) */
1699                                 Mat4CpyMat4(tmat, cob.matrix);
1700                                 Mat4MulMat34(cob.matrix, td->smtx, tmat);
1701                         }
1702                 }
1703                 
1704                 /* copy results from cob->matrix */
1705                 if (td->tdi) {
1706                         TransDataIpokey *tdi= td->tdi;
1707                         tdi->locx[0]= cob.matrix[3][0];
1708                         tdi->locy[0]= cob.matrix[3][1];
1709                         tdi->locz[0]= cob.matrix[3][2];
1710                 }
1711                 else {
1712                         VECCOPY(td->loc, cob.matrix[3]);
1713                 }
1714         }
1715 }
1716
1717 static void constraintRotLim(TransInfo *t, TransData *td)
1718 {
1719         if (td->con) {
1720                 bConstraintTypeInfo *cti= get_constraint_typeinfo(CONSTRAINT_TYPE_ROTLIMIT);
1721                 bConstraintOb cob;
1722                 bConstraint *con;
1723                 
1724                 /* Make a temporary bConstraintOb for using these limit constraints 
1725                  *      - they only care that cob->matrix is correctly set ;-)
1726                  *      - current space should be local
1727                  */
1728                 memset(&cob, 0, sizeof(bConstraintOb));
1729                 if (td->flag & TD_USEQUAT) {
1730                         /* quats */
1731                         if (td->ext)
1732                                 QuatToMat4(td->ext->quat, cob.matrix);
1733                         else
1734                                 return;
1735                 }
1736                 else if (td->tdi) {
1737                         /* ipo-keys eulers */
1738                         TransDataIpokey *tdi= td->tdi;
1739                         float eul[3];
1740                         
1741                         eul[0]= tdi->rotx[0];
1742                         eul[1]= tdi->roty[0];
1743                         eul[2]= tdi->rotz[0];
1744                         
1745                         EulToMat4(eul, cob.matrix);
1746                 }
1747                 else {
1748                         /* eulers */
1749                         if (td->ext)
1750                                 EulToMat4(td->ext->rot, cob.matrix);
1751                         else
1752                                 return;
1753                 }
1754                         
1755                 /* Evaluate valid constraints */
1756                 for (con= td->con; con; con= con->next) {
1757                         /* we're only interested in Limit-Scale constraints */
1758                         if (con->type == CONSTRAINT_TYPE_ROTLIMIT) {
1759                                 bRotLimitConstraint *data= con->data;
1760                                 float tmat[4][4];
1761                                 
1762                                 /* only use it if it's tagged for this purpose */
1763                                 if ((data->flag2 & LIMIT_TRANSFORM)==0) 
1764                                         continue;
1765                                         
1766                                 /* do space conversions */
1767                                 if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
1768                                         /* just multiply by td->mtx (this should be ok) */
1769                                         Mat4CpyMat4(tmat, cob.matrix);
1770                                         Mat4MulMat34(cob.matrix, td->mtx, tmat);
1771                                 }
1772                                 else if (con->ownspace != CONSTRAINT_SPACE_LOCAL) {
1773                                         /* skip... incompatable spacetype */
1774                                         continue;
1775                                 }
1776                                 
1777                                 /* do constraint */
1778                                 cti->evaluate_constraint(con, &cob, NULL);
1779                                 
1780                                 /* convert spaces again */
1781                                 if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
1782                                         /* just multiply by td->mtx (this should be ok) */
1783                                         Mat4CpyMat4(tmat, cob.matrix);
1784                                         Mat4MulMat34(cob.matrix, td->smtx, tmat);
1785                                 }
1786                         }
1787                 }
1788                 
1789                 /* copy results from cob->matrix */
1790                 if (td->flag & TD_USEQUAT) {
1791                         /* quats */
1792                         Mat4ToQuat(cob.matrix, td->ext->quat);
1793                 }
1794                 else if (td->tdi) {
1795                         /* ipo-keys eulers */
1796                         TransDataIpokey *tdi= td->tdi;
1797                         float eul[3];
1798                         
1799                         Mat4ToEul(cob.matrix, eul);
1800                         
1801                         tdi->rotx[0]= eul[0];
1802                         tdi->roty[0]= eul[1];
1803                         tdi->rotz[0]= eul[2];
1804                 }
1805                 else {
1806                         /* eulers */
1807                         Mat4ToEul(cob.matrix, td->ext->rot);
1808                 }
1809         }
1810 }
1811
1812 static void constraintSizeLim(TransInfo *t, TransData *td)
1813 {
1814         if (td->con && td->ext) {
1815                 bConstraintTypeInfo *cti= get_constraint_typeinfo(CONSTRAINT_TYPE_SIZELIMIT);
1816                 bConstraintOb cob;
1817                 bConstraint *con;
1818                 
1819                 /* Make a temporary bConstraintOb for using these limit constraints 
1820                  *      - they only care that cob->matrix is correctly set ;-)
1821                  *      - current space should be local
1822                  */
1823                 memset(&cob, 0, sizeof(bConstraintOb));
1824                 if (td->tdi) {
1825                         TransDataIpokey *tdi= td->tdi;
1826                         float size[3];
1827                         
1828                         size[0]= tdi->sizex[0];
1829                         size[1]= tdi->sizey[0];
1830                         size[2]= tdi->sizez[0];
1831                         SizeToMat4(size, cob.matrix);
1832                 } 
1833                 else if ((td->flag & TD_SINGLESIZE) && !(t->con.mode & CON_APPLY)) {
1834                         /* scale val and reset size */
1835                         return; // TODO: fix this case
1836                 }
1837                 else {
1838                         /* Reset val if SINGLESIZE but using a constraint */
1839                         if (td->flag & TD_SINGLESIZE)
1840                                 return;
1841                         
1842                         SizeToMat4(td->ext->size, cob.matrix);
1843                 }
1844                         
1845                 /* Evaluate valid constraints */
1846                 for (con= td->con; con; con= con->next) {
1847                         /* we're only interested in Limit-Scale constraints */
1848                         if (con->type == CONSTRAINT_TYPE_SIZELIMIT) {
1849                                 bSizeLimitConstraint *data= con->data;
1850                                 float tmat[4][4];
1851                                 
1852                                 /* only use it if it's tagged for this purpose */
1853                                 if ((data->flag2 & LIMIT_TRANSFORM)==0) 
1854                                         continue;
1855                                         
1856                                 /* do space conversions */
1857                                 if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
1858                                         /* just multiply by td->mtx (this should be ok) */
1859                                         Mat4CpyMat4(tmat, cob.matrix);
1860                                         Mat4MulMat34(cob.matrix, td->mtx, tmat);
1861                                 }
1862                                 else if (con->ownspace != CONSTRAINT_SPACE_LOCAL) {
1863                                         /* skip... incompatable spacetype */
1864                                         continue;
1865                                 }
1866                                 
1867                                 /* do constraint */
1868                                 cti->evaluate_constraint(con, &cob, NULL);
1869                                 
1870                                 /* convert spaces again */
1871                                 if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
1872                                         /* just multiply by td->mtx (this should be ok) */
1873                                         Mat4CpyMat4(tmat, cob.matrix);
1874                                         Mat4MulMat34(cob.matrix, td->smtx, tmat);
1875                                 }
1876                         }
1877                 }
1878                 
1879                 /* copy results from cob->matrix */
1880                 if (td->tdi) {
1881                         TransDataIpokey *tdi= td->tdi;
1882                         float size[3];
1883                         
1884                         Mat4ToSize(cob.matrix, size);
1885                         
1886                         tdi->sizex[0]= size[0];
1887                         tdi->sizey[0]= size[1];
1888                         tdi->sizez[0]= size[2];
1889                 } 
1890                 else if ((td->flag & TD_SINGLESIZE) && !(t->con.mode & CON_APPLY)) {
1891                         /* scale val and reset size */
1892                         return; // TODO: fix this case
1893                 }
1894                 else {
1895                         /* Reset val if SINGLESIZE but using a constraint */
1896                         if (td->flag & TD_SINGLESIZE)
1897                                 return;
1898                                 
1899                         Mat4ToSize(cob.matrix, td->ext->size);
1900                 }
1901         }
1902 }
1903
1904 /* ************************** WARP *************************** */
1905
1906 void initWarp(TransInfo *t) 
1907 {
1908         float max[3], min[3];
1909         int i;
1910         
1911         t->mode = TFM_WARP;
1912         t->transform = Warp;
1913         t->handleEvent = handleEventWarp;
1914         
1915         t->idx_max = 0;
1916         t->num.idx_max = 0;
1917         t->snap[0] = 0.0f;
1918         t->snap[1] = 5.0f;
1919         t->snap[2] = 1.0f;
1920         
1921         t->flag |= T_NO_CONSTRAINT;
1922
1923 /* warp is done fully in view space */
1924         calculateCenterCursor(t);
1925         t->fac = (float)(t->center2d[0] - t->imval[0]);
1926         
1927         /* we need min/max in view space */
1928         for(i = 0; i < t->total; i++) {
1929                 float center[3];
1930                 VECCOPY(center, t->data[i].center);
1931                 Mat3MulVecfl(t->data[i].mtx, center);
1932                 Mat4MulVecfl(t->viewmat, center);
1933                 VecSubf(center, center, t->viewmat[3]);
1934                 if (i)
1935                         MinMax3(min, max, center);
1936                 else {
1937                         VECCOPY(max, center);
1938                         VECCOPY(min, center);
1939                 }
1940         }
1941         
1942         t->center[0]= (min[0]+max[0])/2.0f;
1943         t->center[1]= (min[1]+max[1])/2.0f;
1944         t->center[2]= (min[2]+max[2])/2.0f;
1945         
1946         if (max[0] == min[0]) max[0] += 0.1; /* not optimal, but flipping is better than invalid garbage (i.e. division by zero!) */
1947         t->val= (max[0]-min[0])/2.0f; /* t->val is X dimension projected boundbox */
1948 }
1949
1950 int handleEventWarp(TransInfo *t, unsigned short event, short val)
1951 {
1952         int status = 0;
1953         
1954         if (event == MIDDLEMOUSE && val)
1955         {
1956                 // Use customData pointer to signal warp direction
1957                 if      (t->customData == 0)
1958                         t->customData = (void*)1;
1959                 else
1960                         t->customData = 0;
1961                         
1962                 status = 1;
1963         }
1964         
1965         return status;
1966 }
1967
1968 int Warp(TransInfo *t, short mval[2])
1969 {
1970         TransData *td = t->data;
1971         float vec[3], circumfac, dist, phi0, co, si, *curs, cursor[3], gcursor[3];
1972         int i;
1973         char str[50];
1974         
1975         curs= give_cursor();
1976         /*
1977          * gcursor is the one used for helpline.
1978          * It has to be in the same space as the drawing loop
1979          * (that means it needs to be in the object's space when in edit mode and
1980          *  in global space in object mode)
1981          *
1982          * cursor is used for calculations.
1983          * It needs to be in view space, but we need to take object's offset
1984          * into account if in Edit mode.
1985          */
1986         VECCOPY(cursor, curs);
1987         VECCOPY(gcursor, cursor);       
1988         if (t->flag & T_EDIT) {
1989                 VecSubf(cursor, cursor, G.obedit->obmat[3]);
1990                 VecSubf(gcursor, gcursor, G.obedit->obmat[3]);
1991                 Mat3MulVecfl(t->data->smtx, gcursor);
1992         }
1993         Mat4MulVecfl(t->viewmat, cursor);
1994         VecSubf(cursor, cursor, t->viewmat[3]);
1995
1996         /* amount of degrees for warp */
1997         circumfac= 360.0f * InputHorizontalRatio(t, mval);
1998         
1999         if (t->customData) /* non-null value indicates reversed input */
2000         {
2001                 circumfac *= -1;
2002         }
2003
2004         snapGrid(t, &circumfac);
2005         applyNumInput(&t->num, &circumfac);
2006         
2007         /* header print for NumInput */
2008         if (hasNumInput(&t->num)) {
2009                 char c[20];
2010                 
2011                 outputNumInput(&(t->num), c);
2012                 
2013                 sprintf(str, "Warp: %s", c);
2014         }
2015         else {
2016                 /* default header print */
2017                 sprintf(str, "Warp: %.3f", circumfac);
2018         }
2019         
2020         circumfac*= (float)(-M_PI/360.0);
2021         
2022         for(i = 0; i < t->total; i++, td++) {
2023                 float loc[3];
2024                 if (td->flag & TD_NOACTION)
2025                         break;
2026
2027                 if (td->flag & TD_SKIP)
2028                         continue;
2029                 
2030                 /* translate point to center, rotate in such a way that outline==distance */
2031                 VECCOPY(vec, td->iloc);
2032                 Mat3MulVecfl(td->mtx, vec);
2033                 Mat4MulVecfl(t->viewmat, vec);
2034                 VecSubf(vec, vec, t->viewmat[3]);
2035                 
2036                 dist= vec[0]-cursor[0];
2037                 
2038                 /* t->val is X dimension projected boundbox */
2039                 phi0= (circumfac*dist/t->val);  
2040                 
2041                 vec[1]= (vec[1]-cursor[1]);
2042                 
2043                 co= (float)cos(phi0);
2044                 si= (float)sin(phi0);
2045                 loc[0]= -si*vec[1]+cursor[0];
2046                 loc[1]= co*vec[1]+cursor[1];
2047                 loc[2]= vec[2];
2048                 
2049                 Mat4MulVecfl(t->viewinv, loc);
2050                 VecSubf(loc, loc, t->viewinv[3]);
2051                 Mat3MulVecfl(td->smtx, loc);
2052                 
2053                 VecSubf(loc, loc, td->iloc);
2054                 VecMulf(loc, td->factor);
2055                 VecAddf(td->loc, td->iloc, loc);
2056         }
2057
2058         recalcData(t);
2059         
2060         headerprint(str);
2061         
2062         viewRedrawForce(t);
2063         
2064         helpline(t, gcursor);
2065         
2066         return 1;
2067 }
2068
2069 /* ************************** SHEAR *************************** */
2070
2071 void initShear(TransInfo *t) 
2072 {
2073         t->mode = TFM_SHEAR;
2074         t->transform = Shear;
2075         t->handleEvent = handleEventShear;
2076         
2077         t->idx_max = 0;
2078         t->num.idx_max = 0;
2079         t->snap[0] = 0.0f;
2080         t->snap[1] = 0.1f;
2081         t->snap[2] = t->snap[1] * 0.1f;
2082         
2083         t->flag |= T_NO_CONSTRAINT;
2084 }
2085
2086 int handleEventShear(TransInfo *t, unsigned short event, short val)
2087 {
2088         int status = 0;
2089         
2090         if (event == MIDDLEMOUSE && val)
2091         {
2092                 // Use customData pointer to signal Shear direction
2093                 if      (t->customData == 0)
2094                         t->customData = (void*)1;
2095                 else
2096                         t->customData = 0;
2097                         
2098                 status = 1;
2099         }
2100         
2101         return status;
2102 }
2103
2104
2105 int Shear(TransInfo *t, short mval[2]) 
2106 {
2107         TransData *td = t->data;
2108         float vec[3];
2109         float smat[3][3], tmat[3][3], totmat[3][3], persmat[3][3], persinv[3][3];
2110         float value;
2111         int i;
2112         char str[50];
2113
2114         Mat3CpyMat4(persmat, t->viewmat);
2115         Mat3Inv(persinv, persmat);
2116
2117         // Custom data signals shear direction
2118         if (t->customData == 0)
2119                 value = 0.05f * InputHorizontalAbsolute(t, mval);
2120         else
2121                 value = 0.05f * InputVerticalAbsolute(t, mval);
2122
2123         snapGrid(t, &value);
2124
2125         applyNumInput(&t->num, &value);
2126
2127         /* header print for NumInput */
2128         if (hasNumInput(&t->num)) {
2129                 char c[20];
2130
2131                 outputNumInput(&(t->num), c);
2132
2133                 sprintf(str, "Shear: %s %s", c, t->proptext);
2134         }
2135         else {
2136                 /* default header print */
2137                 sprintf(str, "Shear: %.3f %s", value, t->proptext);
2138         }
2139         
2140         Mat3One(smat);
2141         
2142         // Custom data signals shear direction
2143         if (t->customData == 0)
2144                 smat[1][0] = value;
2145         else
2146                 smat[0][1] = value;
2147         
2148         Mat3MulMat3(tmat, smat, persmat);
2149         Mat3MulMat3(totmat, persinv, tmat);
2150         
2151         for(i = 0 ; i < t->total; i++, td++) {
2152                 if (td->flag & TD_NOACTION)
2153                         break;
2154
2155                 if (td->flag & TD_SKIP)
2156                         continue;
2157
2158                 if (G.obedit) {
2159                         float mat3[3][3];
2160                         Mat3MulMat3(mat3, totmat, td->mtx);
2161                         Mat3MulMat3(tmat, td->smtx, mat3);
2162                 }
2163                 else {
2164                         Mat3CpyMat3(tmat, totmat);
2165                 }
2166                 VecSubf(vec, td->center, t->center);
2167
2168                 Mat3MulVecfl(tmat, vec);
2169
2170                 VecAddf(vec, vec, t->center);
2171                 VecSubf(vec, vec, td->center);
2172
2173                 VecMulf(vec, td->factor);
2174
2175                 VecAddf(td->loc, td->iloc, vec);
2176         }
2177
2178         recalcData(t);
2179
2180         headerprint(str);
2181
2182         viewRedrawForce(t);
2183
2184         helpline (t, t->center);
2185
2186         return 1;
2187 }
2188
2189 /* ************************** RESIZE *************************** */
2190
2191 void initResize(TransInfo *t) 
2192 {
2193         t->mode = TFM_RESIZE;
2194         t->transform = Resize;
2195         
2196         t->flag |= T_NULL_ONE;
2197         t->num.flag |= NUM_NULL_ONE;
2198         t->num.flag |= NUM_AFFECT_ALL;
2199         if (!G.obedit) {
2200                 t->flag |= T_NO_ZERO;
2201                 t->num.flag |= NUM_NO_ZERO;
2202         }
2203         
2204         t->idx_max = 2;
2205         t->num.idx_max = 2;
2206         t->snap[0] = 0.0f;
2207         t->snap[1] = 0.1f;
2208         t->snap[2] = t->snap[1] * 0.1f;
2209
2210         t->fac = (float)sqrt(
2211                 (
2212                         ((float)(t->center2d[1] - t->imval[1]))*((float)(t->center2d[1] - t->imval[1]))
2213                 +
2214                         ((float)(t->center2d[0] - t->imval[0]))*((float)(t->center2d[0] - t->imval[0]))
2215                 ) );
2216
2217         if(t->fac==0.0f) t->fac= 1.0f;  // prevent Inf
2218 }
2219
2220 static void headerResize(TransInfo *t, float vec[3], char *str) {
2221         char tvec[60];
2222         if (hasNumInput(&t->num)) {
2223                 outputNumInput(&(t->num), tvec);
2224         }
2225         else {
2226                 sprintf(&tvec[0], "%.4f", vec[0]);
2227                 sprintf(&tvec[20], "%.4f", vec[1]);
2228                 sprintf(&tvec[40], "%.4f", vec[2]);
2229         }
2230
2231         if (t->con.mode & CON_APPLY) {
2232                 switch(t->num.idx_max) {
2233                 case 0:
2234                         sprintf(str, "Scale: %s%s %s", &tvec[0], t->con.text, t->proptext);
2235                         break;
2236                 case 1:
2237                         sprintf(str, "Scale: %s : %s%s %s", &tvec[0], &tvec[20], t->con.text, t->proptext);
2238                         break;
2239                 case 2:
2240                         sprintf(str, "Scale: %s : %s : %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext);
2241                 }
2242         }
2243         else {
2244                 if (t->flag & T_2D_EDIT)
2245                         sprintf(str, "Scale X: %s   Y: %s%s %s", &tvec[0], &tvec[20], t->con.text, t->proptext);
2246                 else
2247                         sprintf(str, "Scale X: %s   Y: %s  Z: %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext);
2248         }
2249 }
2250
2251 #define SIGN(a)         (a<-FLT_EPSILON?1:a>FLT_EPSILON?2:3)
2252 #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)
2253
2254 /* smat is reference matrix, only scaled */
2255 static void TransMat3ToSize( float mat[][3], float smat[][3], float *size)
2256 {
2257         float vec[3];
2258         
2259         VecCopyf(vec, mat[0]);
2260         size[0]= Normalize(vec);
2261         VecCopyf(vec, mat[1]);
2262         size[1]= Normalize(vec);
2263         VecCopyf(vec, mat[2]);
2264         size[2]= Normalize(vec);
2265         
2266         /* first tried with dotproduct... but the sign flip is crucial */
2267         if( VECSIGNFLIP(mat[0], smat[0]) ) size[0]= -size[0]; 
2268         if( VECSIGNFLIP(mat[1], smat[1]) ) size[1]= -size[1]; 
2269         if( VECSIGNFLIP(mat[2], smat[2]) ) size[2]= -size[2]; 
2270 }
2271
2272
2273 static void ElementResize(TransInfo *t, TransData *td, float mat[3][3]) {
2274         float tmat[3][3], smat[3][3], center[3];
2275         float vec[3];
2276
2277         if (t->flag & T_EDIT) {
2278                 Mat3MulMat3(smat, mat, td->mtx);
2279                 Mat3MulMat3(tmat, td->smtx, smat);
2280         }
2281         else {
2282                 Mat3CpyMat3(tmat, mat);
2283         }
2284
2285         if (t->con.applySize) {
2286                 t->con.applySize(t, td, tmat);
2287         }
2288
2289         /* local constraint shouldn't alter center */
2290         if (t->around == V3D_LOCAL) {
2291                 if (t->flag & T_OBJECT) {
2292                         VECCOPY(center, td->center);
2293                 }
2294                 else if (t->flag & T_EDIT) {
2295                         
2296                         if(G.vd->around==V3D_LOCAL && (G.scene->selectmode & SCE_SELECT_FACE)) {
2297                                 VECCOPY(center, td->center);
2298                         }
2299                         else {
2300                                 VECCOPY(center, t->center);
2301                         }
2302                 }
2303                 else {
2304                         VECCOPY(center, t->center);
2305                 }
2306         }
2307         else {
2308                 VECCOPY(center, t->center);
2309         }
2310
2311         if (td->ext) {
2312                 float fsize[3];
2313                 
2314                 if (t->flag & (T_OBJECT|T_TEXTURE|T_POSE)) {
2315                         float obsizemat[3][3];
2316                         // Reorient the size mat to fit the oriented object.
2317                         Mat3MulMat3(obsizemat, tmat, td->axismtx);
2318                         //printmatrix3("obsizemat", obsizemat);
2319                         TransMat3ToSize(obsizemat, td->axismtx, fsize);
2320                         //printvecf("fsize", fsize);
2321                 }
2322                 else {
2323                         Mat3ToSize(tmat, fsize);
2324                 }
2325                 
2326                 protectedSizeBits(td->protectflag, fsize);
2327                 
2328                 if ((t->flag & T_V3D_ALIGN)==0) {       // align mode doesn't resize objects itself
2329                         /* handle ipokeys? */
2330                         if(td->tdi) {
2331                                 TransDataIpokey *tdi= td->tdi;
2332                                 /* calculate delta size (equal for size and dsize) */
2333                                 
2334                                 vec[0]= (tdi->oldsize[0])*(fsize[0] -1.0f) * td->factor;
2335                                 vec[1]= (tdi->oldsize[1])*(fsize[1] -1.0f) * td->factor;
2336                                 vec[2]= (tdi->oldsize[2])*(fsize[2] -1.0f) * td->factor;
2337                                 
2338                                 add_tdi_poin(tdi->sizex, tdi->oldsize,   vec[0]);
2339                                 add_tdi_poin(tdi->sizey, tdi->oldsize+1, vec[1]);
2340                                 add_tdi_poin(tdi->sizez, tdi->oldsize+2, vec[2]);
2341                                 
2342                         } 
2343                         else if((td->flag & TD_SINGLESIZE) && !(t->con.mode & CON_APPLY)){
2344                                 /* scale val and reset size */
2345                                 *td->val = td->ival * fsize[0] * td->factor;
2346                                 
2347                                 td->ext->size[0] = td->ext->isize[0];
2348                                 td->ext->size[1] = td->ext->isize[1];
2349                                 td->ext->size[2] = td->ext->isize[2];
2350                         }
2351                         else {
2352                                 /* Reset val if SINGLESIZE but using a constraint */
2353                                 if (td->flag & TD_SINGLESIZE)
2354                                         *td->val = td->ival;
2355                                 
2356                                 td->ext->size[0] = td->ext->isize[0] * (fsize[0]) * td->factor;
2357                                 td->ext->size[1] = td->ext->isize[1] * (fsize[1]) * td->factor;
2358                                 td->ext->size[2] = td->ext->isize[2] * (fsize[2]) * td->factor;
2359                         }
2360                 }
2361                 
2362                 constraintSizeLim(t, td);
2363         }
2364         
2365         /* For individual element center, Editmode need to use iloc */
2366         if (t->flag & T_POINTS)
2367                 VecSubf(vec, td->iloc, center);
2368         else
2369                 VecSubf(vec, td->center, center);
2370
2371         Mat3MulVecfl(tmat, vec);
2372
2373         VecAddf(vec, vec, center);
2374         if (t->flag & T_POINTS)
2375                 VecSubf(vec, vec, td->iloc);
2376         else
2377                 VecSubf(vec, vec, td->center);
2378
2379         VecMulf(vec, td->factor);
2380
2381         if (t->flag & T_OBJECT) {
2382                 Mat3MulVecfl(td->smtx, vec);
2383         }
2384
2385         protectedTransBits(td->protectflag, vec);
2386
2387         if(td->tdi) {
2388                 TransDataIpokey *tdi= td->tdi;
2389                 add_tdi_poin(tdi->locx, tdi->oldloc, vec[0]);
2390                 add_tdi_poin(tdi->locy, tdi->oldloc+1, vec[1]);
2391                 add_tdi_poin(tdi->locz, tdi->oldloc+2, vec[2]);
2392         }
2393         else VecAddf(td->loc, td->iloc, vec);
2394         
2395         constraintTransLim(t, td);
2396 }
2397
2398 int Resize(TransInfo *t, short mval[2]) 
2399 {
2400         TransData *td;
2401         float size[3], mat[3][3];
2402         float ratio;
2403         int i;
2404         char str[200];
2405
2406         /* for manipulator, center handle, the scaling can't be done relative to center */
2407         if( (t->flag & T_USES_MANIPULATOR) && t->con.mode==0) {
2408                 ratio = 1.0f - ((t->imval[0] - mval[0]) + (t->imval[1] - mval[1]))/100.0f;
2409         }
2410         else {
2411                 ratio = InputScaleRatio(t, mval);
2412                 
2413                 /* flip scale, but not for manipulator center handle */
2414                 if      ((t->center2d[0] - mval[0]) * (t->center2d[0] - t->imval[0]) + 
2415                          (t->center2d[1] - mval[1]) * (t->center2d[1] - t->imval[1]) < 0)
2416                                 ratio *= -1.0f;
2417         }
2418         
2419         size[0] = size[1] = size[2] = ratio;
2420
2421         snapGrid(t, size);
2422
2423         if (hasNumInput(&t->num)) {
2424                 applyNumInput(&t->num, size);
2425                 constraintNumInput(t, size);
2426         }
2427
2428         SizeToMat3(size, mat);
2429
2430         if (t->con.applySize) {
2431                 t->con.applySize(t, NULL, mat);
2432         }
2433
2434         Mat3CpyMat3(t->mat, mat);       // used in manipulator
2435         
2436         headerResize(t, size, str);
2437
2438         for(i = 0, td=t->data; i < t->total; i++, td++) {
2439                 if (td->flag & TD_NOACTION)
2440                         break;
2441
2442                 if (td->flag & TD_SKIP)
2443                         continue;
2444                 
2445                 ElementResize(t, td, mat);
2446         }
2447
2448         /* evil hack - redo resize if cliping needed */
2449         if (t->flag & T_CLIP_UV && clipUVTransform(t, size, 1)) {
2450                 SizeToMat3(size, mat);
2451
2452                 if (t->con.applySize)
2453                         t->con.applySize(t, NULL, mat);
2454
2455                 for(i = 0, td=t->data; i < t->total; i++, td++)
2456                         ElementResize(t, td, mat);
2457         }
2458
2459         recalcData(t);
2460
2461         headerprint(str);
2462
2463         viewRedrawForce(t);
2464
2465         if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
2466
2467         return 1;
2468 }
2469
2470 /* ************************** TOSPHERE *************************** */
2471
2472 void initToSphere(TransInfo *t) 
2473 {
2474         TransData *td = t->data;
2475         int i;
2476
2477         t->mode = TFM_TOSPHERE;
2478         t->transform = ToSphere;
2479
2480         t->idx_max = 0;
2481         t->num.idx_max = 0;
2482         t->snap[0] = 0.0f;
2483         t->snap[1] = 0.1f;
2484         t->snap[2] = t->snap[1] * 0.1f;
2485         
2486         t->num.flag |= NUM_NULL_ONE | NUM_NO_NEGATIVE;
2487         t->flag |= T_NO_CONSTRAINT;
2488
2489         // Calculate average radius
2490         for(i = 0 ; i < t->total; i++, td++) {
2491                 t->val += VecLenf(t->center, td->iloc);
2492         }
2493
2494         t->val /= (float)t->total;
2495 }
2496
2497 int ToSphere(TransInfo *t, short mval[2]) 
2498 {
2499         float vec[3];
2500         float ratio, radius;
2501         int i;
2502         char str[64];
2503         TransData *td = t->data;
2504
2505         ratio = InputHorizontalRatio(t, mval);
2506
2507         snapGrid(t, &ratio);
2508
2509         applyNumInput(&t->num, &ratio);
2510
2511         if (ratio < 0)
2512                 ratio = 0.0f;
2513         else if (ratio > 1)
2514                 ratio = 1.0f;
2515
2516         /* header print for NumInput */
2517         if (hasNumInput(&t->num)) {
2518                 char c[20];
2519
2520                 outputNumInput(&(t->num), c);
2521
2522                 sprintf(str, "To Sphere: %s %s", c, t->proptext);
2523         }
2524         else {
2525                 /* default header print */
2526                 sprintf(str, "To Sphere: %.4f %s", ratio, t->proptext);
2527         }
2528         
2529         
2530         for(i = 0 ; i < t->total; i++, td++) {
2531                 float tratio;
2532                 if (td->flag & TD_NOACTION)
2533                         break;
2534
2535                 if (td->flag & TD_SKIP)
2536                         continue;
2537
2538                 VecSubf(vec, td->iloc, t->center);
2539
2540                 radius = Normalize(vec);
2541
2542                 tratio = ratio * td->factor;
2543
2544                 VecMulf(vec, radius * (1.0f - tratio) + t->val * tratio);
2545
2546                 VecAddf(td->loc, t->center, vec);
2547         }
2548         
2549
2550         recalcData(t);
2551
2552         headerprint(str);
2553
2554         viewRedrawForce(t);
2555
2556         return 1;
2557 }
2558
2559 /* ************************** ROTATION *************************** */
2560
2561
2562 void initRotation(TransInfo *t) 
2563 {
2564         t->mode = TFM_ROTATION;
2565         t->transform = Rotation;
2566         
2567         t->idx_max = 0;
2568         t->num.idx_max = 0;
2569         t->snap[0] = 0.0f;
2570         t->snap[1] = (float)((5.0/180)*M_PI);
2571         t->snap[2] = t->snap[1] * 0.2f;
2572         t->fac = 0;
2573         
2574         if (t->flag & T_2D_EDIT)
2575                 t->flag |= T_NO_CONSTRAINT;
2576 }
2577
2578 static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3]) {
2579         float vec[3], totmat[3][3], smat[3][3];
2580         float eul[3], fmat[3][3], quat[4];
2581
2582         if (t->flag & T_POINTS) {
2583                 Mat3MulMat3(totmat, mat, td->mtx);
2584                 Mat3MulMat3(smat, td->smtx, totmat);
2585                 
2586                 VecSubf(vec, td->iloc, t->center);
2587                 Mat3MulVecfl(smat, vec);
2588                 
2589                 VecAddf(td->loc, vec, t->center);
2590
2591                 VecSubf(vec,td->loc,td->iloc);
2592                 protectedTransBits(td->protectflag, vec);
2593                 VecAddf(td->loc, td->iloc, vec);
2594
2595                 if(td->flag & TD_USEQUAT) {
2596                         Mat3MulSerie(fmat, td->mtx, mat, td->smtx, 0, 0, 0, 0, 0);
2597                         Mat3ToQuat(fmat, quat); // Actual transform
2598                         
2599                         if(td->ext->quat){
2600                                 QuatMul(td->ext->quat, quat, td->ext->iquat);
2601                                 
2602                                 /* is there a reason not to have this here? -jahka */
2603                                 protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat);
2604                         }
2605                 }
2606         }
2607         /**
2608          * HACK WARNING
2609          * 
2610          * This is some VERY ugly special case to deal with pose mode.
2611          * 
2612          * The problem is that mtx and smtx include each bone orientation.
2613          * 
2614          * That is needed to rotate each bone properly, HOWEVER, to calculate
2615          * the translation component, we only need the actual armature object's
2616          * matrix (and inverse). That is not all though. Once the proper translation
2617          * has been computed, it has to be converted back into the bone's space.
2618          */
2619         else if (t->flag & T_POSE) {
2620                 float pmtx[3][3], imtx[3][3];
2621
2622                 // Extract and invert armature object matrix            
2623                 Mat3CpyMat4(pmtx, t->poseobj->obmat);
2624                 Mat3Inv(imtx, pmtx);
2625                 
2626                 VecSubf(vec, td->center, t->center);
2627                 
2628                 Mat3MulVecfl(pmtx, vec);        // To Global space
2629                 Mat3MulVecfl(mat, vec);         // Applying rotation
2630                 Mat3MulVecfl(imtx, vec);        // To Local space
2631
2632                 VecAddf(vec, vec, t->center);
2633                 /* vec now is the location where the object has to be */
2634                 
2635                 VecSubf(vec, vec, td->center); // Translation needed from the initial location
2636                 
2637                 Mat3MulVecfl(pmtx, vec);        // To Global space
2638                 Mat3MulVecfl(td->smtx, vec);// To Pose space
2639
2640                 protectedTransBits(td->protectflag, vec);
2641
2642                 VecAddf(td->loc, td->iloc, vec);
2643                 
2644                 constraintTransLim(t, td);
2645                 
2646                 /* rotation */
2647                 if ((t->flag & T_V3D_ALIGN)==0) { // align mode doesn't rotate objects itself
2648                         Mat3MulSerie(fmat, td->mtx, mat, td->smtx, 0, 0, 0, 0, 0);
2649                         
2650                         Mat3ToQuat(fmat, quat); // Actual transform
2651                         
2652                         QuatMul(td->ext->quat, quat, td->ext->iquat);
2653                         /* this function works on end result */
2654                         protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat);
2655                         
2656                         constraintRotLim(t, td);
2657                 }
2658         }
2659         else {
2660                 /* translation */
2661                 VecSubf(vec, td->center, t->center);
2662                 Mat3MulVecfl(mat, vec);
2663                 VecAddf(vec, vec, t->center);
2664                 /* vec now is the location where the object has to be */
2665                 VecSubf(vec, vec, td->center);
2666                 Mat3MulVecfl(td->smtx, vec);
2667                 
2668                 protectedTransBits(td->protectflag, vec);
2669                 
2670                 if(td->tdi) {
2671                         TransDataIpokey *tdi= td->tdi;
2672                         add_tdi_poin(tdi->locx, tdi->oldloc, vec[0]);
2673                         add_tdi_poin(tdi->locy, tdi->oldloc+1, vec[1]);
2674                         add_tdi_poin(tdi->locz, tdi->oldloc+2, vec[2]);
2675                 }
2676                 else VecAddf(td->loc, td->iloc, vec);
2677                 
2678                 constraintTransLim(t, td);
2679
2680                 /* rotation */
2681                 if ((t->flag & T_V3D_ALIGN)==0) { // align mode doesn't rotate objects itself
2682                         if(td->flag & TD_USEQUAT) {
2683                                 Mat3MulSerie(fmat, td->mtx, mat, td->smtx, 0, 0, 0, 0, 0);
2684                                 Mat3ToQuat(fmat, quat); // Actual transform
2685                                 
2686                                 QuatMul(td->ext->quat, quat, td->ext->iquat);
2687                                 /* this function works on end result */
2688                                 protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat);
2689                         }
2690                         else {
2691                                 float obmat[3][3];
2692                                 
2693                                 /* are there ipo keys? */
2694                                 if(td->tdi) {
2695                                         TransDataIpokey *tdi= td->tdi;
2696                                         float rot[3];
2697                                         
2698                                         /* calculate the total rotatation in eulers */
2699                                         VecAddf(eul, td->ext->irot, td->ext->drot);
2700                                         EulToMat3(eul, obmat);
2701                                         /* mat = transform, obmat = object rotation */
2702                                         Mat3MulMat3(fmat, mat, obmat);
2703                                         
2704                                         Mat3ToCompatibleEul(fmat, eul, td->ext->irot);
2705                                         
2706                                         /* correct back for delta rot */
2707                                         if(tdi->flag & TOB_IPODROT) {
2708                                                 VecSubf(rot, eul, td->ext->irot);
2709                                         }
2710                                         else {
2711                                                 VecSubf(rot, eul, td->ext->drot);
2712                                         }
2713                                         
2714                                         VecMulf(rot, (float)(9.0/M_PI_2));
2715                                         VecSubf(rot, rot, tdi->oldrot);
2716                                         
2717                                         protectedRotateBits(td->protectflag, rot, tdi->oldrot);
2718                                         
2719                                         add_tdi_poin(tdi->rotx, tdi->oldrot, rot[0]);
2720                                         add_tdi_poin(tdi->roty, tdi->oldrot+1, rot[1]);
2721                                         add_tdi_poin(tdi->rotz, tdi->oldrot+2, rot[2]);
2722                                 }
2723                                 else {
2724                                         Mat3MulMat3(totmat, mat, td->mtx);
2725                                         Mat3MulMat3(smat, td->smtx, totmat);
2726                                         
2727                                         /* calculate the total rotatation in eulers */
2728                                         VecAddf(eul, td->ext->irot, td->ext->drot); /* we have to correct for delta rot */
2729                                         EulToMat3(eul, obmat);
2730                                         /* mat = transform, obmat = object rotation */
2731                                         Mat3MulMat3(fmat, smat, obmat);
2732                                         
2733                                         Mat3ToCompatibleEul(fmat, eul, td->ext->irot);
2734                                         
2735                                         /* correct back for delta rot */
2736                                         VecSubf(eul, eul, td->ext->drot);
2737                                         
2738                                         /* and apply */
2739                                         protectedRotateBits(td->protectflag, eul, td->ext->irot);
2740                                         VECCOPY(td->ext->rot, eul);
2741                                 }
2742                         }
2743                         
2744                         constraintRotLim(t, td);
2745                 }
2746         }
2747 }
2748
2749 static void applyRotation(TransInfo *t, float angle, float axis[3]) 
2750 {
2751         TransData *td = t->data;
2752         float mat[3][3], center[3];
2753         int i;
2754
2755         /* saving original center */
2756         if (t->around == V3D_LOCAL) {
2757                 VECCOPY(center, t->center);
2758         }
2759         else {
2760                 center[0] = center[1] = center[2] = 0.0f;
2761         }
2762
2763         VecRotToMat3(axis, angle, mat);
2764         
2765         for(i = 0 ; i < t->total; i++, td++) {
2766
2767                 if (td->flag & TD_NOACTION)
2768                         break;
2769
2770                 if (td->flag & TD_SKIP)
2771                         continue;
2772                 
2773                 /* local constraint shouldn't alter center */
2774                 if (t->around == V3D_LOCAL) {
2775                         if (t->flag & (T_OBJECT|T_POSE)) {
2776                                 VECCOPY(t->center, td->center);
2777                         }
2778                         else {
2779                                 if(G.vd->around==V3D_LOCAL && (G.scene->selectmode & SCE_SELECT_FACE)) {
2780                                         VECCOPY(t->center, td->center);
2781                                 }
2782                         }
2783                 }
2784                 
2785                 if (t->con.applyRot) {
2786                         t->con.applyRot(t, td, axis);
2787                         VecRotToMat3(axis, angle * td->factor, mat);
2788                 }
2789                 else if (t->flag & T_PROP_EDIT) {
2790                         VecRotToMat3(axis, angle * td->factor, mat);
2791                 }
2792
2793                 ElementRotation(t, td, mat);
2794         }
2795
2796         /* restoring original center */
2797         if (t->around == V3D_LOCAL) {
2798                 VECCOPY(t->center, center);
2799         }
2800 }
2801
2802 int Rotation(TransInfo *t, short mval[2]) 
2803 {
2804         char str[64];
2805
2806         float final;
2807
2808         int dx2 = t->center2d[0] - mval[0];
2809         int dy2 = t->center2d[1] - mval[1];
2810         double B = sqrt(dx2*dx2+dy2*dy2);
2811
2812         int dx1 = t->center2d[0] - t->imval[0];
2813         int dy1 = t->center2d[1] - t->imval[1];
2814         double A = sqrt(dx1*dx1+dy1*dy1);
2815
2816         int dx3 = mval[0] - t->imval[0];
2817         int dy3 = mval[1] - t->imval[1];
2818                 /* use doubles here, to make sure a "1.0" (no rotation) doesnt become 9.999999e-01, which gives 0.02 for acos */
2819         double deler= ((double)((dx1*dx1+dy1*dy1)+(dx2*dx2+dy2*dy2)-(dx3*dx3+dy3*dy3) ))
2820                 / (2.0 * (A*B?A*B:1.0));
2821         /* (A*B?A*B:1.0f) this takes care of potential divide by zero errors */
2822
2823         float dphi;
2824
2825         float axis[3];
2826         float mat[3][3];
2827
2828         VECCOPY(axis, t->viewinv[2]);
2829         VecMulf(axis, -1.0f);
2830         Normalize(axis);
2831
2832         dphi = saacos((float)deler);
2833         if( (dx1*dy2-dx2*dy1)>0.0 ) dphi= -dphi;
2834
2835         if(t->flag & T_SHIFT_MOD) t->fac += dphi/30.0f;
2836         else t->fac += dphi;
2837
2838         /*
2839         clamping angle between -2 PI and 2 PI (not sure if useful so commented out - theeth)
2840         if (t->fac >= 2 * M_PI)
2841                 t->fac -= 2 * M_PI;
2842         else if (t->fac <= -2 * M_PI)
2843                 t->fac -= -2 * M_PI;
2844         */
2845
2846         final = t->fac;
2847
2848         snapGrid(t, &final);
2849
2850         t->imval[0] = mval[0];
2851         t->imval[1] = mval[1];
2852
2853         if (t->con.applyRot) {
2854                 t->con.applyRot(t, NULL, axis);
2855         }
2856         
2857         applySnapping(t, &final);
2858
2859         if (hasNumInput(&t->num)) {
2860                 char c[20];
2861
2862                 applyNumInput(&t->num, &final);
2863
2864                 outputNumInput(&(t->num), c);
2865
2866                 sprintf(str, "Rot: %s %s %s", &c[0], t->con.text, t->proptext);
2867
2868                 /* Clamp between -180 and 180 */
2869                 while (final >= 180.0)
2870                         final -= 360.0;
2871                 
2872                 while (final <= -180.0)
2873                         final += 360.0;
2874
2875                 final *= (float)(M_PI / 180.0);
2876         }
2877         else {
2878                 sprintf(str, "Rot: %.2f%s %s", 180.0*final/M_PI, t->con.text, t->proptext);
2879         }
2880
2881         VecRotToMat3(axis, final, mat);
2882
2883         t->val = final;                         // used in manipulator
2884         Mat3CpyMat3(t->mat, mat);       // used in manipulator
2885         
2886         applyRotation(t, final, axis);
2887         
2888         recalcData(t);
2889
2890         headerprint(str);
2891
2892         viewRedrawForce(t);
2893
2894         if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
2895
2896         return 1;
2897 }
2898
2899
2900 /* ************************** TRACKBALL *************************** */
2901
2902 void initTrackball(TransInfo *t) 
2903 {
2904         t->mode = TFM_TRACKBALL;
2905         t->transform = Trackball;
2906
2907         t->idx_max = 1;
2908         t->num.idx_max = 1;
2909         t->snap[0] = 0.0f;
2910         t->snap[1] = (float)((5.0/180)*M_PI);
2911         t->snap[2] = t->snap[1] * 0.2f;
2912         t->fac = 0;
2913         
2914         t->flag |= T_NO_CONSTRAINT;
2915 }
2916
2917 static void applyTrackball(TransInfo *t, float axis1[3], float axis2[3], float angles[2])
2918 {
2919         TransData *td = t->data;
2920         float mat[3][3], smat[3][3], totmat[3][3];
2921         float center[3];
2922         int i;
2923
2924         VecRotToMat3(axis1, angles[0], smat);
2925         VecRotToMat3(axis2, angles[1], totmat);
2926         
2927         Mat3MulMat3(mat, smat, totmat);
2928
2929         for(i = 0 ; i < t->total; i++, td++) {
2930                 if (td->flag & TD_NOACTION)
2931                         break;
2932
2933                 if (td->flag & TD_SKIP)
2934                         continue;
2935                 
2936                 VECCOPY(center, t->center);
2937                 
2938                 if (t->around == V3D_LOCAL) {
2939                         /* local-mode shouldn't change center */
2940                         if (t->flag & (T_OBJECT|T_POSE)) {
2941                                 VECCOPY(t->center, td->center);
2942                         }
2943                         else {
2944                                 if(G.vd->around==V3D_LOCAL && (G.scene->selectmode & SCE_SELECT_FACE)) {
2945                                         VECCOPY(t->center, td->center);
2946                                 }
2947                         }
2948                 }
2949                 
2950                 if (t->flag & T_PROP_EDIT) {
2951                         VecRotToMat3(axis1, td->factor * angles[0], smat);
2952                         VecRotToMat3(axis2, td->factor * angles[1], totmat);
2953                         
2954                         Mat3MulMat3(mat, smat, totmat);
2955                 }
2956                 
2957                 ElementRotation(t, td, mat);
2958                 
2959                 VECCOPY(t->center, center);
2960         }
2961 }
2962
2963 int Trackball(TransInfo *t, short mval[2]) 
2964 {
2965         char str[128];
2966         float axis1[3], axis2[3];
2967         float mat[3][3], totmat[3][3], smat[3][3];
2968         float phi[2];
2969         
2970         VECCOPY(axis1, t->persinv[0]);
2971         VECCOPY(axis2, t->persinv[1]);
2972         Normalize(axis1);
2973         Normalize(axis2);
2974         
2975         /* factore has to become setting or so */
2976         phi[0]= 0.01f*(float)( t->imval[1] - mval[1] );
2977         phi[1]= 0.01f*(float)( mval[0] - t->imval[0] );
2978                 
2979         snapGrid(t, phi);
2980         
2981         if (hasNumInput(&t->num)) {
2982                 char c[40];
2983                 
2984                 applyNumInput(&t->num, phi);
2985                 
2986                 outputNumInput(&(t->num), c);
2987                 
2988                 sprintf(str, "Trackball: %s %s %s", &c[0], &c[20], t->proptext);
2989                 
2990                 phi[0] *= (float)(M_PI / 180.0);
2991                 phi[1] *= (float)(M_PI / 180.0);
2992         }
2993         else {
2994                 sprintf(str, "Trackball: %.2f %.2f %s", 180.0*phi[0]/M_PI, 180.0*phi[1]/M_PI, t->proptext);
2995         
2996                 if(t->flag & T_SHIFT_MOD) {
2997                         if(phi[0] != 0.0) phi[0]/= 5.0f;
2998                         if(phi[1] != 0.0) phi[1]/= 5.0f;
2999                 }
3000         }
3001
3002         VecRotToMat3(axis1, phi[0], smat);
3003         VecRotToMat3(axis2, phi[1], totmat);
3004         
3005         Mat3MulMat3(mat, smat, totmat);
3006         
3007         Mat3CpyMat3(t->mat, mat);       // used in manipulator
3008         
3009         applyTrackball(t, axis1, axis2, phi);
3010         
3011         recalcData(t);
3012         
3013         headerprint(str);
3014         
3015         viewRedrawForce(t);
3016         
3017         if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
3018         
3019         return 1;
3020 }
3021
3022 /* ************************** TRANSLATION *************************** */
3023         
3024 void initTranslation(TransInfo *t) 
3025 {
3026         t->mode = TFM_TRANSLATION;
3027         t->transform = Translation;
3028
3029         t->idx_max = (t->flag & T_2D_EDIT)? 1: 2;
3030         t->num.flag = 0;
3031         t->num.idx_max = t->idx_max;
3032         
3033
3034         if(t->spacetype == SPACE_VIEW3D) {
3035                 /* initgrabz() defines a factor for perspective depth correction, used in window_to_3d() */
3036                 if(t->flag & (T_EDIT|T_POSE)) {
3037                         Object *ob= G.obedit?G.obedit:t->poseobj;
3038                         float vec[3];
3039                         
3040                         VECCOPY(vec, t->center);
3041                         Mat4MulVecfl(ob->obmat, vec);
3042                         initgrabz(vec[0], vec[1], vec[2]);
3043                 }
3044                 else {
3045                         initgrabz(t->center[0], t->center[1], t->center[2]);
3046                 } 
3047
3048                 t->snap[0] = 0.0f;
3049                 t->snap[1] = G.vd->gridview * 1.0f;
3050                 t->snap[2] = t->snap[1] * 0.1f;
3051         }
3052         else if(t->spacetype == SPACE_IMAGE) {
3053                 t->snap[0] = 0.0f;
3054                 t->snap[1] = 0.125f;
3055                 t->snap[2] = 0.0625f;
3056         }
3057         else {
3058                 t->snap[0] = 0.0f;
3059                 t->snap[1] = t->snap[2] = 1.0f;
3060         }
3061 }
3062
3063 static void headerTranslation(TransInfo *t, float vec[3], char *str) {
3064         char tvec[60];
3065         char distvec[20];
3066         char autoik[20];
3067         float dvec[3];
3068         float dist;
3069         
3070         convertVecToDisplayNum(vec, dvec);
3071
3072         if (hasNumInput(&t->num)) {
3073                 outputNumInput(&(t->num), tvec);
3074                 dist = VecLength(t->num.val);
3075         }
3076         else {
3077                 dist = VecLength(vec);
3078                 sprintf(&tvec[0], "%.4f", dvec[0]);
3079                 sprintf(&tvec[20], "%.4f", dvec[1]);
3080                 sprintf(&tvec[40], "%.4f", dvec[2]);
3081         }
3082
3083         if( dist > 1e10 || dist < -1e10 )       /* prevent string buffer overflow */
3084                 sprintf(distvec, "%.4e", dist);
3085         else
3086                 sprintf(distvec, "%.4f", dist);
3087                 
3088         if(t->flag & T_AUTOIK) {
3089                 short chainlen= G.scene->toolsettings->autoik_chainlen;
3090                 
3091                 if(chainlen)
3092                         sprintf(autoik, "AutoIK-Len: %d", chainlen);
3093                 else
3094                         strcpy(autoik, "");
3095         }
3096         else
3097                 strcpy(autoik, "");
3098
3099         if (t->con.mode & CON_APPLY) {
3100                 switch(t->num.idx_max) {
3101                 case 0:
3102                         sprintf(str, "D: %s (%s)%s %s  %s", &tvec[0], distvec, t->con.text, t->proptext, &autoik[0]);
3103                         break;
3104                 case 1:
3105                         sprintf(str, "D: %s   D: %s (%s)%s %s  %s", &tvec[0], &tvec[20], distvec, t->con.text, t->proptext, &autoik[0]);
3106                         break;
3107                 case 2:
3108                         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]);
3109                 }
3110         }
3111         else {
3112                 if(t->flag & T_2D_EDIT)
3113                         sprintf(str, "Dx: %s   Dy: %s (%s)%s %s", &tvec[0], &tvec[20], distvec, t->con.text, t->proptext);
3114                 else
3115                         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]);
3116         }
3117 }
3118
3119 static void applyTranslation(TransInfo *t, float vec[3]) {
3120         TransData *td = t->data;
3121         float tvec[3];
3122         int i;
3123
3124         for(i = 0 ; i < t->total; i++, td++) {
3125                 if (td->flag & TD_NOACTION)
3126                         break;
3127                 
3128                 if (td->flag & TD_SKIP)
3129                         continue;
3130                 
3131                 if (t->con.applyVec) {
3132                         float pvec[3];
3133                         t->con.applyVec(t, td, vec, tvec, pvec);
3134                 }
3135                 else {
3136                         VECCOPY(tvec, vec);
3137                 }
3138                 
3139                 Mat3MulVecfl(td->smtx, tvec);
3140                 VecMulf(tvec, td->factor);
3141                 
3142                 protectedTransBits(td->protectflag, tvec);
3143                 
3144                 /* transdata ipokey */
3145                 if(td->tdi) {
3146                         TransDataIpokey *tdi= td->tdi;
3147                         add_tdi_poin(tdi->locx, tdi->oldloc, tvec[0]);
3148                         add_tdi_poin(tdi->locy, tdi->oldloc+1, tvec[1]);
3149                         add_tdi_poin(tdi->locz, tdi->oldloc+2, tvec[2]);
3150                 }
3151                 else VecAddf(td->loc, td->iloc, tvec);
3152                 
3153                 constraintTransLim(t, td);
3154         }
3155 }
3156
3157 /* uses t->vec to store actual translation in */
3158 int Translation(TransInfo *t, short mval[2]) 
3159 {
3160         float tvec[3];
3161         char str[250];
3162         
3163         if(t->flag & T_SHIFT_MOD) {
3164                 float dvec[3];
3165                 /* calculate the main translation and the precise one separate */
3166                 convertViewVec(t, dvec, (short)(mval[0] - t->shiftmval[0]), (short)(mval[1] - t->shiftmval[1]));
3167                 VecMulf(dvec, 0.1f);
3168                 convertViewVec(t, t->vec, (short)(t->shiftmval[0] - t->imval[0]), (short)(t->shiftmval[1] - t->imval[1]));
3169                 VecAddf(t->vec, t->vec, dvec);
3170         }
3171         else convertViewVec(t, t->vec, (short)(mval[0] - t->imval[0]), (short)(mval[1] - t->imval[1]));
3172
3173         if (t->con.mode & CON_APPLY) {
3174                 float pvec[3] = {0.0f, 0.0f, 0.0f};
3175                 applySnapping(t, t->vec);
3176                 t->con.applyVec(t, NULL, t->vec, tvec, pvec);
3177                 VECCOPY(t->vec, tvec);
3178                 headerTranslation(t, pvec, str);
3179         }
3180         else {
3181                 snapGrid(t, t->vec);
3182                 applyNumInput(&t->num, t->vec);
3183                 applySnapping(t, t->vec);
3184                 headerTranslation(t, t->vec, str);
3185         }