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