Removed casting warnings from transform_manipulator.
[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 <string.h>
35 #include <math.h>
36
37 #ifdef HAVE_CONFIG_H
38 #include <config.h>
39 #endif
40
41 #ifndef WIN32
42 #include <unistd.h>
43 #else
44 #include <io.h>
45 #endif
46
47 #include "MEM_guardedalloc.h"
48
49 #include "DNA_action_types.h"
50 #include "DNA_armature_types.h"
51 #include "DNA_camera_types.h"
52 #include "DNA_curve_types.h"
53 #include "DNA_effect_types.h"
54 #include "DNA_ika_types.h"
55 #include "DNA_image_types.h"
56 #include "DNA_ipo_types.h"
57 #include "DNA_key_types.h"
58 #include "DNA_lamp_types.h"
59 #include "DNA_lattice_types.h"
60 #include "DNA_mesh_types.h"
61 #include "DNA_meshdata_types.h"
62 #include "DNA_meta_types.h"
63 #include "DNA_object_types.h"
64 #include "DNA_scene_types.h"
65 #include "DNA_screen_types.h"
66 #include "DNA_texture_types.h"
67 #include "DNA_view3d_types.h"
68 #include "DNA_world_types.h"
69 #include "DNA_userdef_types.h"
70 #include "DNA_property_types.h"
71 #include "DNA_vfont_types.h"
72 #include "DNA_constraint_types.h"
73
74 #include "BIF_editview.h"
75 #include "BIF_resources.h"
76 #include "BIF_mywindow.h"
77 #include "BIF_gl.h"
78 #include "BIF_editlattice.h"
79 #include "BIF_editarmature.h"
80 #include "BIF_editmesh.h"
81 #include "BIF_screen.h"
82 #include "BIF_space.h"
83 #include "BIF_toolbox.h"
84
85 #include "BKE_action.h"
86 #include "BKE_armature.h"
87 #include "BKE_blender.h"
88 #include "BKE_curve.h"
89 #include "BKE_displist.h"
90 #include "BKE_effect.h"
91 #include "BKE_global.h"
92 #include "BKE_ipo.h"
93 #include "BKE_lattice.h"
94 #include "BKE_mball.h"
95 #include "BKE_object.h"
96 #include "BKE_utildefines.h"
97
98 #include "BSE_view.h"
99 #include "BSE_edit.h"
100 #include "BSE_editipo.h"
101 #include "BSE_editipo_types.h"
102 #include "BDR_editobject.h"             // reset_slowparents()
103
104 #include "BLI_arithb.h"
105 #include "BLI_editVert.h"
106 #include "BLI_ghash.h"
107
108 #include "PIL_time.h"
109
110 #include "blendef.h"
111
112 #include "mydevice.h"
113
114 extern ListBase editNurb;
115 extern ListBase editelems;
116
117 extern void helpline(float *vec);
118
119
120 #include "transform.h"
121 #include "transform_generics.h"
122 #include "transform_constraints.h"
123 #include "transform_numinput.h"
124
125 /* GLOBAL VARIABLE THAT SHOULD MOVED TO SCREEN MEMBER OR SOMETHING  */
126 TransInfo Trans;
127 int     LastMode = TFM_TRANSLATION;
128
129 /* ************************** Functions *************************** */
130
131 static void qsort_trans_data(TransData *head, TransData *tail) {
132         TransData pivot = *head;
133         TransData *ihead = head;
134         TransData *itail = tail;
135
136         while (head < tail)
137         {
138                 while ((tail->dist >= pivot.dist) && (head < tail))
139                         tail--;
140
141                 if (head != tail)
142                 {
143                         *head = *tail;
144                         head++;
145                 }
146
147                 while ((head->dist <= pivot.dist) && (head < tail))
148                         head++;
149
150                 if (head != tail)
151                 {
152                         *tail = *head;
153                         tail--;
154                 }
155         }
156
157         *head = pivot;
158         if (ihead < head) {
159                 qsort_trans_data(ihead, head-1);
160         }
161         if (itail > head) {
162                 qsort_trans_data(head+1, itail);
163         }
164 }
165
166 static void sort_trans_data_dist(TransInfo *t) {
167         TransData *start = t->data;
168         int i = 1;
169
170         while(i < t->total && start->flag & TD_SELECTED) {
171                 start++;
172                 i++;
173         }
174         qsort_trans_data(start, t->data + t->total - 1);
175 }
176
177 static void sort_trans_data(TransInfo *t) 
178 {
179         TransData *sel, *unsel;
180         TransData temp;
181         unsel = t->data;
182         sel = t->data;
183         sel += t->total - 1;
184         while (sel > unsel) {
185                 while (unsel->flag & TD_SELECTED) {
186                         unsel++;
187                         if (unsel == sel) {
188                                 return;
189                         }
190                 }
191                 while (!(sel->flag & TD_SELECTED)) {
192                         sel--;
193                         if (unsel == sel) {
194                                 return;
195                         }
196                 }
197                 temp = *unsel;
198                 *unsel = *sel;
199                 *sel = temp;
200                 sel--;
201                 unsel++;
202         }
203 }
204
205
206 /* distance calculated from not-selected vertex to nearest selected vertex
207    warning; this is loops inside loop, has minor N^2 issues, but by sorting list it is OK */
208 static void set_prop_dist(TransInfo *t, short with_dist)
209 {
210         TransData *tob;
211         int a;
212         
213         for(a=0, tob= t->data; a<t->total; a++, tob++) {
214                 
215                 tob->rdist= 0.0f; // init, it was mallocced
216                 
217                 if((tob->flag & TD_SELECTED)==0) {
218                         TransData *td;
219                         int i;
220                         float dist, vec[3];
221
222                         tob->rdist = -1.0f; // signal for next loop
223                                 
224                         for (i = 0, td= t->data; i < t->total; i++, td++) {
225                                 if(td->flag & TD_SELECTED) {
226                                         VecSubf(vec, tob->center, td->center);
227                                         Mat3MulVecfl(tob->mtx, vec);
228                                         dist = Normalise(vec);
229                                         if (tob->rdist == -1.0f) {
230                                                 tob->rdist = dist;
231                                         }
232                                         else if (dist < tob->rdist) {
233                                                 tob->rdist = dist;
234                                         }
235                                 }
236                                 else break;     // by definition transdata has selected items in beginning
237                         }
238                         if (with_dist) {
239                                 tob->dist = tob->rdist;
240                         }
241                 }       
242         }
243 }
244
245 /* ************************** CONVERSIONS ************************* */
246
247 static void createTransTexspace(void)
248 {
249         TransData *td;
250         Object *ob;
251         ID *id;
252         
253         ob= OBACT;
254         Trans.total = 1;
255         td= Trans.data= MEM_callocN(sizeof(TransData), "TransTexspace");
256         td->ext= Trans.ext= MEM_callocN(sizeof(TransDataExtension), "TransTexspace");
257         
258         td->flag= TD_SELECTED;
259         VECCOPY(td->center, ob->obmat[3]);
260         td->ob = ob;
261         
262         Mat3CpyMat4(td->mtx, ob->obmat);
263         Mat3Inv(td->smtx, td->mtx);
264         
265         id= ob->data;
266         if(id==0);
267         else if( GS(id->name)==ID_ME) {
268                 Mesh *me= ob->data;
269                 me->texflag &= ~AUTOSPACE;
270                 td->loc= me->loc;
271                 td->ext->rot= me->rot;
272                 td->ext->size= me->size;
273         }
274         else if( GS(id->name)==ID_CU) {
275                 Curve *cu= ob->data;
276                 cu->texflag &= ~CU_AUTOSPACE;
277                 td->loc= cu->loc;
278                 td->ext->rot= cu->rot;
279                 td->ext->size= cu->size;
280         }
281         else if( GS(id->name)==ID_MB) {
282                 MetaBall *mb= ob->data;
283                 mb->texflag &= ~MB_AUTOSPACE;
284                 td->loc= mb->loc;
285                 td->ext->rot= mb->rot;
286                 td->ext->size= mb->size;
287         }
288         
289         VECCOPY(td->iloc, td->loc);
290         VECCOPY(td->ext->irot, td->ext->rot);
291         VECCOPY(td->ext->isize, td->ext->size);
292 }
293
294
295 /* ********************* pose mode ************* */
296
297 /* callback, make sure it's identical structured as next one */
298 /* also used to count for manipulator */
299 void count_bone_select(ListBase *lb, int *counter) 
300 {
301         Bone *bone;
302         int deeper= 1;
303         
304         for(bone= lb->first; bone; bone= bone->next) {
305                 if (bone->flag & BONE_SELECTED) {
306                         /* We don't let IK children get "grabbed" */
307                         /* ALERT! abusive global Trans here */
308                         if ( (Trans.mode!=TFM_TRANSLATION) || (bone->flag & BONE_IK_TOPARENT)==0 ) {
309                                 (*counter)++;
310                                 deeper= 0;      // no transform on children if one parent bone is selected
311                         }
312                         else deeper= 1;
313                 }
314                 if(deeper) count_bone_select( &bone->childbase, counter);
315         }
316 }
317
318 /* recursive */
319 static void add_pose_transdata(ListBase *lb, Object *ob, TransData **tdp)
320 {
321         Bone *bone;
322         TransData *td= *tdp;
323         float   parmat[4][4], tempmat[4][4];
324         float tempobmat[4][4];
325         float vec[3];
326         int deeper= 1;
327         
328         for(bone= lb->first; bone; bone= bone->next) {
329                 if (bone->flag & BONE_SELECTED) {
330                         /* We don't let IK children get "grabbed" */
331                         /* ALERT! abusive global Trans here */
332                         if ( (Trans.mode!=TFM_TRANSLATION) || (bone->flag & BONE_IK_TOPARENT)==0 ) {
333                                 
334                                 get_bone_root_pos (bone, vec, 1);
335                                 
336                                 //VecAddf (centroid, centroid, vec);
337                                 VECCOPY(td->center, vec);
338                                 
339                                 td->ob = ob;
340                                 td->flag= TD_SELECTED|TD_USEQUAT;
341                                 td->loc = bone->loc;
342                                 VECCOPY(td->iloc, bone->loc);
343                                 
344                                 td->ext->rot= NULL;
345                                 td->ext->quat= bone->quat;
346                                 td->ext->size= bone->size;
347                                 td->ext->bone= bone; // FIXME: Dangerous
348
349                                 QUATCOPY(td->ext->iquat, bone->quat);
350                                 VECCOPY(td->ext->isize, bone->size);
351                                 
352                                 /* Get the matrix of this bone minus the usertransform */
353                                 Mat4CpyMat4 (tempobmat, bone->obmat);
354                                 Mat4One (bone->obmat);
355                                 get_objectspace_bone_matrix(bone, tempmat, 1, 1);
356                                 Mat4CpyMat4 (bone->obmat, tempobmat);
357
358                                 Mat4MulMat4 (parmat, tempmat, ob->obmat);       /* Original */
359                                 
360                                 Mat3CpyMat4 (td->mtx, parmat);
361                                 Mat3Inv (td->smtx, td->mtx);
362                                 
363                                 (*tdp)++;
364                                 td= *tdp;
365                                 deeper= 0;
366                         }
367                         else deeper= 1;
368                 }
369                 if(deeper) add_pose_transdata(&bone->childbase, ob, tdp);
370         }
371 }
372
373 static void createTransPose(void)
374 {
375         bArmature *arm;
376         TransData *td;
377         TransDataExtension *tdx;
378         int i;
379         
380         Trans.total= 0; // to be able to return
381         
382         /* check validity of state */
383         arm=get_armature (G.obpose);
384         if (arm==NULL) return;
385         
386         if (arm->flag & ARM_RESTPOS){
387                 notice ("Transformation not possible while Rest Position is enabled");
388                 return;
389         }
390         if (!(G.obpose->lay & G.vd->lay)) return;
391
392         /* copied from old code, no idea. we let linker solve it for now */
393         {
394                 extern void figure_bone_nocalc(Object *ob);
395                 extern void figure_pose_updating(void);
396
397                 /* figure out which bones need calculating */
398                 figure_bone_nocalc(G.obpose);
399                 figure_pose_updating();
400         }
401         
402         /* copied from old code, no idea... (ton) */
403         apply_pose_armature(arm, G.obpose->pose, 0);
404         where_is_armature (G.obpose);
405         
406         /* count total */
407         count_bone_select(&arm->bonebase, &Trans.total);
408         
409         if(Trans.total==0 && Trans.mode==TFM_TRANSLATION) {
410                 Trans.mode= TFM_ROTATION;
411                 count_bone_select(&arm->bonebase, &Trans.total);
412         }               
413         if(Trans.total==0) return;
414         
415         /* init trans data */
416     td = Trans.data = MEM_mallocN(Trans.total*sizeof(TransData), "TransPoseBone");
417     tdx = Trans.ext = MEM_mallocN(Trans.total*sizeof(TransDataExtension), "TransPoseBoneExt");
418         for(i=0; i<Trans.total; i++, td++, tdx++) {
419                 td->ext= tdx;
420                 td->tdi = NULL;
421                 td->val = NULL;
422         }       
423         /* recursive fill trans data */
424         td= Trans.data;
425         add_pose_transdata(&arm->bonebase, G.obpose, &td);
426         
427 }
428
429 static void createTransArmatureVerts(void)
430 {
431         EditBone *ebo;
432         TransData *td;
433         float mtx[3][3], smtx[3][3];
434
435         Trans.total = 0;
436         for (ebo=G.edbo.first;ebo;ebo=ebo->next){
437                 if (ebo->flag & BONE_TIPSEL){
438                         Trans.total++;
439                 }
440                 if (ebo->flag & BONE_ROOTSEL){
441                         Trans.total++;
442                 }
443         }
444
445     if (!Trans.total) return;
446         
447         Mat3CpyMat4(mtx, G.obedit->obmat);
448         Mat3Inv(smtx, mtx);
449
450     td = Trans.data = MEM_mallocN(Trans.total*sizeof(TransData), "TransEditBone");
451         
452         for (ebo=G.edbo.first;ebo;ebo=ebo->next){
453                 if (ebo->flag & BONE_TIPSEL){
454                         VECCOPY (td->iloc, ebo->tail);
455                         VECCOPY (td->center, td->iloc);
456                         td->loc= ebo->tail;
457                         td->flag= TD_SELECTED;
458
459                         Mat3CpyMat3(td->smtx, smtx);
460                         Mat3CpyMat3(td->mtx, mtx);
461
462                         td->ext = NULL;
463                         td->tdi = NULL;
464                         td->val = NULL;
465
466                         td++;
467                 }
468                 if (ebo->flag & BONE_ROOTSEL){
469                         VECCOPY (td->iloc, ebo->head);
470                         VECCOPY (td->center, td->iloc);
471                         td->loc= ebo->head;
472                         td->flag= TD_SELECTED;
473
474                         Mat3CpyMat3(td->smtx, smtx);
475                         Mat3CpyMat3(td->mtx, mtx);
476
477                         td->ext = NULL;
478                         td->tdi = NULL;
479                         td->val = NULL;
480
481                         td++;
482                 }
483                         
484         }
485 }
486
487 static void createTransMBallVerts(void)
488 {
489         MetaElem *ml;
490         TransData *td;
491         TransDataExtension *tx;
492         float mtx[3][3], smtx[3][3];
493         int count=0, countsel=0;
494         int propmode = Trans.flag & T_PROP_EDIT;
495
496         /* count totals */
497         for(ml= editelems.first; ml; ml= ml->next) {
498                 if(ml->flag & SELECT) countsel++;
499                 if(propmode) count++;
500         }
501
502         /* note: in prop mode we need at least 1 selected */
503         if (countsel==0) return;
504         
505         if(propmode) Trans.total = count; 
506         else Trans.total = countsel;
507         
508         Trans.data= MEM_mallocN(Trans.total*sizeof(TransData), "TransObData(MBall EditMode)");
509         tx = Trans.ext = MEM_mallocN(Trans.total*sizeof(TransDataExtension), "MetaElement_TransExtension");
510
511         Mat3CpyMat4(mtx, G.obedit->obmat);
512         Mat3Inv(smtx, mtx);
513     
514         td = Trans.data;
515         for(ml= editelems.first; ml; ml= ml->next) {
516                 if(propmode || (ml->flag & SELECT)) {
517                         td->loc= &ml->x;
518                         VECCOPY(td->iloc, td->loc);
519                         VECCOPY(td->center, td->loc);
520
521                         if(ml->flag & SELECT) td->flag= TD_SELECTED | TD_USEQUAT;
522                         else td->flag= TD_USEQUAT;
523
524                         Mat3CpyMat3(td->smtx, smtx);
525                         Mat3CpyMat3(td->mtx, mtx);
526
527                         td->ext = tx;
528                         td->tdi = NULL;
529                         td->val = NULL;
530
531                         tx->size = &ml->expx;
532                         tx->isize[0] = ml->expx;
533                         tx->isize[1] = ml->expy;
534                         tx->isize[2] = ml->expz;
535
536                         tx->quat = ml->quat;
537                         QUATCOPY(tx->iquat, ml->quat);
538
539                         tx->rot = NULL;
540
541                         td++;
542                         tx++;
543                 }
544         }
545
546
547 static void calc_distanceCurveVerts(TransData *head, TransData *tail) {
548         TransData *td, *td_near = NULL;
549         for (td = head; td<=tail; td++) {
550                 if (td->flag & TD_SELECTED) {
551                         td_near = td;
552                         td->dist = 0.0f;
553                 }
554                 else if(td_near) {
555                         float dist;
556                         dist = VecLenf(td_near->center, td->center);
557                         if (dist < (td-1)->dist) {
558                                 td->dist = (td-1)->dist;
559                         }
560                         else {
561                                 td->dist = dist;
562                         }
563                 }
564                 else {
565                         td->dist = 1000000.0f;
566                         td->flag |= TD_NOTCONNECTED;
567                 }
568         }
569         td_near = NULL;
570         for (td = tail; td>=head; td--) {
571                 if (td->flag & TD_SELECTED) {
572                         td_near = td;
573                         td->dist = 0.0f;
574                 }
575                 else if(td_near) {
576                         float dist;
577                         dist = VecLenf(td_near->center, td->center);
578                         if (td->flag & TD_NOTCONNECTED || dist < td->dist || (td+1)->dist < td->dist) {
579                                 td->flag &= ~TD_NOTCONNECTED;
580                                 if (dist < (td+1)->dist) {
581                                         td->dist = (td+1)->dist;
582                                 }
583                                 else {
584                                         td->dist = dist;
585                                 }
586                         }
587                 }
588         }
589 }
590
591 static void createTransCurveVerts(void)
592 {
593         TransData *td = NULL;
594         Nurb *nu;
595         BezTriple *bezt;
596         BPoint *bp;
597         float mtx[3][3], smtx[3][3];
598         int a;
599         int count=0, countsel=0;
600         int propmode = Trans.flag & T_PROP_EDIT;
601
602         /* count total of vertices, check identical as in 2nd loop for making transdata! */
603         for(nu= editNurb.first; nu; nu= nu->next) {
604                 if((nu->type & 7)==CU_BEZIER) {
605                         for(a=0, bezt= nu->bezt; a<nu->pntsu; a++, bezt++) {
606                                 if(bezt->hide==0) {
607                                         if(bezt->f1 & 1) countsel++;
608                                         if(bezt->f2 & 1) countsel++;
609                                         if(bezt->f3 & 1) countsel++;
610                                         if(propmode) count+= 3;
611                                 }
612                         }
613                 }
614                 else {
615                         for(a= nu->pntsu*nu->pntsv, bp= nu->bp; a>0; a--, bp++) {
616                                 if(bp->hide==0) {
617                                         if(propmode) count++;
618                                         if(bp->f1 & 1) countsel++;
619                                 }
620                         }
621                 }
622         }
623         /* note: in prop mode we need at least 1 selected */
624         if (countsel==0) return;
625         
626         if(propmode) Trans.total = count; 
627         else Trans.total = countsel;
628         Trans.data= MEM_mallocN(Trans.total*sizeof(TransData), "TransObData(Curve EditMode)");
629
630         Mat3CpyMat4(mtx, G.obedit->obmat);
631         Mat3Inv(smtx, mtx);
632
633     td = Trans.data;
634         for(nu= editNurb.first; nu; nu= nu->next) {
635                 if((nu->type & 7)==CU_BEZIER) {
636                         for(a=0, bezt= nu->bezt; a<nu->pntsu; a++, bezt++) {
637                                 if(bezt->hide==0) {
638                                         if(propmode || (bezt->f1 & 1)) {
639                                                 VECCOPY(td->iloc, bezt->vec[0]);
640                                                 td->loc= bezt->vec[0];
641                                                 VECCOPY(td->center, bezt->vec[1]);
642                                                 if(bezt->f1 & 1) td->flag= TD_SELECTED;
643                                                 else td->flag= 0;
644                                                 td->ext = NULL;
645                                                 td->tdi = NULL;
646                                                 td->val = NULL;
647
648                                                 Mat3CpyMat3(td->smtx, smtx);
649                                                 Mat3CpyMat3(td->mtx, mtx);
650
651                                                 td++;
652                                                 count++;
653                                         }
654                                         /* THIS IS THE CV, the other two are handles */
655                                         if(propmode || (bezt->f2 & 1)) {
656                                                 VECCOPY(td->iloc, bezt->vec[1]);
657                                                 td->loc= bezt->vec[1];
658                                                 VECCOPY(td->center, td->loc);
659                                                 if(bezt->f2 & 1) td->flag= TD_SELECTED;
660                                                 else td->flag= 0;
661                                                 td->ext = NULL;
662                                                 td->tdi = NULL;
663                                                 td->val = &(bezt->alfa);
664                                                 td->ival = bezt->alfa;
665
666                                                 Mat3CpyMat3(td->smtx, smtx);
667                                                 Mat3CpyMat3(td->mtx, mtx);
668
669                                                 td++;
670                                                 count++;
671                                         }
672                                         if(propmode || (bezt->f3 & 1)) {
673                                                 VECCOPY(td->iloc, bezt->vec[2]);
674                                                 td->loc= bezt->vec[2];
675                                                 VECCOPY(td->center, bezt->vec[1]);
676                                                 if(bezt->f3 & 1) td->flag= TD_SELECTED;
677                                                 else td->flag= 0;
678                                                 td->ext = NULL;
679                                                 td->tdi = NULL;
680                                                 td->val = NULL;
681
682                                                 Mat3CpyMat3(td->smtx, smtx);
683                                                 Mat3CpyMat3(td->mtx, mtx);
684
685                                                 td++;
686                                                 count++;
687                                         }
688                                 }
689                         }
690                         if (propmode)
691                                 calc_distanceCurveVerts(td-(nu->pntsu*3), td-1);
692                 }
693                 else {
694                         for(a= nu->pntsu*nu->pntsv, bp= nu->bp; a>0; a--, bp++) {
695                                 if(bp->hide==0) {
696                                         if(propmode || (bp->f1 & 1)) {
697                                                 VECCOPY(td->iloc, bp->vec);
698                                                 td->loc= bp->vec;
699                                                 VECCOPY(td->center, td->loc);
700                                                 if(bp->f1 & 1) td->flag= TD_SELECTED;
701                                                 else td->flag= 0;
702                                                 td->ext = NULL;
703                                                 td->tdi = NULL;
704                                                 td->val = &(bp->alfa);
705                                                 td->ival = bp->alfa;
706
707                                                 Mat3CpyMat3(td->smtx, smtx);
708                                                 Mat3CpyMat3(td->mtx, mtx);
709
710                                                 td++;
711                                                 count++;
712                                         }
713                                 }
714                         }
715                         if (propmode)
716                                 calc_distanceCurveVerts(td-(nu->pntsu*nu->pntsv), td-1);
717                 }
718         }
719 }
720
721 static void createTransLatticeVerts(void)
722 {
723         TransData *td = NULL;
724         BPoint *bp;
725         float mtx[3][3], smtx[3][3];
726         int a;
727         int count=0, countsel=0;
728         int propmode = Trans.flag & T_PROP_EDIT;
729
730         bp= editLatt->def;
731         a= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
732         while(a--) {
733                 if(bp->f1 & 1) countsel++;
734                 if(propmode) count++;
735                 bp++;
736         }
737         
738         /* note: in prop mode we need at least 1 selected */
739         if (countsel==0) return;
740         
741         if(propmode) Trans.total = count; 
742         else Trans.total = countsel;
743         Trans.data= MEM_mallocN(Trans.total*sizeof(TransData), "TransObData(Lattice EditMode)");
744         
745         Mat3CpyMat4(mtx, G.obedit->obmat);
746         Mat3Inv(smtx, mtx);
747
748         td = Trans.data;
749         bp= editLatt->def;
750         a= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
751         while(a--) {
752                 if(propmode || (bp->f1 & 1)) {
753                         if(bp->hide==0) {
754                                 VECCOPY(td->iloc, bp->vec);
755                                 td->loc= bp->vec;
756                                 VECCOPY(td->center, td->loc);
757                                 if(bp->f1 & 1) td->flag= TD_SELECTED;
758                                 else td->flag= 0;
759                                 Mat3CpyMat3(td->smtx, smtx);
760                                 Mat3CpyMat3(td->mtx, mtx);
761
762                                 td->ext = NULL;
763                                 td->tdi = NULL;
764                                 td->val = NULL;
765
766                                 td++;
767                                 count++;
768                         }
769                 }
770                 bp++;
771         }
772
773
774 /* proportional distance based on connectivity  */
775 #define E_VEC(a)        (vectors + (3 * (int)(a)->vn))
776 #define E_NEAR(a)       (nears[((int)(a)->vn)])
777 static void editmesh_set_connectivity_distance(int total, float *vectors, EditVert **nears)
778 {
779         EditMesh *em = G.editMesh;
780         EditVert *eve;
781         EditEdge *eed;
782         int i= 0, done= 1;
783
784         /* f2 flag is used for 'selection' */
785         /* vn is offset on scratch array   */
786         for(eve= em->verts.first; eve; eve= eve->next, i++) {
787                 if(eve->h==0) {
788                         eve->vn = (EditVert *)(i);
789
790                         if(eve->f & SELECT) {
791                                 eve->f2= 2;
792                                 E_NEAR(eve) = eve;
793                                 E_VEC(eve)[0] = 0.0f;
794                                 E_VEC(eve)[1] = 0.0f;
795                                 E_VEC(eve)[2] = 0.0f;
796                         }
797                         else {
798                                 eve->f2 = 0;
799                         }
800                 }
801         }
802
803
804         /* Floodfill routine */
805         /*
806         At worst this is n*n of complexity where n is number of edges 
807         Best case would be n if the list is ordered perfectly.
808         Estimate is n log n in average (so not too bad)
809         */
810         while(done) {
811                 done= 0;
812                 
813                 for(eed= em->edges.first; eed; eed= eed->next) {
814                         if(eed->h==0) {
815                                 EditVert *v1= eed->v1, *v2= eed->v2;
816                                 float *vec2 = E_VEC(v2);
817                                 float *vec1 = E_VEC(v1);
818
819                                 if (v1->f2 + v2->f2 == 4)
820                                         continue;
821
822                                 if (v1->f2) {
823                                         if (v2->f2) {
824                                                 float nvec[3];
825                                                 float len1 = VecLength(vec1);
826                                                 float len2 = VecLength(vec2);
827                                                 float lenn;
828                                                 /* for v2 if not selected */
829                                                 if (v2->f2 != 2) {
830                                                         VecSubf(nvec, v2->co, E_NEAR(v1)->co);
831                                                         lenn = VecLength(nvec);
832                                                         if (lenn - len1 > 0.00001f && len2 - lenn > 0.00001f) {
833                                                                 VECCOPY(vec2, nvec);
834                                                                 E_NEAR(v2) = E_NEAR(v1);
835                                                                 done = 1;
836                                                         }
837                                                         else if (len2 - len1 > 0.00001f && len1 - lenn > 0.00001f) {
838                                                                 VECCOPY(vec2, vec1);
839                                                                 E_NEAR(v2) = E_NEAR(v1);
840                                                                 done = 1;
841                                                         }
842                                                 }
843                                                 /* for v1 if not selected */
844                                                 if (v1->f2 != 2) {
845                                                         VecSubf(nvec, v1->co, E_NEAR(v2)->co);
846                                                         lenn = VecLength(nvec);
847                                                         if (lenn - len2 > 0.00001f && len1 - lenn > 0.00001f) {
848                                                                 VECCOPY(vec1, nvec);
849                                                                 E_NEAR(v1) = E_NEAR(v2);
850                                                                 done = 1;
851                                                         }
852                                                         else if (len1 - len2 > 0.00001f && len2 - lenn > 0.00001f) {
853                                                                 VECCOPY(vec1, vec2);
854                                                                 E_NEAR(v1) = E_NEAR(v2);
855                                                                 done = 1;
856                                                         }
857                                                 }
858                                         }
859                                         else {
860                                                 v2->f2 = 1;
861                                                 VecSubf(vec2, v2->co, E_NEAR(v1)->co);
862                                                 if (VecLength(vec1) - VecLength(vec2) > 0.00001f) {
863                                                         VECCOPY(vec2, vec1);
864                                                 }
865                                                 E_NEAR(v2) = E_NEAR(v1);
866                                                 done = 1;
867                                         }
868                                 }
869                                 else if (v2->f2) {
870                                         v1->f2 = 1;
871                                         VecSubf(vec1, v1->co, E_NEAR(v2)->co);
872                                         if (VecLength(vec2) - VecLength(vec1) > 0.00001f) {
873                                                 VECCOPY(vec1, vec2);
874                                         }
875                                         E_NEAR(v1) = E_NEAR(v2);
876                                         done = 1;
877                                 }
878                         }
879                 }
880         }
881
882         /* set unused or clipped away vertices on huge dist */
883         for(i=0, eve= em->verts.first; eve; eve= eve->next, i++) {
884                 if(eve->f2==0) {
885                         E_NEAR(eve) = NULL;
886                 }
887         }
888 }
889
890
891 static void VertsToTransData(TransData *td, EditVert *eve)
892 {
893         td->flag = 0;
894         td->loc = eve->co;
895         VECCOPY(td->center, td->loc);
896         VECCOPY(td->iloc, td->loc);
897
898         // Setting normals
899         VECCOPY(td->axismtx[2], eve->no);
900         td->axismtx[0][0]               =
901                 td->axismtx[0][1]       =
902                 td->axismtx[0][2]       =
903                 td->axismtx[1][0]       =
904                 td->axismtx[1][1]       =
905                 td->axismtx[1][2]       = 0.0f;
906
907         td->ext = NULL;
908         td->tdi = NULL;
909         td->val = NULL;
910 }
911
912 static void createTransEditVerts(void)
913 {
914         TransData *tob = NULL;
915         EditMesh *em = G.editMesh;
916         EditVert *eve;
917         EditVert **nears;
918         float mtx[3][3], smtx[3][3];
919         float *vectors;
920         int count=0, countsel=0;
921         int propmode = Trans.flag & T_PROP_EDIT;
922                 
923         // transform now requires awareness for select mode, so we tag the f1 flags in verts
924         if(G.scene->selectmode & SCE_SELECT_VERTEX) {
925                 for(eve= em->verts.first; eve; eve= eve->next) {
926                         if(eve->h==0 && (eve->f & SELECT)) 
927                                 eve->f1= SELECT;
928                         else
929                                 eve->f1= 0;
930                 }
931         }
932         else if(G.scene->selectmode & SCE_SELECT_EDGE) {
933                 EditEdge *eed;
934                 for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;
935                 for(eed= em->edges.first; eed; eed= eed->next) {
936                         if(eed->h==0 && (eed->f & SELECT))
937                                 eed->v1->f1= eed->v2->f1= SELECT;
938                 }
939         }
940         else {
941                 EditFace *efa;
942                 for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;
943                 for(efa= em->faces.first; efa; efa= efa->next) {
944                         if(efa->h==0 && (efa->f & SELECT)) {
945                                 efa->v1->f1= efa->v2->f1= efa->v3->f1= SELECT;
946                                 if(efa->v4) efa->v4->f1= SELECT;
947                         }
948                 }
949         }
950         
951         /* now we can count */
952         for(eve= em->verts.first; eve; eve= eve->next) {
953                 if(eve->h==0) {
954                         if(eve->f1) countsel++;
955                         if(propmode) count++;
956                 }
957         }
958         
959         /* note: in prop mode we need at least 1 selected */
960         if (countsel==0) return;
961         
962         if(propmode) {
963                 Trans.total = count; 
964         
965                 /* allocating scratch arrays */
966                 vectors = (float *)malloc(Trans.total * 3 * sizeof(float));
967                 nears = (EditVert**)malloc(Trans.total * sizeof(EditVert*));
968         }
969         else Trans.total = countsel;
970         tob= Trans.data= MEM_mallocN(Trans.total*sizeof(TransData), "TransObData(Mesh EditMode)");
971         
972         Mat3CpyMat4(mtx, G.obedit->obmat);
973         Mat3Inv(smtx, mtx);
974
975         if(propmode) editmesh_set_connectivity_distance(Trans.total, vectors, nears);
976         
977         for (eve=em->verts.first; eve; eve=eve->next) {
978                 if(eve->h==0) {
979                         if(propmode || eve->f1) {
980                                 VertsToTransData(tob, eve);
981
982                                 if(eve->f1) tob->flag |= TD_SELECTED;
983                                 if(propmode) {
984                                         if (E_NEAR(eve)) {
985                                                 tob->dist= VecLength(E_VEC(eve));
986                                         }
987                                         else {
988                                                 tob->flag |= TD_NOTCONNECTED;
989                                                 tob->dist = 10000000.0f;
990                                         }
991                                 }
992                                 
993                                 Mat3CpyMat3(tob->smtx, smtx);
994                                 Mat3CpyMat3(tob->mtx, mtx);
995
996                                 tob++;
997                         }
998                 }       
999         }
1000         if (propmode) {
1001                 free(nears);
1002                 free(vectors);
1003         }
1004
1005 }
1006
1007 /* **************** IpoKey stuff, for Object TransData ********** */
1008
1009 /* storage of bezier triple. thats why -3 and +3! */
1010 static void set_tdi_old(float *old, float *poin)
1011 {
1012         old[0]= *(poin);
1013         old[3]= *(poin-3);
1014         old[6]= *(poin+3);
1015 }
1016
1017 /* while transforming */
1018 static void add_tdi_poin(float *poin, float *old, float delta)
1019 {
1020         if(poin) {
1021                 poin[0]= old[0]+delta;
1022                 poin[-3]= old[3]+delta;
1023                 poin[3]= old[6]+delta;
1024         }
1025 }
1026
1027 /* fill ipokey transdata with old vals and pointers */
1028 static void ipokey_to_transdata(IpoKey *ik, TransData *td)
1029 {
1030         extern int ob_ar[];             // blenkernel ipo.c
1031         TransDataIpokey *tdi= td->tdi;
1032         BezTriple *bezt;
1033         int a, delta= 0;
1034         
1035         for(a=0; a<OB_TOTIPO; a++) {
1036                 if(ik->data[a]) {
1037                         bezt= ik->data[a];
1038                         
1039                         switch( ob_ar[a] ) {
1040                                 case OB_LOC_X:
1041                                 case OB_DLOC_X:
1042                                         tdi->locx= &(bezt->vec[1][1]); break;
1043                                 case OB_LOC_Y:
1044                                 case OB_DLOC_Y:
1045                                         tdi->locy= &(bezt->vec[1][1]); break;
1046                                 case OB_LOC_Z:
1047                                 case OB_DLOC_Z:
1048                                         tdi->locz= &(bezt->vec[1][1]); break;
1049                                         
1050                                 case OB_DROT_X:
1051                                         delta= 1;
1052                                 case OB_ROT_X:
1053                                         tdi->rotx= &(bezt->vec[1][1]); break;
1054                                 case OB_DROT_Y:
1055                                         delta= 1;
1056                                 case OB_ROT_Y:
1057                                         tdi->roty= &(bezt->vec[1][1]); break;
1058                                 case OB_DROT_Z:
1059                                         delta= 1;
1060                                 case OB_ROT_Z:
1061                                         tdi->rotz= &(bezt->vec[1][1]); break;
1062                                         
1063                                 case OB_SIZE_X:
1064                                 case OB_DSIZE_X:
1065                                         tdi->sizex= &(bezt->vec[1][1]); break;
1066                                 case OB_SIZE_Y:
1067                                 case OB_DSIZE_Y:
1068                                         tdi->sizey= &(bezt->vec[1][1]); break;
1069                                 case OB_SIZE_Z:
1070                                 case OB_DSIZE_Z:
1071                                         tdi->sizez= &(bezt->vec[1][1]); break;          
1072                         }       
1073                 }
1074         }
1075         
1076         /* oldvals for e.g. undo */
1077         if(tdi->locx) set_tdi_old(tdi->oldloc, tdi->locx);
1078         if(tdi->locy) set_tdi_old(tdi->oldloc+1, tdi->locy);
1079         if(tdi->locz) set_tdi_old(tdi->oldloc+2, tdi->locz);
1080         
1081         /* remember, for mapping curves ('1'=10 degrees)  */
1082         if(tdi->rotx) set_tdi_old(tdi->oldrot, tdi->rotx);
1083         if(tdi->roty) set_tdi_old(tdi->oldrot+1, tdi->roty);
1084         if(tdi->rotz) set_tdi_old(tdi->oldrot+2, tdi->rotz);
1085         
1086         /* this is not allowed to be dsize! */
1087         if(tdi->sizex) set_tdi_old(tdi->oldsize, tdi->sizex);
1088         if(tdi->sizey) set_tdi_old(tdi->oldsize+1, tdi->sizey);
1089         if(tdi->sizez) set_tdi_old(tdi->oldsize+2, tdi->sizez);
1090         
1091         tdi->flag= TOB_IPO;
1092         if(delta) tdi->flag |= TOB_IPODROT;
1093 }
1094
1095
1096 /* *************************** Object Transform data ******************* */
1097
1098 static void ObjectToTransData(TransData *td, Object *ob) 
1099 {
1100         float obmtx[3][3];
1101         Object *tr;
1102         void *cfirst, *clast;
1103
1104         cfirst = ob->constraints.first;
1105         clast = ob->constraints.last;
1106         ob->constraints.first=ob->constraints.last=NULL;
1107
1108         tr= ob->track;
1109         ob->track= NULL;
1110
1111         where_is_object(ob);
1112
1113         ob->track= tr;
1114
1115         ob->constraints.first = cfirst;
1116         ob->constraints.last = clast;
1117
1118         td->ob = ob;
1119
1120         td->loc = ob->loc;
1121         VECCOPY(td->iloc, td->loc);
1122         
1123         td->ext->rot = ob->rot;
1124         VECCOPY(td->ext->irot, ob->rot);
1125         VECCOPY(td->ext->drot, ob->drot);
1126         
1127         td->ext->size = ob->size;
1128         VECCOPY(td->ext->isize, ob->size);
1129         VECCOPY(td->ext->dsize, ob->dsize);
1130
1131         VECCOPY(td->center, ob->obmat[3]);
1132
1133         Mat3CpyMat4(td->axismtx, ob->obmat);
1134         Mat3Ortho(td->axismtx);
1135
1136         if (ob->parent)
1137         {
1138                 float totmat[3][3], obinv[3][3];
1139                 
1140                 /* we calculate smtx without obmat: so a parmat */
1141                 object_to_mat3(ob, obmtx);
1142                 Mat3CpyMat4(totmat, ob->obmat);
1143                 Mat3Inv(obinv, totmat);
1144                 Mat3MulMat3(td->smtx, obmtx, obinv);
1145                 Mat3Inv(td->mtx, td->smtx);
1146         }
1147         else
1148         {
1149                 Mat3One(td->smtx);
1150                 Mat3One(td->mtx);
1151         }
1152 }
1153
1154 /* only used in function below, stuff to be removed */
1155 static Object *is_a_parent_selected_int(Object *startob, Object *ob, GHash *done_hash) 
1156 {
1157         if (ob!=startob && TESTBASE(ob))
1158                 return ob;
1159         
1160         if (BLI_ghash_haskey(done_hash, ob))
1161                 return NULL;
1162         else
1163                 BLI_ghash_insert(done_hash, ob, NULL);
1164         
1165         if (ob->parent) {
1166                 Object *par= is_a_parent_selected_int(startob, ob->parent, done_hash);
1167                 if (par)
1168                         return par;
1169         }
1170         return NULL;
1171 }
1172
1173 /* only used in function below, stuff to be removed */
1174 static Object *is_a_parent_selected(Object *ob) 
1175 {
1176         GHash *gh= BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
1177         Object *res= is_a_parent_selected_int(ob, ob, gh);
1178         BLI_ghash_free(gh, NULL, NULL);
1179         
1180         return res;
1181 }
1182
1183
1184
1185 /* sets flags in Bases to define whether they take part in transform */
1186 /* it deselects Bases, so we have to call the clear function always after */
1187 static void set_trans_object_base_flags(TransInfo *t)
1188 {
1189         /*
1190          if Base selected and has parent selected:
1191          base->flag= BA_WASSEL+BA_PARSEL
1192          if base not selected and parent selected:
1193          base->flag= BA_PARSEL
1194          */
1195         GHash *object_to_base_hash= NULL; 
1196         Base *base;
1197         
1198         /* moved to start of function, it is needed for hooks now too */
1199         if (!object_to_base_hash) {
1200                 Base *b;
1201                 object_to_base_hash= BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
1202                 
1203                 for (b= FIRSTBASE; b; b= b->next)
1204                         BLI_ghash_insert(object_to_base_hash, b->object, b);
1205         }
1206         
1207         /* makes sure base flags and object flags are identical */
1208         copy_baseflags();
1209         
1210         for (base= FIRSTBASE; base; base= base->next) {
1211                 base->flag &= ~(BA_PARSEL+BA_WASSEL);
1212                 
1213                 if( (base->lay & G.vd->lay) && base->object->id.lib==0) {
1214                         Object *ob= base->object;
1215                         Object *parsel= is_a_parent_selected(ob);
1216                         
1217                         /* parentkey here? */
1218                         
1219                         if(parsel) {
1220                                 if(base->flag & SELECT) {
1221                                         base->flag &= ~SELECT;
1222                                         base->flag |= (BA_PARSEL+BA_WASSEL);
1223                                 }
1224                                 else base->flag |= BA_PARSEL;
1225                         }
1226                         
1227                         if(t->mode==TFM_TRANSLATION)  {
1228                                 if(ob->track && TESTBASE(ob->track) && (base->flag & SELECT)==0)  
1229                                         base->flag |= BA_PARSEL;
1230                         }
1231                         
1232                         /* updates? */
1233                         if(ob->hooks.first) {
1234                                 Base *b;
1235                                 ObHook *hook= ob->hooks.first;
1236                                 
1237                                 while(hook) {
1238                                         if(hook->parent) {
1239                                                 Object *parsel= is_a_parent_selected(hook->parent);
1240                                                 
1241                                                 b= BLI_ghash_lookup(object_to_base_hash, hook->parent);
1242                                                 if(parsel || ((base->flag | b->flag) & (SELECT | BA_PARSEL)) ) {
1243                                                         base->flag |= BA_DISP_UPDATE;
1244                                                 }
1245                                         }
1246                                         hook= hook->next;
1247                                 }
1248                         }
1249                         
1250                         if(ob->parent && ob->parent->type==OB_LATTICE)
1251                                 if(ob->parent->hooks.first) base->flag |= BA_DISP_UPDATE;
1252                         
1253                         if(base->flag & (SELECT | BA_PARSEL)) {
1254                                 
1255                                 base->flag |= BA_WHERE_UPDATE;
1256                                 
1257                                 if(ob->parent) {
1258                                         if(ob->parent->type==OB_LATTICE) base->flag |= BA_DISP_UPDATE;
1259                                         else if(ob->partype==PARSKEL) {
1260                                                 if ELEM3(ob->parent->type, OB_IKA, OB_CURVE, OB_ARMATURE) 
1261                                                         base->flag |= BA_DISP_UPDATE;
1262                                         }
1263                                 }
1264                                 if(ob->track) {
1265                                         ;
1266                                 }
1267                                 
1268                                 if( give_parteff(ob) ) base->flag |= BA_DISP_UPDATE;
1269                                 
1270                                 if(ob->type==OB_MBALL) {
1271                                         Base *b;
1272                                         
1273                                         b= BLI_ghash_lookup(object_to_base_hash, find_basis_mball(ob));
1274                                         b->flag |= BA_DISP_UPDATE;
1275                                 }
1276                         }
1277                 }
1278         }
1279         
1280         if (object_to_base_hash)
1281                 BLI_ghash_free(object_to_base_hash, NULL, NULL);
1282         
1283 }
1284
1285 static void clear_trans_object_base_flags(void)
1286 {
1287         Base *base;
1288         
1289         base= FIRSTBASE;
1290         while(base) {
1291                 if(base->flag & BA_WASSEL) base->flag |= SELECT;
1292                 base->flag &= ~(BA_PARSEL+BA_WASSEL);
1293                 
1294                 base->flag &= ~(BA_DISP_UPDATE+BA_WHERE_UPDATE+BA_DO_IPO);
1295                 
1296                 /* pose here? */
1297                 if (base->object->pose) {
1298                         Object *ob= base->object;
1299                         bPoseChannel *chan;
1300                         for (chan = ob->pose->chanbase.first; chan; chan=chan->next) {
1301                                 chan->flag &= ~PCHAN_TRANS_UPDATE;
1302                         }
1303                 }
1304                 
1305                 base= base->next;
1306         }
1307         copy_baseflags();
1308 }
1309
1310
1311 static void createTransObject(void)
1312 {
1313         TransData *td = NULL;
1314         TransDataExtension *tx;
1315         Object *ob;
1316         Base *base;
1317         IpoKey *ik;
1318         ListBase elems;
1319         
1320         /* hackish... but we have to do it somewhere */
1321         reset_slowparents();
1322         
1323         set_trans_object_base_flags(&Trans);
1324         
1325         /* count */     
1326         for(base= FIRSTBASE; base; base= base->next) {
1327                 if TESTBASELIB(base) {
1328                         ob= base->object;
1329                         
1330                         /* store ipo keys? */
1331                         if(ob->ipo && ob->ipo->showkey && (ob->ipoflag & OB_DRAWKEY)) {
1332                                 elems.first= elems.last= NULL;
1333                                 make_ipokey_transform(ob, &elems, 1); /* '1' only selected keys */
1334                                 
1335                                 pushdata(&elems, sizeof(ListBase));
1336                                 
1337                                 for(ik= elems.first; ik; ik= ik->next) Trans.total++;
1338
1339                                 if(elems.first==NULL) Trans.total++;
1340                         }
1341                         else {
1342                                 Trans.total++;
1343                         }
1344                 }
1345         }
1346
1347         if(!Trans.total) {
1348                 /* clear here, main transform function escapes too */
1349                 clear_trans_object_base_flags();
1350                 return;
1351         }
1352         
1353         td = Trans.data = MEM_mallocN(Trans.total*sizeof(TransData), "TransOb");
1354         tx = Trans.ext = MEM_mallocN(Trans.total*sizeof(TransDataExtension), "TransObExtension");
1355
1356         for(base= FIRSTBASE; base; base= base->next) {
1357                 if TESTBASELIB(base) {
1358                         ob= base->object;
1359                         
1360                         td->flag= TD_SELECTED;
1361                         td->ext = tx;
1362
1363                         /* store ipo keys? */
1364                         if(ob->ipo && ob->ipo->showkey && (ob->ipoflag & OB_DRAWKEY)) {
1365                                 
1366                                 popfirst(&elems);       // bring back pushed listbase
1367                                 
1368                                 if(elems.first) {
1369                                         float cfraont;
1370                                         int ipoflag;
1371                                         
1372                                         base->flag |= BA_DO_IPO+BA_WASSEL;
1373                                         base->flag &= ~SELECT;
1374                                         
1375                                         cfraont= CFRA;
1376                                         set_no_parent_ipo(1);
1377                                         ipoflag= ob->ipoflag;
1378                                         ob->ipoflag &= ~OB_OFFS_OB;
1379                                         
1380                                         pushdata(ob->loc, 7*3*4); // tsk! tsk!
1381                                         
1382                                         for(ik= elems.first; ik; ik= ik->next) {
1383                                                 
1384                                                 /* weak... this doesn't correct for floating values, giving small errors */
1385                                                 CFRA= (short)(ik->val/G.scene->r.framelen);
1386                                                 
1387                                                 do_ob_ipo(ob);
1388                                                 ObjectToTransData(td, ob);      // does where_is_object()
1389                                                 
1390                                                 td->tdi= MEM_callocN(sizeof(TransDataIpokey), "TransDataIpokey");
1391                                                 /* also does tdi->flag and oldvals, needs to be after ob_to_transob()! */
1392                                                 ipokey_to_transdata(ik, td);
1393                                                 
1394                                                 td++;
1395                                                 tx++;
1396                                                 if(ik->next) td->ext= tx;       // prevent corrupting mem!
1397                                         }
1398                                         free_ipokey(&elems);
1399                                         
1400                                         poplast(ob->loc);
1401                                         set_no_parent_ipo(0);
1402                                         
1403                                         CFRA= (short)cfraont;
1404                                         ob->ipoflag= ipoflag;
1405                                 }
1406                                 else {
1407                                         ObjectToTransData(td, ob);
1408                                         td->tdi = NULL;
1409                                         td->val = NULL;
1410                                 }
1411                         }
1412                         else {
1413                                 ObjectToTransData(td, ob);
1414                                 td->tdi = NULL;
1415                                 td->val = NULL;
1416                         }
1417                         td++;
1418                         tx++;
1419                 }
1420         }
1421 }
1422
1423 static void createTransData(TransInfo *t) 
1424 {
1425         if (t->context == CTX_TEXTURE) {
1426                 t->flag |= T_TEXTURE;
1427                 createTransTexspace();
1428         }
1429         else if (G.obpose) {
1430                 t->flag |= T_POSE;
1431                 createTransPose();
1432         }
1433         else if (G.obedit) {
1434                 t->ext = NULL;
1435                 if (G.obedit->type == OB_MESH) {
1436                         if(t->mode==TFM_SHRINKFATTEN) vertexnormals(0);
1437                         createTransEditVerts(); 
1438                 }
1439                 else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) {
1440                         createTransCurveVerts();
1441                 }
1442                 else if (G.obedit->type==OB_LATTICE) {
1443                         createTransLatticeVerts();
1444                 }
1445                 else if (G.obedit->type==OB_MBALL) {
1446                         createTransMBallVerts();
1447                 }
1448                 else if (G.obedit->type==OB_ARMATURE) {
1449                         createTransArmatureVerts();
1450                 }                                                       
1451                 else {
1452                         printf("not done yet! only have mesh surface curve\n");
1453                 }
1454                 
1455                 if(t->flag & T_PROP_EDIT) {
1456                         if (ELEM(G.obedit->type, OB_CURVE, OB_MESH)) {
1457                                 sort_trans_data(t);     // makes selected become first in array
1458                                 set_prop_dist(t, 0);
1459                                 sort_trans_data_dist(t);
1460                         }
1461                         else {
1462                                 sort_trans_data(t);     // makes selected become first in array
1463                                 set_prop_dist(t, 1);
1464                                 sort_trans_data_dist(t);
1465                         }
1466                 }
1467                 t->flag |= T_EDIT;
1468         }
1469         else {
1470                 createTransObject();
1471                 t->flag |= T_OBJECT;
1472         }
1473
1474         if((t->flag & T_OBJECT) && G.vd->camera==OBACT && G.vd->persp>1) {
1475                 t->flag |= T_CAMERA;
1476         }
1477 }
1478
1479 #define TRANS_CANCEL    2
1480 #define TRANS_CONFIRM   1
1481
1482 /* ************************** TRANSFORMATIONS **************************** */
1483
1484 void Transform(int mode, int context) 
1485 {
1486         int ret_val = 0;
1487         short pmval[2] = {0, 0}, mval[2], val;
1488         float mati[3][3];
1489         unsigned short event;
1490         char cmode = '\0';
1491
1492         /*joeedh -> hopefully may be what makes the old transform() constant*/
1493         /* ton: I doubt, but it doesnt harm for now. shouldnt be needed though */
1494         areawinset(curarea->win);
1495
1496         Mat3One(mati);
1497
1498         /* stupid PET initialisation code */
1499         /* START */
1500         if (Trans.propsize == 0.0f) {
1501                 Trans.propsize = 1.0;
1502         }
1503         /* END */
1504
1505         if (mode == TFM_REPEAT) {
1506                 mode = LastMode;
1507         }
1508         else {
1509                 LastMode = mode;
1510         }
1511
1512         Trans.context = context;
1513
1514         initTrans(&Trans);                                      // internal data, mouse, vectors
1515
1516         initTransModeFlags(&Trans, mode);       // modal settings in struct Trans
1517
1518         createTransData(&Trans);                        // make TransData structs from selection
1519
1520         if (Trans.total == 0)
1521                 return;
1522
1523         /* EVIL! posemode code can switch translation to rotate when 1 bone is selected. will be removed (ton) */
1524         /* EVIL2: we gave as argument also texture space context bit... was cleared */
1525         mode= Trans.mode;
1526         
1527         calculatePropRatio(&Trans);
1528         calculateCenter(&Trans);
1529
1530         switch (mode) {
1531         case TFM_TRANSLATION:
1532                 initTranslation(&Trans);
1533                 break;
1534         case TFM_ROTATION:
1535                 initRotation(&Trans);
1536                 break;
1537         case TFM_RESIZE:
1538                 initResize(&Trans);
1539                 break;
1540         case TFM_TOSPHERE:
1541                 initToSphere(&Trans);
1542                 break;
1543         case TFM_SHEAR:
1544                 initShear(&Trans);
1545                 break;
1546         case TFM_WARP:
1547                 initWarp(&Trans);
1548                 break;
1549         case TFM_SHRINKFATTEN:
1550                 initShrinkFatten(&Trans);
1551                 break;
1552         case TFM_TILT:
1553                 initTilt(&Trans);
1554                 break;
1555         case TFM_TRACKBALL:
1556                 initTrackball(&Trans);
1557                 break;
1558         case TFM_PUSHPULL:
1559                 initPushPull(&Trans);
1560                 break;
1561         }
1562
1563         initConstraint(&Trans);
1564
1565         // Emptying event queue
1566         while( qtest() ) {
1567                 event= extern_qread(&val);
1568         }
1569
1570         Trans.redraw = 1;
1571
1572         while (ret_val == 0) {
1573
1574                 getmouseco_areawin(mval);
1575                 
1576                 if (mval[0] != pmval[0] || mval[1] != pmval[1]) {
1577                         Trans.redraw = 1;
1578                 }
1579                 if (Trans.redraw) {
1580                         pmval[0] = mval[0];
1581                         pmval[1] = mval[1];
1582
1583                         selectConstraint(&Trans);
1584                         if (Trans.transform) {
1585                                 Trans.transform(&Trans, mval);
1586                         }
1587                         Trans.redraw = 0;
1588                 }
1589                 
1590                 /* essential for idling subloop */
1591                 if( qtest()==0) PIL_sleep_ms(2);
1592
1593                 while( qtest() ) {
1594                         event= extern_qread(&val);
1595
1596                         if (val) {
1597                                 switch (event){
1598                                 /* enforce redraw of transform when modifiers are used */
1599                                 case LEFTCTRLKEY:
1600                                 case RIGHTCTRLKEY:
1601                                         Trans.redraw = 1;
1602                                         break;
1603                                 case LEFTSHIFTKEY:
1604                                 case RIGHTSHIFTKEY:
1605                                         /* shift is modifier for higher resolution transform, works nice to store this mouse position */
1606                                         getmouseco_areawin(Trans.shiftmval);
1607                                         Trans.flag |= T_SHIFT_MOD;
1608                                         Trans.redraw = 1;
1609                                         break;
1610                                         
1611                                 case MIDDLEMOUSE:
1612                                         if ((Trans.flag & T_NO_CONSTRAINT)==0) {
1613                                                 /* exception for switching to dolly, or trackball, in camera view */
1614                                                 if (Trans.flag & T_CAMERA) {
1615                                                         if (Trans.mode==TFM_TRANSLATION)
1616                                                                 setLocalConstraint(&Trans, (CON_AXIS2), "along local Z");
1617                                                         else if (Trans.mode==TFM_ROTATION) {
1618                                                                 restoreTransObjects(&Trans);
1619                                                                 initTransModeFlags(&Trans, TFM_TRACKBALL);
1620                                                                 initTrackball(&Trans);
1621                                                         }
1622                                                 }
1623                                                 else 
1624                                                         initSelectConstraint(&Trans);
1625                                         }
1626                                         Trans.redraw = 1;
1627                                         break;
1628                                 case ESCKEY:
1629                                 case RIGHTMOUSE:
1630                                         ret_val = TRANS_CANCEL;
1631                                         break;
1632                                 case LEFTMOUSE:
1633                                 case SPACEKEY:
1634                                 case PADENTER:
1635                                 case RETKEY:
1636                                         ret_val = TRANS_CONFIRM;
1637                                         break;
1638                                 case GKEY:
1639                                         restoreTransObjects(&Trans);
1640                                         initTransModeFlags(&Trans, TFM_TRANSLATION);
1641                                         initTranslation(&Trans);
1642                                         Trans.redraw = 1;
1643                                         break;
1644                                 case SKEY:
1645                                         restoreTransObjects(&Trans);
1646                                         initTransModeFlags(&Trans, TFM_RESIZE);
1647                                         initResize(&Trans);
1648                                         Trans.redraw = 1;
1649                                         break;
1650                                 case RKEY:
1651                                         if (Trans.mode == TFM_ROTATION) {
1652                                                 restoreTransObjects(&Trans);
1653                                                 initTransModeFlags(&Trans, TFM_TRACKBALL);
1654                                                 initTrackball(&Trans);
1655                                         }
1656                                         else {
1657                                                 restoreTransObjects(&Trans);
1658                                                 initTransModeFlags(&Trans, TFM_ROTATION);
1659                                                 initRotation(&Trans);
1660                                         }
1661                                         Trans.redraw = 1;
1662                                         break;
1663                                 case XKEY:
1664                                         if ((Trans.flag & T_NO_CONSTRAINT)==0) {
1665                                                 if (cmode == 'X') {
1666                                                         stopConstraint(&Trans);
1667                                                         cmode = '\0';
1668                                                 }
1669                                                 else if(cmode == 'x') {
1670                                                         if (G.qual == 0)
1671                                                                 setLocalConstraint(&Trans, (CON_AXIS0), "along local X");
1672                                                         else if (G.qual == LR_SHIFTKEY)
1673                                                                 setLocalConstraint(&Trans, (CON_AXIS1|CON_AXIS2), "locking local X");
1674
1675                                                         cmode = 'X';
1676                                                 }
1677                                                 else {
1678                                                         if (G.qual == 0)
1679                                                                 setConstraint(&Trans, mati, (CON_AXIS0), "along global X");
1680                                                         else if (G.qual == LR_SHIFTKEY)
1681                                                                 setConstraint(&Trans, mati, (CON_AXIS1|CON_AXIS2), "locking global X");
1682
1683                                                         cmode = 'x';
1684                                                 }
1685                                                 Trans.redraw = 1;
1686                                         }
1687                                         break;
1688                                 case YKEY:
1689                                         if ((Trans.flag & T_NO_CONSTRAINT)==0) {
1690                                                 if (cmode == 'Y') {
1691                                                         stopConstraint(&Trans);
1692                                                         cmode = '\0';
1693                                                 }
1694                                                 else if(cmode == 'y') {
1695                                                         if (G.qual == 0)
1696                                                                 setLocalConstraint(&Trans, (CON_AXIS1), "along global Y");
1697                                                         else if (G.qual == LR_SHIFTKEY)
1698                                                                 setLocalConstraint(&Trans, (CON_AXIS0|CON_AXIS2), "locking global Y");
1699
1700                                                         cmode = 'Y';
1701                                                 }
1702                                                 else {
1703                                                         if (G.qual == 0)
1704                                                                 setConstraint(&Trans, mati, (CON_AXIS1), "along local Y");
1705                                                         else if (G.qual == LR_SHIFTKEY)
1706                                                                 setConstraint(&Trans, mati, (CON_AXIS0|CON_AXIS2), "locking local Y");
1707
1708                                                         cmode = 'y';
1709                                                 }
1710                                                 Trans.redraw = 1;
1711                                         }
1712                                         break;
1713                                 case ZKEY:
1714                                         if ((Trans.flag & T_NO_CONSTRAINT)==0) {
1715                                                 if (cmode == 'Z') {
1716                                                         stopConstraint(&Trans);
1717                                                         cmode = '\0';
1718                                                 }
1719                                                 else if(cmode == 'z') {
1720                                                         if (G.qual == 0)
1721                                                                 setLocalConstraint(&Trans, (CON_AXIS2), "along local Z");
1722                                                         else if (G.qual == LR_SHIFTKEY)
1723                                                                 setLocalConstraint(&Trans, (CON_AXIS0|CON_AXIS1), "locking local Z");
1724
1725                                                         cmode = 'Z';
1726                                                 }
1727                                                 else {
1728                                                         if (G.qual == 0)
1729                                                                 setConstraint(&Trans, mati, (CON_AXIS2), "along global Z");
1730                                                         else if (G.qual == LR_SHIFTKEY)
1731                                                                 setConstraint(&Trans, mati, (CON_AXIS0|CON_AXIS1), "locking global Z");
1732
1733                                                         cmode = 'z';
1734                                                 }
1735                                                 Trans.redraw = 1;
1736                                         }
1737                                         break;
1738                                 case OKEY:
1739                                         if (Trans.flag & T_PROP_EDIT && G.qual==LR_SHIFTKEY) {
1740                                                 extern int prop_mode;
1741                                                 prop_mode = (prop_mode+1)%6;
1742                                                 calculatePropRatio(&Trans);
1743                                                 Trans.redraw= 1;
1744                                         }
1745                                         break;
1746                                 case WHEELDOWNMOUSE:
1747                                 case PADPLUSKEY:
1748                                         if(Trans.flag & T_PROP_EDIT) {
1749                                                 Trans.propsize*= 1.1f;
1750                                                 calculatePropRatio(&Trans);
1751                                                 Trans.redraw= 1;
1752                                         }
1753                                         break;
1754                                 case WHEELUPMOUSE:
1755                                 case PADMINUS:
1756                                         if(Trans.flag & T_PROP_EDIT) {
1757                                                 Trans.propsize*= 0.90909090f;
1758                                                 calculatePropRatio(&Trans);
1759                                                 Trans.redraw= 1;
1760                                         }
1761                                         break;
1762                                 }
1763                                 Trans.redraw |= handleNumInput(&(Trans.num), event);
1764                                 arrows_move_cursor(event);
1765                         }
1766                         else {
1767                                 switch (event){
1768                                 /* no redraw on release modifier keys! this makes sure you can assign the 'grid' still 
1769                                    after releasing modifer key */
1770                                 case MIDDLEMOUSE:
1771                                         if ((Trans.flag & T_NO_CONSTRAINT)==0) {
1772                                                 postSelectConstraint(&Trans);
1773                                                 Trans.redraw = 1;
1774                                         }
1775                                         break;
1776                                 case LEFTMOUSE:
1777                                 case RIGHTMOUSE:
1778                                         /* commented out, doesn't work for actions started with menu */
1779                                         // ret_val = TRANS_CONFIRM;
1780                                         break;
1781                                 case LEFTSHIFTKEY:
1782                                 case RIGHTSHIFTKEY:
1783                                         /* shift is modifier for higher resolution transform */
1784                                         Trans.flag &= ~T_SHIFT_MOD;
1785                                         break;
1786                                 }
1787                         }
1788                 }
1789         }
1790         
1791         
1792         if(ret_val == TRANS_CANCEL) {
1793                 restoreTransObjects(&Trans);
1794         }
1795         else {
1796                 BIF_undo_push("Transform");
1797         }
1798         
1799         /* free data, reset vars */
1800         postTrans(&Trans);
1801         
1802         /* mess from old transform, just for now (ton) */
1803         {
1804                 char cmode='g';
1805                 
1806                 if(mode==TFM_RESIZE) cmode= 's';
1807                 else if(mode==TFM_ROTATION) cmode= 'r';
1808                 /* aftertrans does displists, ipos and action channels */
1809                 /* 7 = keyflags, meaning do loc/rot/scale ipos. Not sure if I like the old method to detect what changed (ton) */
1810                 special_aftertrans_update(cmode, 0, (short)(ret_val == TRANS_CANCEL), 7);
1811                 
1812                 if(G.obedit==NULL && G.obpose==NULL)
1813                         clear_trans_object_base_flags();
1814         }
1815         
1816         /* send events out for redraws */
1817         allqueue(REDRAWVIEW3D, 0);
1818         allqueue(REDRAWBUTSOBJECT, 0);
1819         scrarea_queue_headredraw(curarea);
1820 }
1821
1822 void ManipulatorTransform(int mode) 
1823 {
1824         int ret_val = 0;
1825         short pmval[2] = {0, 0}, mval[2], val;
1826         unsigned short event;
1827
1828
1829         /* stupid PET initialisation code */
1830         /* START */
1831         if (Trans.propsize == 0.0f) {
1832                 Trans.propsize = 1.0;
1833         }
1834         /* END */
1835
1836         Trans.context = CTX_NONE;
1837
1838         initTrans(&Trans);                                      // internal data, mouse, vectors
1839
1840         initTransModeFlags(&Trans, mode);       // modal settings in struct Trans
1841
1842         G.moving |= G_TRANSFORM_MANIP;          // signal to draw manipuls while transform
1843         createTransData(&Trans);                        // make TransData structs from selection
1844
1845         if (Trans.total == 0)
1846                 return;
1847
1848         /* EVIL! posemode code can switch translation to rotate when 1 bone is selected. will be removed (ton) */
1849         /* EVIL2: we gave as argument also texture space context bit... was cleared */
1850         mode= Trans.mode;
1851         
1852         calculatePropRatio(&Trans);
1853         calculateCenter(&Trans);
1854
1855         switch (mode) {
1856         case TFM_TRANSLATION:
1857                 initTranslation(&Trans);
1858                 break;
1859         case TFM_ROTATION:
1860                 initRotation(&Trans);
1861                 break;
1862         case TFM_RESIZE:
1863                 initResize(&Trans);
1864                 break;
1865         case TFM_TRACKBALL:
1866                 initTrackball(&Trans);
1867                 break;
1868         }
1869
1870         initConstraint(&Trans);
1871         
1872         Trans.flag |= T_USES_MANIPULATOR;
1873         Trans.redraw = 1;
1874
1875         while (ret_val == 0) {
1876                 
1877                 getmouseco_areawin(mval);
1878                 
1879                 if (mval[0] != pmval[0] || mval[1] != pmval[1]) {
1880                         Trans.redraw = 1;
1881                 }
1882                 if (Trans.redraw) {
1883                         pmval[0] = mval[0];
1884                         pmval[1] = mval[1];
1885
1886                         //selectConstraint(&Trans);  needed?
1887                         if (Trans.transform) {
1888                                 Trans.transform(&Trans, mval);
1889                         }
1890                         Trans.redraw = 0;
1891                 }
1892                 
1893                 /* essential for idling subloop */
1894                 if( qtest()==0) PIL_sleep_ms(2);
1895
1896                 while( qtest() ) {
1897                         event= extern_qread(&val);
1898
1899                         switch (event){
1900                         /* enforce redraw of transform when modifiers are used */
1901                         case LEFTCTRLKEY:
1902                         case RIGHTCTRLKEY:
1903                                 if(val) Trans.redraw = 1;
1904                                 break;
1905                         case LEFTSHIFTKEY:
1906                         case RIGHTSHIFTKEY:
1907                                 /* shift is modifier for higher resolution transform, works nice to store this mouse position */
1908                                 if(val) {
1909                                         getmouseco_areawin(Trans.shiftmval);
1910                                         Trans.flag |= T_SHIFT_MOD;
1911                                         Trans.redraw = 1;
1912                                 }
1913                                 else Trans.flag &= ~T_SHIFT_MOD; 
1914                                 break;
1915                                 
1916                         case ESCKEY:
1917                         case RIGHTMOUSE:
1918                                 ret_val = TRANS_CANCEL;
1919                                 break;
1920                         case LEFTMOUSE:
1921                         case SPACEKEY:
1922                         case PADENTER:
1923                         case RETKEY:
1924                                 ret_val = TRANS_CONFIRM;
1925                                 break;
1926                         }
1927                         if(val) {
1928                                 switch(event) {
1929                                 case WHEELDOWNMOUSE:
1930                                 case PADPLUSKEY:
1931                                         if(Trans.flag & T_PROP_EDIT) {
1932                                                 Trans.propsize*= 1.1f;
1933                                                 calculatePropRatio(&Trans);
1934                                                 Trans.redraw= 1;
1935                                         }
1936                                         break;
1937                                 case WHEELUPMOUSE:
1938                                 case PADMINUS:
1939                                         if(Trans.flag & T_PROP_EDIT) {
1940                                                 Trans.propsize*= 0.90909090f;
1941                                                 calculatePropRatio(&Trans);
1942                                                 Trans.redraw= 1;
1943                                         }
1944                                         break;
1945                                 }                       
1946                         }
1947                 }
1948         }
1949         
1950         if(ret_val == TRANS_CANCEL) {
1951                 restoreTransObjects(&Trans);
1952         }
1953         else {
1954                 BIF_undo_push("Transform");
1955         }
1956         
1957         /* free data, reset vars */
1958         postTrans(&Trans);
1959         
1960         /* mess from old transform, just for now (ton) */
1961         {
1962                 char cmode='g';
1963                 
1964                 if(mode==TFM_RESIZE) cmode= 's';
1965                 else if(mode==TFM_ROTATION) cmode= 'r';
1966                 /* aftertrans does displists, ipos and action channels */
1967                 /* 7 = keyflags, meaning do loc/rot/scale ipos. Not sure if I like the old method to detect what changed (ton) */
1968                 special_aftertrans_update(cmode, 0, (short)(ret_val == TRANS_CANCEL), 7);
1969                 
1970                 if(G.obedit==NULL && G.obpose==NULL)
1971                         clear_trans_object_base_flags();
1972         }
1973         
1974         /* send events out for redraws */
1975         allqueue(REDRAWVIEW3D, 0);
1976         allqueue(REDRAWBUTSOBJECT, 0);
1977         scrarea_queue_headredraw(curarea);
1978 }
1979
1980
1981
1982 /* ************************** WRAP *************************** */
1983
1984 /* warp is done fully in view space */
1985 void initWarp(TransInfo *t) 
1986 {
1987         float max[3], min[3];
1988         int i;
1989         
1990         calculateCenterCursor(t);
1991         t->idx_max = 0;
1992         t->num.idx_max = 0;
1993         t->transform = Warp;
1994         t->snap[0] = 0.0f;
1995         t->snap[1] = 5.0f;
1996         t->snap[2] = 1.0f;
1997         
1998         t->fac = (float)(t->center2d[0] - t->imval[0]);
1999         
2000         /* we need min/max in view space */
2001         for(i = 0; i < t->total; i++) {
2002                 float center[3];
2003                 VECCOPY(center, t->data[i].center);
2004                 Mat3MulVecfl(t->data[i].mtx, center);
2005                 Mat4MulVecfl(G.vd->viewmat, center);
2006                 VecSubf(center, center, G.vd->viewmat[3]);
2007                 if (i)
2008                         MinMax3(min, max, center);
2009                 else {
2010                         VECCOPY(max, center);
2011                         VECCOPY(min, center);
2012                 }
2013         }
2014
2015         t->center[0]= (min[0]+max[0])/2.0f;
2016         t->center[1]= (min[1]+max[1])/2.0f;
2017         t->center[2]= (min[2]+max[2])/2.0f;
2018         
2019         t->val= (max[0]-min[0])/2.0f;   // t->val is free variable
2020 }
2021
2022
2023 int Warp(TransInfo *t, short mval[2])
2024 {
2025         TransData *td = t->data;
2026         float vec[3], circumfac, dist, phi0, co, si, *curs, cursor[3], gcursor[3];
2027         int i;
2028         char str[50];
2029         
2030         curs= give_cursor();
2031         /*
2032          * gcursor is the one used for helpline.
2033          * It has to be in the same space as the drawing loop
2034          * (that means it needs to be in the object's space when in edit mode and
2035          *  in global space in object mode)
2036          *
2037          * cursor is used for calculations.
2038          * It needs to be in view space, but we need to take object's offset
2039          * into account if in Edit mode.
2040          */
2041         VECCOPY(cursor, curs);
2042         VECCOPY(gcursor, cursor);       
2043         if (t->flag & T_EDIT) {
2044                 VecSubf(cursor, cursor, G.obedit->obmat[3]);
2045                 VecSubf(gcursor, gcursor, G.obedit->obmat[3]);
2046                 Mat3MulVecfl(t->data->smtx, gcursor);
2047         }
2048         Mat4MulVecfl(G.vd->viewmat, cursor);
2049         VecSubf(cursor, cursor, G.vd->viewmat[3]);
2050
2051         // amount of degrees for warp, 450 = allow to create 360 degree warp
2052         circumfac= 450.0f*(mval[1] - t->imval[1]) / (float)(curarea->winy);
2053         circumfac+= 90.0f;
2054
2055         snapGrid(t, &circumfac);
2056         applyNumInput(&t->num, &circumfac);
2057         
2058         /* header print for NumInput */
2059         if (hasNumInput(&t->num)) {
2060                 char c[20];
2061                 
2062                 outputNumInput(&(t->num), c);
2063                 
2064                 sprintf(str, "Warp: %s", c);
2065         }
2066         else {
2067                 /* default header print */
2068                 sprintf(str, "Warp: %.3f", circumfac);
2069         }
2070         
2071         circumfac*= (float)(-M_PI/360.0);
2072         
2073         for(i = 0 ; i < t->total; i++, td++) {
2074                 float loc[3];
2075                 if (td->flag & TD_NOACTION)
2076                         break;
2077
2078                 /* translate point to centre, rotate in such a way that outline==distance */
2079                 
2080                 VECCOPY(vec, td->iloc);
2081                 Mat3MulVecfl(td->mtx, vec);
2082                 Mat4MulVecfl(G.vd->viewmat, vec);
2083                 VecSubf(vec, vec, G.vd->viewmat[3]);
2084                 
2085                 dist= vec[0]-cursor[0];
2086
2087                 phi0= (circumfac*dist/t->val);  // t->val is X dimension projected boundbox
2088                 
2089                 vec[1]= (vec[1]-cursor[1]);
2090                 
2091                 co= (float)cos(phi0);
2092                 si= (float)sin(phi0);
2093                 loc[0]= -si*vec[1]+cursor[0];
2094                 loc[1]= co*vec[1]+cursor[1];
2095                 loc[2]= vec[2];
2096                 
2097                 Mat4MulVecfl(G.vd->viewinv, loc);
2098                 VecSubf(loc, loc, G.vd->viewinv[3]);
2099                 Mat3MulVecfl(td->smtx, loc);
2100
2101                 VecSubf(loc, loc, td->iloc);
2102                 VecMulf(loc, td->factor);
2103                 VecAddf(td->loc, td->iloc, loc);
2104         }
2105
2106         recalcData(t);
2107         
2108         headerprint(str);
2109         
2110         force_draw(0);
2111         
2112         helpline(gcursor);
2113         
2114         return 1;
2115 }
2116
2117 /* ************************** SHEAR *************************** */
2118
2119 void initShear(TransInfo *t) 
2120 {
2121         t->idx_max = 0;
2122         t->num.idx_max = 0;
2123         t->snap[0] = 0.0f;
2124         t->snap[1] = 0.1f;
2125         t->snap[2] = t->snap[1] * 0.1f;
2126         t->transform = Shear;
2127         t->fac = (float)(t->center2d[0] - t->imval[0]);
2128 }
2129
2130 int Shear(TransInfo *t, short mval[2]) 
2131 {
2132         TransData *td = t->data;
2133         float vec[3];
2134         float smat[3][3], tmat[3][3], totmat[3][3], persmat[3][3], persinv[3][3];
2135         float value;
2136         int i;
2137         char str[50];
2138
2139         Mat3CpyMat4(persmat, G.vd->viewmat);
2140         Mat3Inv(persinv, persmat);
2141
2142         value = -0.005f * ((float)(t->center2d[0] - mval[0]) - t->fac);
2143
2144         snapGrid(t, &value);
2145
2146         applyNumInput(&t->num, &value);
2147
2148         /* header print for NumInput */
2149         if (hasNumInput(&t->num)) {
2150                 char c[20];
2151
2152                 outputNumInput(&(t->num), c);
2153
2154                 sprintf(str, "Shear: %s %s", c, t->proptext);
2155         }
2156         else {
2157                 /* default header print */
2158                 sprintf(str, "Shear: %.3f %s", value, t->proptext);
2159         }
2160         
2161         Mat3One(smat);
2162         smat[1][0] = value;
2163         Mat3MulMat3(tmat, smat, persmat);
2164         Mat3MulMat3(totmat, persinv, tmat);
2165         
2166         for(i = 0 ; i < t->total; i++, td++) {
2167                 if (td->flag & TD_NOACTION)
2168                         break;
2169
2170                 if (G.obedit) {
2171                         float mat3[3][3];
2172                         Mat3MulMat3(mat3, totmat, td->mtx);
2173                         Mat3MulMat3(tmat, td->smtx, mat3);
2174                 }
2175                 else {
2176                         Mat3CpyMat3(tmat, totmat);
2177                 }
2178                 VecSubf(vec, td->center, t->center);
2179
2180                 Mat3MulVecfl(tmat, vec);
2181
2182                 VecAddf(vec, vec, t->center);
2183                 VecSubf(vec, vec, td->center);
2184
2185                 VecMulf(vec, td->factor);
2186
2187                 VecAddf(td->loc, td->iloc, vec);
2188         }
2189
2190         recalcData(t);
2191
2192         headerprint(str);
2193
2194         force_draw(0);
2195
2196         helpline (t->center);
2197
2198         return 1;
2199 }
2200
2201 /* ************************** RESIZE *************************** */
2202
2203 void initResize(TransInfo *t) 
2204 {
2205         t->fac = (float)sqrt( (float)
2206                 (
2207                         (t->center2d[1] - t->imval[1])*(t->center2d[1] - t->imval[1])
2208                 +
2209                         (t->center2d[0] - t->imval[0])*(t->center2d[0] - t->imval[0])
2210                 ) );
2211
2212         if(t->fac==0.0f) t->fac= 1.0f;  // prevent Inf
2213         
2214         t->idx_max = 2;
2215         t->num.idx_max = 2;
2216         t->snap[0] = 0.0f;
2217         t->snap[1] = 0.1f;
2218         t->snap[2] = t->snap[1] * 0.1f;
2219         t->transform = Resize;
2220 }
2221
2222 static void headerResize(TransInfo *t, float vec[3], char *str) {
2223         char tvec[60];
2224         if (hasNumInput(&t->num)) {
2225                 outputNumInput(&(t->num), tvec);
2226         }
2227         else {
2228                 sprintf(&tvec[0], "%.4f", vec[0]);
2229                 sprintf(&tvec[20], "%.4f", vec[1]);
2230                 sprintf(&tvec[40], "%.4f", vec[2]);
2231         }
2232
2233         if (t->con.mode & CON_APPLY) {
2234                 switch(t->num.idx_max) {
2235                 case 0:
2236                         sprintf(str, "Size: %s%s %s", &tvec[0], t->con.text, t->proptext);
2237                         break;
2238                 case 1:
2239                         sprintf(str, "Size: %s : %s%s %s", &tvec[0], &tvec[20], t->con.text, t->proptext);
2240                         break;
2241                 case 2:
2242                         sprintf(str, "Size: %s : %s : %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext);
2243                 }
2244         }
2245         else {
2246                 sprintf(str, "Size X: %s   Y: %s  Z: %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext);
2247         }
2248 }
2249
2250 int Resize(TransInfo *t, short mval[2]) 
2251 {
2252         TransData *td = t->data;
2253         float vec[3];
2254         float size[3], mat[3][3], tmat[3][3];
2255         float ratio;
2256         int i;
2257         char str[50];
2258
2259         /* for manipulator, center handle, the scaling can't be done relative to center */
2260         if( (t->flag & T_USES_MANIPULATOR) && t->con.mode==0) {
2261                 ratio = 1.0f - ((t->imval[0] - mval[0]) + (t->imval[1] - mval[1]))/100.0f;
2262         }
2263         else {
2264                 
2265                 if(t->flag & T_SHIFT_MOD) {
2266                         /* calculate ratio for shiftkey pos, and for total, and blend these for precision */
2267                         float dx= (float)(t->center2d[0] - t->shiftmval[0]);
2268                         float dy= (float)(t->center2d[1] - t->shiftmval[1]);
2269                         ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
2270                         
2271                         dx= (float)(t->center2d[0] - mval[0]);
2272                         dy= (float)(t->center2d[1] - mval[1]);
2273                         ratio+= 0.1f*(float)(sqrt( dx*dx + dy*dy)/t->fac -ratio);
2274                         
2275                 }
2276                 else {
2277                         float dx= (float)(t->center2d[0] - mval[0]);
2278                         float dy= (float)(t->center2d[1] - mval[1]);
2279                         ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
2280                 }
2281                 
2282                 /* flip scale, but not for manipulator center handle */
2283                 if      ((t->center2d[0] - mval[0]) * (t->center2d[0] - t->imval[0]) + 
2284                          (t->center2d[1] - mval[1]) * (t->center2d[1] - t->imval[1]) < 0)
2285                                 ratio *= -1.0f;
2286         }
2287         
2288         size[0] = size[1] = size[2] = ratio;
2289
2290         snapGrid(t, size);
2291
2292         if (hasNumInput(&t->num)) {
2293                 applyNumInput(&t->num, size);
2294                 constraintNumInput(t, size);
2295         }
2296
2297         SizeToMat3(size, mat);
2298
2299         if (t->con.applySize) {
2300                 t->con.applySize(t, NULL, mat);
2301         }
2302
2303         Mat3CpyMat3(t->mat, mat);       // used in manipulator
2304         
2305         headerResize(t, size, str);
2306
2307         for(i = 0 ; i < t->total; i++, td++) {
2308                 float smat[3][3];
2309                 if (td->flag & TD_NOACTION)
2310                         break;
2311
2312
2313                 if (t->flag & T_EDIT) {
2314                         Mat3MulMat3(smat, mat, td->mtx);
2315                         Mat3MulMat3(tmat, td->smtx, smat);
2316                 }
2317                 else {
2318                         Mat3CpyMat3(tmat, mat);
2319                 }
2320
2321                 if (t->con.applySize) {
2322                         t->con.applySize(t, td, tmat);
2323                 }
2324
2325                 if (G.vd->around == V3D_LOCAL) {
2326                         VECCOPY(t->center, td->center);
2327                 }
2328
2329                 if (td->ext) {
2330                         float fsize[3];
2331
2332                         if (t->flag & T_OBJECT) {
2333                                 float obsizemat[3][3];
2334                                 // Reorient the size mat to fit the oriented object.
2335                                 Mat3MulMat3(obsizemat, tmat, td->axismtx);
2336                                 Mat3ToSize(obsizemat, fsize);
2337                         }
2338                         else {
2339                                 Mat3ToSize(tmat, fsize);
2340                         }
2341                         
2342                         if ((G.vd->flag & V3D_ALIGN)==0) {      // align mode doesn't rotate objects itself
2343                                 /* handle ipokeys? */
2344                                 if(td->tdi) {
2345                                         TransDataIpokey *tdi= td->tdi;
2346                                         /* calculate delta size (equal for size and dsize) */
2347                                         
2348                                         vec[0]= (tdi->oldsize[0])*(fsize[0] -1.0f) * td->factor;
2349                                         vec[1]= (tdi->oldsize[1])*(fsize[1] -1.0f) * td->factor;
2350                                         vec[2]= (tdi->oldsize[2])*(fsize[2] -1.0f) * td->factor;
2351                                         
2352                                         add_tdi_poin(tdi->sizex, tdi->oldsize,   vec[0]);
2353                                         add_tdi_poin(tdi->sizey, tdi->oldsize+1, vec[1]);
2354                                         add_tdi_poin(tdi->sizez, tdi->oldsize+2, vec[2]);
2355                                         
2356                                 }
2357                                 else {
2358                                         td->ext->size[0] = td->ext->isize[0] * (fsize[0]) * td->factor;
2359                                         td->ext->size[1] = td->ext->isize[1] * (fsize[1]) * td->factor;
2360                                         td->ext->size[2] = td->ext->isize[2] * (fsize[2]) * td->factor;
2361                                 }
2362                         }
2363                 }
2364                 VecSubf(vec, td->center, t->center);
2365
2366                 Mat3MulVecfl(tmat, vec);
2367
2368                 VecAddf(vec, vec, t->center);
2369                 VecSubf(vec, vec, td->center);
2370
2371                 VecMulf(vec, td->factor);
2372
2373                 if (t->flag & T_OBJECT) {
2374                         Mat3MulVecfl(td->smtx, vec);
2375                 }
2376
2377                 VecAddf(td->loc, td->iloc, vec);
2378         }
2379
2380         recalcData(t);
2381
2382         headerprint(str);
2383
2384         force_draw(0);
2385
2386         if(!(t->flag & T_USES_MANIPULATOR)) helpline (t->center);
2387
2388         return 1;
2389 }
2390
2391 /* ************************** TOSPHERE *************************** */
2392
2393 void initToSphere(TransInfo *t) 
2394 {
2395         TransData *td = t->data;
2396         int i;
2397
2398         // Calculate average radius
2399         for(i = 0 ; i < t->total; i++, td++) {
2400                 t->val += VecLenf(t->center, td->iloc);
2401         }
2402
2403         t->val /= (float)t->total;
2404
2405         Trans.fac = (float)sqrt( (float)
2406                 (
2407                         (Trans.center2d[1] - Trans.imval[1])*(Trans.center2d[1] - Trans.imval[1])
2408                 +
2409                         (Trans.center2d[0] - Trans.imval[0])*(Trans.center2d[0] - Trans.imval[0])
2410                 ) );
2411
2412         t->idx_max = 0;
2413         t->num.idx_max = 0;
2414         t->snap[0] = 0.0f;
2415         t->snap[1] = 0.1f;
2416         t->snap[2] = t->snap[1] * 0.1f;
2417         t->transform = ToSphere;
2418 }
2419
2420
2421
2422 int ToSphere(TransInfo *t, short mval[2]) 
2423 {
2424         float vec[3];
2425         float ratio, radius;
2426         int i;
2427         char str[50];
2428         TransData *td = t->data;
2429
2430         ratio = (float)sqrt( (float)
2431                 (
2432                         (t->center2d[1] - mval[1])*(t->center2d[1] - mval[1])
2433                 +
2434                         (t->center2d[0] - mval[0])*(t->center2d[0] - mval[0])
2435                 ) ) / t->fac;
2436
2437         snapGrid(t, &ratio);
2438
2439         applyNumInput(&t->num, &ratio);
2440
2441         if (ratio > 1.0f)
2442                 ratio = 1.0f;
2443
2444         /* header print for NumInput */
2445         if (hasNumInput(&t->num)) {
2446                 char c[20];
2447
2448                 outputNumInput(&(t->num), c);
2449
2450                 sprintf(str, "To Sphere: %s %s", c, t->proptext);
2451         }
2452         else {
2453                 /* default header print */
2454                 sprintf(str, "To Sphere: %.4f %s", ratio, t->proptext);
2455         }
2456         
2457         
2458         for(i = 0 ; i < t->total; i++, td++) {
2459                 float tratio;
2460                 if (td->flag & TD_NOACTION)
2461                         break;
2462
2463                 VecSubf(vec, td->iloc, t->center);
2464
2465                 radius = Normalise(vec);
2466
2467                 tratio = 1.0f - ((1.0f - ratio) * td->factor);
2468
2469                 VecMulf(vec, radius * tratio + t->val * (1.0f - tratio));
2470
2471                 VecAddf(td->loc, t->center, vec);
2472         }
2473
2474         recalcData(t);
2475
2476         headerprint(str);
2477
2478         force_draw(0);
2479
2480         helpline (t->center);
2481
2482         return 1;
2483 }
2484
2485 /* ************************** ROTATION *************************** */
2486
2487
2488 void initRotation(TransInfo *t) 
2489 {
2490         t->idx_max = 0;
2491         t->num.idx_max = 0;
2492         t->snap[0] = 0.0f;
2493         t->snap[1] = (float)((5.0/180)*M_PI);
2494         t->snap[2] = t->snap[1] * 0.2f;
2495         t->fac = 0;
2496         t->transform = Rotation;
2497 }
2498
2499 static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3]) {
2500         float vec[3], totmat[3][3], smat[3][3];
2501         float eul[3], fmat[3][3], quat[4];
2502
2503         if (t->flag & T_EDIT) {
2504                 Mat3MulMat3(totmat, mat, td->mtx);
2505                 Mat3MulMat3(smat, td->smtx, totmat);
2506                 
2507                 VecSubf(vec, td->iloc, t->center);
2508                 Mat3MulVecfl(smat, vec);
2509                 
2510                 VecAddf(td->loc, vec, t->center);
2511
2512                 if(td->flag & TD_USEQUAT) {
2513                         Mat3MulSerie(fmat, td->mtx, mat, td->smtx, 0, 0, 0, 0, 0);
2514                         Mat3ToQuat(fmat, quat); // Actual transform
2515                         QuatMul(td->ext->quat, quat, td->ext->iquat);
2516                 }
2517         }
2518         else {
2519                 /* translation */
2520                 VecSubf(vec, td->center, t->center);
2521                 Mat3MulVecfl(mat, vec);
2522                 VecAddf(vec, vec, t->center);
2523                 /* vec now is the location where the object has to be */
2524                 VecSubf(vec, vec, td->center);
2525                 Mat3MulVecfl(td->smtx, vec);
2526                 
2527                 VecAddf(td->loc, td->iloc, vec);
2528                 
2529                 if(td->flag & TD_USEQUAT) {
2530                         Mat3MulSerie(fmat, td->mtx, mat, td->smtx, 0, 0, 0, 0, 0);
2531                         Mat3ToQuat(fmat, quat); // Actual transform
2532                         QuatMul(td->ext->quat, quat, td->ext->iquat);
2533                 }
2534                 else if ((G.vd->flag & V3D_ALIGN)==0) { // align mode doesn't rotate objects itself
2535                         float obmat[3][3];
2536                         
2537                         /* are there ipo keys? */
2538                         if(td->tdi) {
2539                                 TransDataIpokey *tdi= td->tdi;
2540                                 float rot[3];
2541                                 
2542                                 /* calculate the total rotatation in eulers */
2543                                 VecAddf(eul, td->ext->irot, td->ext->drot);
2544                                 EulToMat3(eul, obmat);
2545                                 /* mat = transform, obmat = object rotation */
2546                                 Mat3MulMat3(fmat, mat, obmat);
2547                                 Mat3ToEul(fmat, eul);
2548                                 compatible_eul(eul, td->ext->irot);
2549                                 
2550                                 /* correct back for delta rot */
2551                                 if(tdi->flag & TOB_IPODROT) {
2552                                         VecSubf(rot, eul, td->ext->irot);
2553                                 }
2554                                 else {
2555                                         VecSubf(rot, eul, td->ext->drot);
2556                                 }
2557                                 
2558                                 VecMulf(rot, (float)(9.0/M_PI_2));
2559                                 VecSubf(rot, rot, tdi->oldrot);
2560                                 
2561                                 add_tdi_poin(tdi->rotx, tdi->oldrot, rot[0]);
2562                                 add_tdi_poin(tdi->roty, tdi->oldrot+1, rot[1]);
2563                                 add_tdi_poin(tdi->rotz, tdi->oldrot+2, rot[2]);
2564                         }
2565                         else {
2566                                 
2567                                 /* calculate the total rotatation in eulers */
2568                                 VecAddf(eul, td->ext->irot, td->ext->drot); /* we have to correct for delta rot */
2569                                 EulToMat3(eul, obmat);
2570                                 /* mat = transform, obmat = object rotation */
2571                                 Mat3MulMat3(fmat, mat, obmat);
2572                                 Mat3ToEul(fmat, eul);
2573                                 compatible_eul(eul, td->ext->irot);
2574                                 
2575                                 /* correct back for delta rot */
2576                                 VecSubf(eul, eul, td->ext->drot);
2577                                 /* and apply */
2578                                 VECCOPY(td->ext->rot, eul);
2579                         }
2580                 }
2581         }
2582 }
2583
2584 static void applyRotation(TransInfo *t, float angle, float axis[3]) 
2585 {
2586         TransData *td = t->data;
2587         float mat[3][3];
2588         int i;
2589
2590         VecRotToMat3(axis, angle, mat);
2591
2592         for(i = 0 ; i < t->total; i++, td++) {
2593                 if (td->flag & TD_NOACTION)
2594                         break;
2595                 
2596                 if (G.vd->around == V3D_LOCAL) {
2597                         VECCOPY(t->center, td->center);
2598                 }
2599                 
2600                 if (t->con.applyRot) {
2601                         t->con.applyRot(t, td, axis);
2602                         VecRotToMat3(axis, angle * td->factor, mat);
2603                 }
2604                 else if (t->flag & T_PROP_EDIT) {
2605                         VecRotToMat3(axis, angle * td->factor, mat);
2606                 }
2607
2608                 ElementRotation(t, td, mat);
2609         }
2610 }
2611
2612 int Rotation(TransInfo *t, short mval[2]) 
2613 {
2614         TransData *td = t->data;
2615         char str[50];
2616
2617         float final;
2618
2619         int dx2 = t->center2d[0] - mval[0];
2620         int dy2 = t->center2d[1] - mval[1];
2621         float B = (float)sqrt(dx2*dx2+dy2*dy2);
2622
2623         int dx1 = t->center2d[0] - t->imval[0];
2624         int dy1 = t->center2d[1] - t->imval[1];
2625         float A = (float)sqrt(dx1*dx1+dy1*dy1);
2626
2627         int dx3 = mval[0] - t->imval[0];
2628         int dy3 = mval[1] - t->imval[1];
2629
2630         float deler= ((dx1*dx1+dy1*dy1)+(dx2*dx2+dy2*dy2)-(dx3*dx3+dy3*dy3))
2631                 / (2 * (A*B?A*B:1.0f));
2632         /* (A*B?A*B:1.0f) this takes care of potential divide by zero errors */
2633
2634         float dphi;
2635
2636         float axis[3];
2637         float mat[3][3];
2638
2639         VECCOPY(axis, t->persinv[2]);
2640         Normalise(axis);
2641
2642         dphi = saacos(deler);
2643         if( (dx1*dy2-dx2*dy1)>0.0 ) dphi= -dphi;
2644
2645         if(G.qual & LR_SHIFTKEY) t->fac += dphi/30.0f;
2646         else t->fac += dphi;
2647
2648         /*
2649         clamping angle between -2 PI and 2 PI (not sure if useful so commented out - theeth)
2650         if (t->fac >= 2 * M_PI)
2651                 t->fac -= 2 * M_PI;
2652         else if (t->fac <= -2 * M_PI)
2653                 t->fac -= -2 * M_PI;
2654         */
2655
2656         final = t->fac;
2657
2658         snapGrid(t, &final);
2659
2660         t->imval[0] = mval[0];
2661         t->imval[1] = mval[1];
2662
2663         if (t->con.applyRot) {
2664                 t->con.applyRot(t, NULL, axis);
2665         }
2666
2667         if (hasNumInput(&t->num)) {
2668                 char c[20];
2669
2670                 applyNumInput(&t->num, &final);
2671
2672                 outputNumInput(&(t->num), c);
2673
2674                 sprintf(str, "Rot: %s %s", &c[0], t->proptext);
2675
2676                 final *= (float)(M_PI / 180.0);
2677         }
2678         else {
2679                 sprintf(str, "Rot: %.2f %s", 180.0*final/M_PI, t->proptext);
2680         }
2681
2682         VecRotToMat3(axis, final * td->factor, mat);
2683
2684         t->val = final;                         // used in manipulator
2685         Mat3CpyMat3(t->mat, mat);       // used in manipulator
2686         
2687         applyRotation(t, final, axis);
2688         
2689         recalcData(t);
2690
2691         headerprint(str);
2692
2693         force_draw(0);
2694
2695         if(!(t->flag & T_USES_MANIPULATOR)) helpline (t->center);
2696
2697         return 1;
2698 }
2699
2700
2701 /* ************************** TRACKBALL *************************** */
2702
2703 void initTrackball(TransInfo *t) 
2704 {
2705         t->idx_max = 1;
2706         t->num.idx_max = 1;
2707         t->snap[0] = 0.0f;
2708         t->snap[1] = (float)((5.0/180)*M_PI);
2709         t->snap[2] = t->snap[1] * 0.2f;
2710         t->fac = 0;
2711         t->transform = Trackball;
2712 }
2713
2714 static void applyTrackball(TransInfo *t, float axis1[3], float axis2[3], float angles[2])
2715 {
2716         TransData *td = t->data;
2717         float mat[3][3], smat[3][3], totmat[3][3];
2718         int i;
2719
2720         VecRotToMat3(axis1, angles[0], smat);
2721         VecRotToMat3(axis2, angles[1], totmat);
2722         
2723         Mat3MulMat3(mat, smat, totmat);
2724
2725         for(i = 0 ; i < t->total; i++, td++) {
2726                 if (td->flag & TD_NOACTION)
2727                         break;
2728                 
2729                 if (G.vd->around == V3D_LOCAL) {
2730                         VECCOPY(t->center, td->center);
2731                 }
2732                 
2733                 if (t->flag & T_PROP_EDIT) {
2734                         VecRotToMat3(axis1, td->factor * angles[0], smat);
2735                         VecRotToMat3(axis2, td->factor * angles[1], totmat);
2736                         
2737                         Mat3MulMat3(mat, smat, totmat);
2738                 }
2739
2740                 ElementRotation(t, td, mat);
2741         }
2742 }
2743
2744 int Trackball(TransInfo *t, short mval[2]) 
2745 {
2746         char str[80];
2747         float axis1[3], axis2[3];
2748         float mat[3][3], totmat[3][3], smat[3][3];
2749         float phi[2];
2750         
2751         VECCOPY(axis1, t->persinv[0]);
2752         VECCOPY(axis2, t->persinv[1]);
2753         Normalise(axis1);
2754         Normalise(axis2);
2755         
2756         /* factore has to become setting or so */
2757         phi[0]= 0.01f*(float)( t->imval[1] - mval[1] );
2758         phi[1]= 0.01f*(float)( mval[0] - t->imval[0] );
2759         
2760         //if(G.qual & LR_SHIFTKEY) t->fac += dphi/30.0f;
2761         //else t->fac += dphi;
2762         
2763         snapGrid(t, phi);
2764         
2765         if (hasNumInput(&t->num)) {
2766                 char c[40];
2767                 
2768                 applyNumInput(&t->num, phi);
2769                 
2770                 outputNumInput(&(t->num), c);
2771                 
2772                 sprintf(str, "Trackball: %s %s %s", &c[0], &c[20], t->proptext);
2773                 
2774                 phi[0] *= (float)(M_PI / 180.0);
2775                 phi[1] *= (float)(M_PI / 180.0);
2776         }
2777         else {
2778                 sprintf(str, "Trackball: %.2f %.2f %s", 180.0*phi[0]/M_PI, 180.0*phi[1]/M_PI, t->proptext);
2779         }
2780         
2781         VecRotToMat3(axis1, phi[0], smat);
2782         VecRotToMat3(axis2, phi[1], totmat);
2783         
2784         Mat3MulMat3(mat, smat, totmat);
2785         
2786         Mat3CpyMat3(t->mat, mat);       // used in manipulator
2787         
2788         applyTrackball(t, axis1, axis2, phi);
2789         
2790         recalcData(t);
2791         
2792         headerprint(str);
2793         
2794         force_draw(0);
2795         
2796         if(!(t->flag & T_USES_MANIPULATOR)) helpline (t->center);
2797         
2798         return 1;
2799 }
2800
2801 /* ************************** TRANSLATION *************************** */
2802         
2803 void initTranslation(TransInfo *t) 
2804 {
2805         t->idx_max = 2;
2806         t->num.idx_max = 2;
2807         t->snap[0] = 0.0f;
2808         t->snap[1] = G.vd->gridview * 1.0f;
2809         t->snap[2] = t->snap[1] * 0.1f;
2810         t->transform = Translation;
2811         
2812         /* initgrabz() defines a factor for perspective depth correction, used in window_to_3d() */
2813         if (G.obedit) {
2814                 float vec[3];
2815                 
2816                 VECCOPY(vec, t->center);
2817                 Mat4MulVecfl(G.obedit->obmat, vec);
2818                 initgrabz(vec[0], vec[1], vec[2]);
2819         }
2820         else initgrabz(t->center[0], t->center[1], t->center[2]); 
2821 }
2822
2823 static void headerTranslation(TransInfo *t, float vec[3], char *str) {
2824         char tvec[60];
2825         if (hasNumInput(&t->num)) {
2826                 outputNumInput(&(t->num), tvec);
2827         }
2828         else {
2829                 sprintf(&tvec[0], "%.4f", vec[0]);
2830                 sprintf(&tvec[20], "%.4f", vec[1]);
2831                 sprintf(&tvec[40], "%.4f", vec[2]);
2832         }
2833
2834         if (t->con.mode & CON_APPLY) {
2835                 switch(t->num.idx_max) {
2836                 case 0:
2837                         sprintf(str, "D: %s%s %s", &tvec[0], t->con.text, t->proptext);
2838                         break;
2839                 case 1:
2840                         sprintf(str, "D: %s   D: %s%s %s", &tvec[0], &tvec[20], t->con.text, t->proptext);
2841                         break;
2842                 case 2:
2843                         sprintf(str, "D: %s   D: %s  D: %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext);
2844                 }
2845         }
2846         else {
2847                 sprintf(str, "Dx: %s   Dy: %s  Dz: %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext);
2848         }
2849 }
2850
2851 static void applyTranslation(TransInfo *t, float vec[3]) {
2852         TransData *td = t->data;
2853         float tvec[3];
2854         int i;
2855
2856         for(i = 0 ; i < t->total; i++, td++) {
2857                 if (td->flag & TD_NOACTION)
2858                         break;
2859
2860                 if (t->con.applyVec) {
2861                         float pvec[3];
2862                         t->con.applyVec(t, td, vec, tvec, pvec);
2863                 }
2864                 else {
2865                         VECCOPY(tvec, vec);
2866                 }
2867
2868                 Mat3MulVecfl(td->smtx, tvec);
2869                 VecMulf(tvec, td->factor);
2870                 
2871                 /* transdata ipokey */
2872                 if(td->tdi) {
2873                         TransDataIpokey *tdi= td->tdi;
2874                         add_tdi_poin(tdi->locx, tdi->oldloc, tvec[0]);
2875                         add_tdi_poin(tdi->locy, tdi->oldloc+1, tvec[1]);
2876                         add_tdi_poin(tdi->locz, tdi->oldloc+2, tvec[2]);
2877                 }
2878                 else VecAddf(td->loc, td->iloc, tvec);
2879         }
2880 }
2881
2882 /* uses t->vec to store actual translation in */
2883 int Translation(TransInfo *t, short mval[2]) 
2884 {
2885         float tvec[3];
2886         char str[200];
2887         
2888         if(t->flag & T_SHIFT_MOD) {
2889                 float dvec[3];
2890                 /* calculate the main translation and the precise one separate */
2891                 window_to_3d(dvec, (short)(mval[0] - t->shiftmval[0]), (short)(mval[1] - t->shiftmval[1]));
2892                 VecMulf(dvec, 0.1f);
2893                 window_to_3d(t->vec, (short)(t->shiftmval[0] - t->imval[0]), (short)(t->shiftmval[1] - t->imval[1]));
2894                 VecAddf(t->vec, t->vec, dvec);
2895         }
2896         else window_to_3d(t->vec, (short)(mval[0] - t->imval[0]), (short)(mval[1] - t->imval[1]));
2897
2898         if (t->con.mode & CON_APPLY) {
2899                 float pvec[3] = {0.0f, 0.0f, 0.0f};
2900                 t->con.applyVec(t, NULL, t->vec, tvec, pvec);
2901                 VECCOPY(t->vec, tvec);
2902                 headerTranslation(t, pvec, str);
2903         }
2904         else {
2905                 snapGrid(t, t->vec);
2906                 applyNumInput(&t->num, t->vec);
2907                 headerTranslation(t, t->vec, str);
2908         }
2909
2910         applyTranslation(t, t->vec);
2911
2912         recalcData(t);
2913
2914         headerprint(str);
2915
2916         force_draw(0);
2917
2918         return 1;
2919 }
2920
2921 /* ************************** SHRINK/FATTEN *************************** */
2922
2923 void initShrinkFatten(TransInfo *t) 
2924 {
2925         if (G.obedit==NULL || G.obedit->type != OB_MESH) {
2926                 initTransModeFlags(t, TFM_RESIZE);
2927                 initResize(t);
2928                 return;
2929         }
2930
2931         t->idx_max = 0;
2932         t->num.idx_max = 0;
2933         t->snap[0] = 0.0f;
2934         t->snap[1] = 1.0f;
2935         t->snap[2] = t->snap[1] * 0.1f;
2936         t->transform = ShrinkFatten;
2937 }
2938
2939
2940
2941 int ShrinkFatten(TransInfo *t, short mval[2]) 
2942 {
2943         float vec[3];
2944         float ratio;
2945         int i;
2946         char str[50];
2947         TransData *td = t->data;
2948
2949         window_to_3d(t->vec, (short)(mval[0] - t->imval[0]), (short)(mval[1] - t->imval[1]));
2950         Projf(vec, t->vec, G.vd->viewinv[1]);
2951         ratio = Normalise(vec);
2952
2953         if (mval[1] < t->imval[1])
2954                 ratio *= -1;
2955
2956         snapGrid(t, &ratio);
2957
2958         applyNumInput(&t->num, &ratio);
2959
2960         /* header print for NumInput */
2961         if (hasNumInput(&t->num)) {
2962                 char c[20];
2963
2964                 outputNumInput(&(t->num), c);
2965
2966                 sprintf(str, "Shrink/Fatten: %s %s", c, t->proptext);
2967         }
2968         else {
2969                 /* default header print */
2970                 sprintf(str, "Shrink/Fatten: %.4f %s", ratio, t->proptext);
2971         }
2972         
2973         
2974         for(i = 0 ; i < t->total; i++, td++) {
2975                 if (td->flag & TD_NOACTION)
2976                         break;
2977
2978                 VECCOPY(vec, td->axismtx[2]);
2979                 VecMulf(vec, ratio);
2980                 VecMulf(vec, td->factor);
2981
2982                 VecAddf(td->loc, td->iloc, vec);
2983         }
2984
2985         recalcData(t);
2986
2987         headerprint(str);
2988
2989         force_draw(0);
2990
2991         return 1;
2992 }
2993
2994 /* ************************** TILT *************************** */
2995
2996 void initTilt(TransInfo *t) 
2997 {
2998         t->idx_max = 0;
2999         t->num.idx_max = 0;
3000         t->snap[0] = 0.0f;
3001         t->snap[1] = (float)((5.0/180)*M_PI);
3002         t->snap[2] = t->snap[1] * 0.2f;
3003         t->fac = 0;
3004         t->transform = Tilt;
3005 }
3006
3007
3008
3009 int Tilt(TransInfo *t, short mval[2]) 
3010 {
3011         TransData *td = t->data;
3012         int i;
3013         char str[50];
3014
3015         float final;
3016
3017         int dx2 = t->center2d[0] - mval[0];
3018         int dy2 = t->center2d[1] - mval[1];
3019         float B = (float)sqrt(dx2*dx2+dy2*dy2);
3020
3021         int dx1 = t->center2d[0] - t->imval[0];
3022         int dy1 = t->center2d[1] - t->imval[1];
3023         float A = (float)sqrt(dx1*dx1+dy1*dy1);
3024
3025         int dx3 = mval[0] - t->imval[0];
3026         int dy3 = mval[1] - t->imval[1];
3027
3028         float deler= ((dx1*dx1+dy1*dy1)+(dx2*dx2+dy2*dy2)-(dx3*dx3+dy3*dy3))
3029                 / (2 * A * B);
3030
3031         float dphi;
3032
3033         dphi = saacos(deler);
3034         if( (dx1*dy2-dx2*dy1)>0.0 ) dphi= -dphi;
3035
3036         if(G.qual & LR_SHIFTKEY) t->fac += dphi/30.0f;
3037         else t->fac += dphi;
3038
3039         final = t->fac;
3040
3041         snapGrid(t, &final);
3042
3043         t->imval[0] = mval[0];
3044         t->imval[1] = mval[1];
3045
3046         if (hasNumInput(&t->num)) {
3047                 char c[20];
3048
3049                 applyNumInput(&t->num, &final);
3050
3051                 outputNumInput(&(t->num), c);
3052
3053                 sprintf(str, "Tilt: %s %s", &c[0], t->proptext);
3054
3055                 final *= (float)(M_PI / 180.0);
3056         }
3057         else {
3058                 sprintf(str, "Tilt: %.2f %s", 180.0*final/M_PI, t->proptext);
3059         }
3060
3061         for(i = 0 ; i < t->total; i++, td++) {
3062                 if (td->flag & TD_NOACTION)
3063                         break;
3064
3065                 if (td->val) {
3066                         *td->val = td->ival + final * td->factor;
3067                 }
3068         }
3069
3070         recalcData(t);
3071
3072         headerprint(str);
3073
3074         force_draw(0);
3075
3076         helpline (t->center);
3077
3078         return 1;
3079 }
3080
3081 /* ************************** PUSH/PULL *************************** */
3082
3083 void initPushPull(TransInfo *t) 
3084 {
3085         t->idx_max = 0;
3086         t->num.idx_max = 0;
3087         t->snap[0] = 0.0f;
3088         t->snap[1] = 1.0f;
3089         t->snap[2] = t->snap[1] * 0.1f;
3090         t->transform = PushPull;
3091 }
3092
3093
3094
3095 int PushPull(TransInfo *t, short mval[2]) 
3096 {
3097         float vec[3], axis[3];
3098         float distance;
3099         int i;
3100         char str[50];
3101         TransData *td = t->data;
3102
3103         window_to_3d(t->vec, (short)(mval[0] - t->imval[0]), (short)(mval[1] - t->imval[1]));
3104         Projf(vec, t->vec, G.vd->viewinv[1]);
3105         distance = Inpf(t->viewinv[1], vec) * 2.0f;
3106
3107         snapGrid(t, &distance);
3108
3109         applyNumInput(&t->num, &distance);
3110
3111         /* header print for NumInput */
3112         if (hasNumInput(&t->num)) {
3113                 char c[20];
3114
3115                 outputNumInput(&(t->num), c);
3116
3117                 sprintf(str, "Push/Pull: %s%s %s", c, t->con.text, t->proptext);
3118         }
3119         else {
3120                 /* default header print */
3121                 sprintf(str, "Push/Pull: %.4f%s %s", distance, t->con.text, t->proptext);
3122         }
3123         
3124         if (t->con.applyRot) {
3125                 t->con.applyRot(t, NULL, axis);
3126         }