Transform fun
[blender-staging.git] / source / blender / editors / transform / transform_constraints.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL 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.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): none yet.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <math.h>
34
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
38
39 #ifndef WIN32
40 #include <unistd.h>
41 #else
42 #include <io.h>
43 #endif
44
45 #include "MEM_guardedalloc.h"
46
47 #include "DNA_action_types.h"
48 #include "DNA_armature_types.h"
49 #include "DNA_camera_types.h"
50 #include "DNA_curve_types.h"
51 #include "DNA_effect_types.h"
52 #include "DNA_image_types.h"
53 #include "DNA_ipo_types.h"
54 #include "DNA_key_types.h"
55 #include "DNA_lamp_types.h"
56 #include "DNA_lattice_types.h"
57 #include "DNA_mesh_types.h"
58 #include "DNA_meshdata_types.h"
59 #include "DNA_meta_types.h"
60 #include "DNA_object_types.h"
61 #include "DNA_scene_types.h"
62 #include "DNA_screen_types.h"
63 #include "DNA_space_types.h"
64 #include "DNA_view3d_types.h"
65
66 //#include "BIF_screen.h"
67 //#include "BIF_resources.h"
68 //#include "BIF_mywindow.h"
69 #include "BIF_gl.h"
70 #include "BIF_glutil.h"
71
72 #include "BKE_global.h"
73 #include "BKE_utildefines.h"
74
75 #include "ED_image.h"
76 #include "ED_view3d.h"
77
78 #include "BLI_arithb.h"
79
80 //#include "blendef.h"
81 //
82 //#include "mydevice.h"
83
84 #include "WM_types.h"
85 #include "UI_resources.h"
86
87
88 #include "transform.h"
89
90 static void drawObjectConstraint(TransInfo *t);
91
92 /* ************************** CONSTRAINTS ************************* */
93 void constraintAutoValues(TransInfo *t, float vec[3])
94 {
95         int mode = t->con.mode;
96         if (mode & CON_APPLY)
97         {
98                 float nval = (t->flag & T_NULL_ONE)?1.0f:0.0f;
99
100                 if ((mode & CON_AXIS0) == 0)
101                 {
102                         vec[0] = nval;
103                 }
104                 if ((mode & CON_AXIS1) == 0)
105                 {
106                         vec[1] = nval;
107                 }
108                 if ((mode & CON_AXIS2) == 0)
109                 {
110                         vec[2] = nval;
111                 }
112         }
113 }
114
115 void constraintNumInput(TransInfo *t, float vec[3])
116 {
117         int mode = t->con.mode;
118         if (mode & CON_APPLY) {
119                 float nval = (t->flag & T_NULL_ONE)?1.0f:0.0f;
120
121                 if (getConstraintSpaceDimension(t) == 2) {
122                         int axis = mode & (CON_AXIS0|CON_AXIS1|CON_AXIS2);
123                         if (axis == (CON_AXIS0|CON_AXIS1)) {
124                                 vec[0] = vec[0];
125                                 vec[1] = vec[1];
126                                 vec[2] = nval;
127                         }
128                         else if (axis == (CON_AXIS1|CON_AXIS2)) {
129                                 vec[2] = vec[1];
130                                 vec[1] = vec[0];
131                                 vec[0] = nval;
132                         }
133                         else if (axis == (CON_AXIS0|CON_AXIS2)) {
134                                 vec[0] = vec[0];
135                                 vec[2] = vec[1];
136                                 vec[1] = nval;
137                         }
138                 }
139                 else if (getConstraintSpaceDimension(t) == 1) {
140                         if (mode & CON_AXIS0) {
141                                 vec[0] = vec[0];
142                                 vec[1] = nval;
143                                 vec[2] = nval;
144                         }
145                         else if (mode & CON_AXIS1) {
146                                 vec[1] = vec[0];
147                                 vec[0] = nval;
148                                 vec[2] = nval;
149                         }
150                         else if (mode & CON_AXIS2) {
151                                 vec[2] = vec[0];
152                                 vec[0] = nval;
153                                 vec[1] = nval;
154                         }
155                 }
156         }
157 }
158
159 static void postConstraintChecks(TransInfo *t, float vec[3], float pvec[3]) {
160         int i = 0;
161
162         Mat3MulVecfl(t->con.imtx, vec);
163
164         snapGrid(t, vec);
165
166         if (t->num.flag & T_NULL_ONE) {
167                 if (!(t->con.mode & CON_AXIS0))
168                         vec[0] = 1.0f;
169
170                 if (!(t->con.mode & CON_AXIS1))
171                         vec[1] = 1.0f;
172
173                 if (!(t->con.mode & CON_AXIS2))
174                         vec[2] = 1.0f;
175         }
176
177         if (hasNumInput(&t->num)) {
178                 applyNumInput(&t->num, vec);
179                 constraintNumInput(t, vec);
180         }
181
182         if (t->flag & T_AUTOVALUES)
183         {
184                 VECCOPY(vec, t->auto_values);
185                 constraintAutoValues(t, vec);
186         }
187         
188         if (t->con.mode & CON_AXIS0) {
189                 pvec[i++] = vec[0];
190         }
191         if (t->con.mode & CON_AXIS1) {
192                 pvec[i++] = vec[1];
193         }
194         if (t->con.mode & CON_AXIS2) {
195                 pvec[i++] = vec[2];
196         }
197
198         Mat3MulVecfl(t->con.mtx, vec);
199 }
200
201 static void axisProjection(TransInfo *t, float axis[3], float in[3], float out[3]) {
202         float norm[3], vec[3], factor;
203         
204         if(in[0]==0.0f && in[1]==0.0f && in[2]==0.0f)
205                 return;
206         
207         /* For when view is parallel to constraint... will cause NaNs otherwise
208            So we take vertical motion in 3D space and apply it to the
209            constraint axis. Nice for camera grab + MMB */
210         if(1.0f - fabs(Inpf(axis, t->viewinv[2])) < 0.000001f) {
211                 Projf(vec, in, t->viewinv[1]);
212                 factor = Inpf(t->viewinv[1], vec) * 2.0f;
213                 /* since camera distance is quite relative, use quadratic relationship. holding shift can compensate */
214                 if(factor<0.0f) factor*= -factor;
215                 else factor*= factor;
216                 
217                 VECCOPY(out, axis);
218                 Normalize(out);
219                 VecMulf(out, -factor);  /* -factor makes move down going backwards */
220         }
221         else {
222                 float cb[3], ab[3];
223                 
224                 VECCOPY(out, axis);
225                 
226                 /* Get view vector on axis to define a plane */
227                 VecAddf(vec, t->con.center, in);
228                 getViewVector(t, vec, norm);
229                 
230                 Crossf(vec, norm, axis);
231                 
232                 /* Project input vector on the plane passing on axis */
233                 Projf(vec, in, vec);
234                 VecSubf(vec, in, vec);
235                 
236                 /* intersect the two lines: axis and norm */
237                 Crossf(cb, vec, norm);
238                 Crossf(ab, axis, norm);
239                 
240                 VecMulf(out, Inpf(cb, ab) / Inpf(ab, ab));
241         }
242 }
243
244 static void planeProjection(TransInfo *t, float in[3], float out[3]) {
245         float vec[3], factor, norm[3];
246
247         VecAddf(vec, in, t->con.center);
248         getViewVector(t, vec, norm);
249
250         VecSubf(vec, out, in);
251
252         factor = Inpf(vec, norm);
253         if (fabs(factor) <= 0.001) {
254                 return; /* prevent divide by zero */
255         }
256         factor = Inpf(vec, vec) / factor;
257
258         VECCOPY(vec, norm);
259         VecMulf(vec, factor);
260
261         VecAddf(out, in, vec);
262 }
263
264 /*
265  * Generic callback for constant spacial constraints applied to linear motion
266  * 
267  * The IN vector in projected into the constrained space and then further
268  * projected along the view vector.
269  * (in perspective mode, the view vector is relative to the position on screen)
270  *
271  */
272
273 static void applyAxisConstraintVec(TransInfo *t, TransData *td, float in[3], float out[3], float pvec[3])
274 {
275         VECCOPY(out, in);
276         if (!td && t->con.mode & CON_APPLY) {
277                 Mat3MulVecfl(t->con.pmtx, out);
278                 
279                 // With snap, a projection is alright, no need to correct for view alignment
280                 if ((t->tsnap.status & SNAP_ON) == 0) {
281                         if (getConstraintSpaceDimension(t) == 2) {
282                                 if (out[0] != 0.0f || out[1] != 0.0f || out[2] != 0.0f) {
283                                         planeProjection(t, in, out);
284                                 }
285                         }
286                         else if (getConstraintSpaceDimension(t) == 1) {
287                                 float c[3];
288         
289                                 if (t->con.mode & CON_AXIS0) {
290                                         VECCOPY(c, t->con.mtx[0]);
291                                 }
292                                 else if (t->con.mode & CON_AXIS1) {
293                                         VECCOPY(c, t->con.mtx[1]);
294                                 }
295                                 else if (t->con.mode & CON_AXIS2) {
296                                         VECCOPY(c, t->con.mtx[2]);
297                                 }
298                                 axisProjection(t, c, in, out);
299                         }
300                 }
301                 postConstraintChecks(t, out, pvec);
302         }
303 }
304
305 /*
306  * Generic callback for object based spacial constraints applied to linear motion
307  * 
308  * At first, the following is applied to the first data in the array
309  * The IN vector in projected into the constrained space and then further
310  * projected along the view vector.
311  * (in perspective mode, the view vector is relative to the position on screen)
312  *
313  * Further down, that vector is mapped to each data's space.
314  */
315
316 static void applyObjectConstraintVec(TransInfo *t, TransData *td, float in[3], float out[3], float pvec[3])
317 {
318         VECCOPY(out, in);
319         if (t->con.mode & CON_APPLY) {
320                 if (!td) {
321                         Mat3MulVecfl(t->con.pmtx, out);
322                         if (getConstraintSpaceDimension(t) == 2) {
323                                 if (out[0] != 0.0f || out[1] != 0.0f || out[2] != 0.0f) {
324                                         planeProjection(t, in, out);
325                                 }
326                         }
327                         else if (getConstraintSpaceDimension(t) == 1) {
328                                 float c[3];
329
330                                 if (t->con.mode & CON_AXIS0) {
331                                         VECCOPY(c, t->con.mtx[0]);
332                                 }
333                                 else if (t->con.mode & CON_AXIS1) {
334                                         VECCOPY(c, t->con.mtx[1]);
335                                 }
336                                 else if (t->con.mode & CON_AXIS2) {
337                                         VECCOPY(c, t->con.mtx[2]);
338                                 }
339                                 axisProjection(t, c, in, out);
340                         }
341                         postConstraintChecks(t, out, pvec);
342                         VECCOPY(out, pvec);
343                 }
344                 else {
345                         int i=0;
346
347                         out[0] = out[1] = out[2] = 0.0f;
348                         if (t->con.mode & CON_AXIS0) {
349                                 out[0] = in[i++];
350                         }
351                         if (t->con.mode & CON_AXIS1) {
352                                 out[1] = in[i++];
353                         }
354                         if (t->con.mode & CON_AXIS2) {
355                                 out[2] = in[i++];
356                         }
357                         Mat3MulVecfl(td->axismtx, out);
358                 }
359         }
360 }
361
362 /*
363  * Generic callback for constant spacial constraints applied to resize motion
364  * 
365  *
366  */
367
368 static void applyAxisConstraintSize(TransInfo *t, TransData *td, float smat[3][3])
369 {
370         if (!td && t->con.mode & CON_APPLY) {
371                 float tmat[3][3];
372
373                 if (!(t->con.mode & CON_AXIS0)) {
374                         smat[0][0] = 1.0f;
375                 }
376                 if (!(t->con.mode & CON_AXIS1)) {
377                         smat[1][1] = 1.0f;
378                 }
379                 if (!(t->con.mode & CON_AXIS2)) {
380                         smat[2][2] = 1.0f;
381                 }
382
383                 Mat3MulMat3(tmat, smat, t->con.imtx);
384                 Mat3MulMat3(smat, t->con.mtx, tmat);
385         }
386 }
387
388 /*
389  * Callback for object based spacial constraints applied to resize motion
390  * 
391  *
392  */
393
394 static void applyObjectConstraintSize(TransInfo *t, TransData *td, float smat[3][3])
395 {
396         if (td && t->con.mode & CON_APPLY) {
397                 float tmat[3][3];
398                 float imat[3][3];
399
400                 Mat3Inv(imat, td->axismtx);
401
402                 if (!(t->con.mode & CON_AXIS0)) {
403                         smat[0][0] = 1.0f;
404                 }
405                 if (!(t->con.mode & CON_AXIS1)) {
406                         smat[1][1] = 1.0f;
407                 }
408                 if (!(t->con.mode & CON_AXIS2)) {
409                         smat[2][2] = 1.0f;
410                 }
411
412                 Mat3MulMat3(tmat, smat, imat);
413                 Mat3MulMat3(smat, td->axismtx, tmat);
414         }
415 }
416
417 /*
418  * Generic callback for constant spacial constraints applied to rotations
419  * 
420  * The rotation axis is copied into VEC.
421  *
422  * In the case of single axis constraints, the rotation axis is directly the one constrained to.
423  * For planar constraints (2 axis), the rotation axis is the normal of the plane.
424  *
425  * The following only applies when CON_NOFLIP is not set.
426  * The vector is then modified to always point away from the screen (in global space)
427  * This insures that the rotation is always logically following the mouse.
428  * (ie: not doing counterclockwise rotations when the mouse moves clockwise).
429  */
430
431 static void applyAxisConstraintRot(TransInfo *t, TransData *td, float vec[3], float *angle)
432 {
433         if (!td && t->con.mode & CON_APPLY) {
434                 int mode = t->con.mode & (CON_AXIS0|CON_AXIS1|CON_AXIS2);
435
436                 switch(mode) {
437                 case CON_AXIS0:
438                 case (CON_AXIS1|CON_AXIS2):
439                         VECCOPY(vec, t->con.mtx[0]);
440                         break;
441                 case CON_AXIS1:
442                 case (CON_AXIS0|CON_AXIS2):
443                         VECCOPY(vec, t->con.mtx[1]);
444                         break;
445                 case CON_AXIS2:
446                 case (CON_AXIS0|CON_AXIS1):
447                         VECCOPY(vec, t->con.mtx[2]);
448                         break;
449                 }
450                 /* don't flip axis if asked to or if num input */
451                 if (angle && (mode & CON_NOFLIP) == 0 && hasNumInput(&t->num) == 0) {
452                         if (Inpf(vec, t->viewinv[2]) > 0.0f) {
453                                 *angle = -(*angle);
454                         }
455                 }
456         }
457 }
458
459 /*
460  * Callback for object based spacial constraints applied to rotations
461  * 
462  * The rotation axis is copied into VEC.
463  *
464  * In the case of single axis constraints, the rotation axis is directly the one constrained to.
465  * For planar constraints (2 axis), the rotation axis is the normal of the plane.
466  *
467  * The following only applies when CON_NOFLIP is not set.
468  * The vector is then modified to always point away from the screen (in global space)
469  * This insures that the rotation is always logically following the mouse.
470  * (ie: not doing counterclockwise rotations when the mouse moves clockwise).
471  */
472
473 static void applyObjectConstraintRot(TransInfo *t, TransData *td, float vec[3], float *angle)
474 {
475         if (t->con.mode & CON_APPLY) {
476                 int mode = t->con.mode & (CON_AXIS0|CON_AXIS1|CON_AXIS2);
477                 
478                 /* on setup call, use first object */
479                 if (td == NULL) {
480                         td= t->data;
481                 }
482
483                 switch(mode) {
484                 case CON_AXIS0:
485                 case (CON_AXIS1|CON_AXIS2):
486                         VECCOPY(vec, td->axismtx[0]);
487                         break;
488                 case CON_AXIS1:
489                 case (CON_AXIS0|CON_AXIS2):
490                         VECCOPY(vec, td->axismtx[1]);
491                         break;
492                 case CON_AXIS2:
493                 case (CON_AXIS0|CON_AXIS1):
494                         VECCOPY(vec, td->axismtx[2]);
495                         break;
496                 }
497                 if (angle && (mode & CON_NOFLIP) == 0 && hasNumInput(&t->num) == 0) {
498                         if (Inpf(vec, t->viewinv[2]) > 0.0f) {
499                                 *angle = -(*angle);
500                         }
501                 }
502         }
503 }
504
505 /*--------------------- INTERNAL SETUP CALLS ------------------*/
506
507 void setConstraint(TransInfo *t, float space[3][3], int mode, const char text[]) {
508         strncpy(t->con.text + 1, text, 48);
509         Mat3CpyMat3(t->con.mtx, space);
510         t->con.mode = mode;
511         getConstraintMatrix(t);
512
513         startConstraint(t);
514
515         t->con.drawExtra = NULL;
516         t->con.applyVec = applyAxisConstraintVec;
517         t->con.applySize = applyAxisConstraintSize;
518         t->con.applyRot = applyAxisConstraintRot;
519         t->redraw = 1;
520 }
521
522 void setLocalConstraint(TransInfo *t, int mode, const char text[]) {
523         if (t->flag & T_EDIT) {
524                 float obmat[3][3];
525                 Mat3CpyMat4(obmat, t->scene->obedit->obmat);
526                 setConstraint(t, obmat, mode, text);
527         }
528         else {
529                 if (t->total == 1) {
530                         setConstraint(t, t->data->axismtx, mode, text);
531                 }
532                 else {
533                         strncpy(t->con.text + 1, text, 48);
534                         Mat3CpyMat3(t->con.mtx, t->data->axismtx);
535                         t->con.mode = mode;
536                         getConstraintMatrix(t);
537
538                         startConstraint(t);
539
540                         t->con.drawExtra = drawObjectConstraint;
541                         t->con.applyVec = applyObjectConstraintVec;
542                         t->con.applySize = applyObjectConstraintSize;
543                         t->con.applyRot = applyObjectConstraintRot;
544                         t->redraw = 1;
545                 }
546         }
547 }
548
549 /*
550         Set the constraint according to the user defined orientation
551
552         ftext is a format string passed to sprintf. It will add the name of
553         the orientation where %s is (logically).
554 */
555 void setUserConstraint(TransInfo *t, int mode, const char ftext[]) {
556         char text[40];
557         //short twmode= (t->spacetype==SPACE_VIEW3D)? ((View3D*)t->view)->twmode: V3D_MANIP_GLOBAL;
558
559         switch(t->current_orientation) {
560         case V3D_MANIP_GLOBAL:
561                 {
562                         float mtx[3][3];
563                         sprintf(text, ftext, "global");
564                         Mat3One(mtx);
565                         setConstraint(t, mtx, mode, text);
566                 }
567                 break;
568         case V3D_MANIP_LOCAL:
569                 sprintf(text, ftext, "local");
570                 setLocalConstraint(t, mode, text);
571                 break;
572         case V3D_MANIP_NORMAL:
573                 sprintf(text, ftext, "normal");
574                 setConstraint(t, t->spacemtx, mode, text);
575                 break;
576         case V3D_MANIP_VIEW:
577                 sprintf(text, ftext, "view");
578                 setConstraint(t, t->spacemtx, mode, text);
579                 break;
580         default: /* V3D_MANIP_CUSTOM */
581                 sprintf(text, ftext, t->spacename);
582                 setConstraint(t, t->spacemtx, mode, text);
583                 break;
584         }
585
586         t->con.mode |= CON_USER;
587 }
588
589 /*--------------------- EXTERNAL SETUP CALLS ------------------*/
590
591 void BIF_setLocalLockConstraint(char axis, char *text) {
592         TransInfo *t = BIF_GetTransInfo();
593
594         if (t->total == 0) {
595                 return;
596         }
597         
598         switch (axis) {
599         case 'x':
600                 setLocalConstraint(t, (CON_AXIS1|CON_AXIS2), text);
601                 break;
602         case 'y':
603                 setLocalConstraint(t, (CON_AXIS0|CON_AXIS2), text);
604                 break;
605         case 'z':
606                 setLocalConstraint(t, (CON_AXIS0|CON_AXIS1), text);
607                 break;
608         }
609 }
610
611 void BIF_setLocalAxisConstraint(char axis, char *text) {
612         TransInfo *t = BIF_GetTransInfo();
613
614         if (t->total == 0) {
615                 return;
616         }
617         
618         switch (axis) {
619         case 'X':
620                 setLocalConstraint(t, CON_AXIS0, text);
621                 break;
622         case 'Y':
623                 setLocalConstraint(t, CON_AXIS1, text);
624                 break;
625         case 'Z':
626                 setLocalConstraint(t, CON_AXIS2, text);
627                 break;
628         }
629 }
630
631 /* text is optional, for header print */
632 void BIF_setSingleAxisConstraint(float vec[3], char *text) {
633         TransInfo *t = BIF_GetTransInfo();
634         float space[3][3], v[3];
635         
636         if (t->total == 0) {
637                 return;
638         }
639         
640         VECCOPY(space[0], vec);
641
642         v[0] = vec[2];
643         v[1] = vec[0];
644         v[2] = vec[1];
645
646         Crossf(space[1], vec, v);
647         Crossf(space[2], vec, space[1]);
648         Mat3Ortho(space);
649
650         Mat3CpyMat3(t->con.mtx, space);
651         t->con.mode = CON_AXIS0;
652         
653         getConstraintMatrix(t);
654
655         startConstraint(t);
656         
657         /* start copying with an offset of 1, to reserve a spot for the SPACE char */
658         if(text)
659         {
660                 strncpy(t->con.text+1, text, 48);       /* 50 in struct */
661         }
662         else
663         {
664                 t->con.text[1] = '\0'; /* No text */
665         }
666         
667         t->con.drawExtra = NULL;
668         t->con.applyVec = applyAxisConstraintVec;
669         t->con.applySize = applyAxisConstraintSize;
670         t->con.applyRot = applyAxisConstraintRot;
671         t->redraw = 1;
672 }
673
674 void BIF_setDualAxisConstraint(float vec1[3], float vec2[3], char *text) {
675         TransInfo *t = BIF_GetTransInfo();
676         float space[3][3];
677         
678         if (t->total == 0) {
679                 return;
680         }
681
682         VECCOPY(space[0], vec1);
683         VECCOPY(space[1], vec2);
684         Crossf(space[2], space[0], space[1]);
685         Mat3Ortho(space);
686         
687         Mat3CpyMat3(t->con.mtx, space);
688         t->con.mode = CON_AXIS0|CON_AXIS1;
689
690         getConstraintMatrix(t);
691
692         startConstraint(t);
693         
694         /* start copying with an offset of 1, to reserve a spot for the SPACE char */
695         if(text)
696         {
697                 strncpy(t->con.text+1, text, 48);       /* 50 in struct */
698         }
699         else
700         {
701                 t->con.text[1] = '\0'; /* No text */
702         }
703
704         t->con.drawExtra = NULL;
705         t->con.applyVec = applyAxisConstraintVec;
706         t->con.applySize = applyAxisConstraintSize;
707         t->con.applyRot = applyAxisConstraintRot;
708         t->redraw = 1;
709 }
710
711 /*----------------- DRAWING CONSTRAINTS -------------------*/
712
713 void drawConstraint(TransInfo *t)
714 {
715         TransCon *tc = &(t->con);
716
717         if (!ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE))
718                 return;
719         if (!(tc->mode & CON_APPLY))
720                 return;
721         if (t->flag & T_USES_MANIPULATOR)
722                 return;
723         if (t->flag & T_NO_CONSTRAINT)
724                 return;
725         
726         /* nasty exception for Z constraint in camera view */
727         // TRANSFORM_FIX_ME
728 //      if((t->flag & T_OBJECT) && G.vd->camera==OBACT && G.vd->persp==V3D_CAMOB) 
729 //              return;
730
731         if (tc->drawExtra) {
732                 tc->drawExtra(t);
733         }
734         else {
735                 if (tc->mode & CON_SELECT) {
736                         float vec[3];
737                         char col2[3] = {255,255,255};
738                         convertViewVec(t, vec, (short)(t->mval[0] - t->con.imval[0]), (short)(t->mval[1] - t->con.imval[1]));
739                         VecAddf(vec, vec, tc->center);
740
741                         drawLine(t, tc->center, tc->mtx[0], 'x', 0);
742                         drawLine(t, tc->center, tc->mtx[1], 'y', 0);
743                         drawLine(t, tc->center, tc->mtx[2], 'z', 0);
744
745                         glColor3ubv((GLubyte *)col2);
746                         
747                         glDisable(GL_DEPTH_TEST);
748                         setlinestyle(1);
749                         glBegin(GL_LINE_STRIP); 
750                                 glVertex3fv(tc->center); 
751                                 glVertex3fv(vec); 
752                         glEnd();
753                         setlinestyle(0);
754                         // TRANSFORM_FIX_ME
755                         //if(G.vd->zbuf)
756                                 glEnable(GL_DEPTH_TEST);        
757                 }
758
759                 if (tc->mode & CON_AXIS0) {
760                         drawLine(t, tc->center, tc->mtx[0], 'x', DRAWLIGHT);
761                 }
762                 if (tc->mode & CON_AXIS1) {
763                         drawLine(t, tc->center, tc->mtx[1], 'y', DRAWLIGHT);
764                 }
765                 if (tc->mode & CON_AXIS2) {
766                         drawLine(t, tc->center, tc->mtx[2], 'z', DRAWLIGHT);
767                 }
768         }
769 }
770
771 /* called from drawview.c, as an extra per-window draw option */
772 void drawPropCircle(TransInfo *t)
773 {
774         if (t->flag & T_PROP_EDIT) {
775                 float tmat[4][4], imat[4][4];
776
777                 UI_ThemeColor(TH_GRID);
778                 
779                 if(t->spacetype == SPACE_VIEW3D)
780                 {
781                         RegionView3D *rv3d = t->ar->regiondata;
782                         
783                         Mat4CpyMat4(tmat, rv3d->viewmat);
784                         Mat4Invert(imat, tmat);
785                 }
786                 else
787                 {
788                         Mat4One(tmat);
789                         Mat4One(imat);
790                 }
791
792                 glPushMatrix();
793
794                 if((t->spacetype == SPACE_VIEW3D) && t->obedit)
795                 {
796                         glMultMatrixf(t->obedit->obmat); /* because t->center is in local space */
797                 }
798                 else if(t->spacetype == SPACE_IMAGE)
799                 {
800                         float aspx, aspy;
801
802                         ED_space_image_uv_aspect(t->sa->spacedata.first, &aspx, &aspy);
803                         glScalef(1.0f/aspx, 1.0f/aspy, 1.0);
804                 }
805
806                 set_inverted_drawing(1);
807                 drawcircball(GL_LINE_LOOP, t->center, t->prop_size, imat);
808                 set_inverted_drawing(0);
809                 
810                 glPopMatrix();
811         }
812 }
813
814 void BIF_getPropCenter(float *center)
815 {
816         TransInfo *t = BIF_GetTransInfo();
817
818         if (t && t->flag & T_PROP_EDIT) {
819                 VECCOPY(center, t->center);
820         }
821         else
822                 center[0] = center[1] = center[2] = 0.0f;
823 }
824
825 static void drawObjectConstraint(TransInfo *t) {
826         int i;
827         TransData * td = t->data;
828
829         /* Draw the first one lighter because that's the one who controls the others.
830            Meaning the transformation is projected on that one and just copied on the others
831            constraint space.
832            In a nutshell, the object with light axis is controlled by the user and the others follow.
833            Without drawing the first light, users have little clue what they are doing.
834          */
835         if (t->con.mode & CON_AXIS0) {
836                 drawLine(t, td->ob->obmat[3], td->axismtx[0], 'x', DRAWLIGHT);
837         }
838         if (t->con.mode & CON_AXIS1) {
839                 drawLine(t, td->ob->obmat[3], td->axismtx[1], 'y', DRAWLIGHT);
840         }
841         if (t->con.mode & CON_AXIS2) {
842                 drawLine(t, td->ob->obmat[3], td->axismtx[2], 'z', DRAWLIGHT);
843         }
844         
845         td++;
846
847         for(i=1;i<t->total;i++,td++) {
848                 if (t->con.mode & CON_AXIS0) {
849                         drawLine(t, td->ob->obmat[3], td->axismtx[0], 'x', 0);
850                 }
851                 if (t->con.mode & CON_AXIS1) {
852                         drawLine(t, td->ob->obmat[3], td->axismtx[1], 'y', 0);
853                 }
854                 if (t->con.mode & CON_AXIS2) {
855                         drawLine(t, td->ob->obmat[3], td->axismtx[2], 'z', 0);
856                 }
857         }
858 }
859
860 /*--------------------- START / STOP CONSTRAINTS ---------------------- */
861
862 void startConstraint(TransInfo *t) {
863         t->con.mode |= CON_APPLY;
864         *t->con.text = ' ';
865         t->num.idx_max = MIN2(getConstraintSpaceDimension(t) - 1, t->idx_max);
866 }
867
868 void stopConstraint(TransInfo *t) {
869         t->con.mode &= ~(CON_APPLY|CON_SELECT);
870         *t->con.text = '\0';
871         t->num.idx_max = t->idx_max;
872 }
873
874 void getConstraintMatrix(TransInfo *t)
875 {
876         float mat[3][3];
877         Mat3Inv(t->con.imtx, t->con.mtx);
878         Mat3One(t->con.pmtx);
879
880         if (!(t->con.mode & CON_AXIS0)) {
881                 t->con.pmtx[0][0]               =
882                         t->con.pmtx[0][1]       =
883                         t->con.pmtx[0][2]       = 0.0f;
884         }
885
886         if (!(t->con.mode & CON_AXIS1)) {
887                 t->con.pmtx[1][0]               =
888                         t->con.pmtx[1][1]       =
889                         t->con.pmtx[1][2]       = 0.0f;
890         }
891
892         if (!(t->con.mode & CON_AXIS2)) {
893                 t->con.pmtx[2][0]               =
894                         t->con.pmtx[2][1]       =
895                         t->con.pmtx[2][2]       = 0.0f;
896         }
897
898         Mat3MulMat3(mat, t->con.pmtx, t->con.imtx);
899         Mat3MulMat3(t->con.pmtx, t->con.mtx, mat);
900 }
901
902 /*------------------------- MMB Select -------------------------------*/
903
904 void initSelectConstraint(TransInfo *t, float mtx[3][3])
905 {
906         Mat3CpyMat3(t->con.mtx, mtx);
907         t->con.mode |= CON_APPLY;
908         t->con.mode |= CON_SELECT;
909
910         setNearestAxis(t);
911         t->con.drawExtra = NULL;
912         t->con.applyVec = applyAxisConstraintVec;
913         t->con.applySize = applyAxisConstraintSize;
914         t->con.applyRot = applyAxisConstraintRot;
915 }
916
917 void selectConstraint(TransInfo *t) {
918         if (t->con.mode & CON_SELECT) {
919                 setNearestAxis(t);
920                 startConstraint(t);
921         }
922 }
923
924 void postSelectConstraint(TransInfo *t)
925 {
926         if (!(t->con.mode & CON_SELECT))
927                 return;
928
929         t->con.mode &= ~CON_AXIS0;
930         t->con.mode &= ~CON_AXIS1;
931         t->con.mode &= ~CON_AXIS2;
932         t->con.mode &= ~CON_SELECT;
933
934         setNearestAxis(t);
935
936         startConstraint(t);
937         t->redraw = 1;
938 }
939
940 static void setNearestAxis2d(TransInfo *t)
941 {
942         /* no correction needed... just use whichever one is lower */
943         if ( abs(t->mval[0]-t->con.imval[0]) < abs(t->mval[1]-t->con.imval[1]) ) {
944                 t->con.mode |= CON_AXIS1;
945                 sprintf(t->con.text, " along Y axis");
946         }
947         else {
948                 t->con.mode |= CON_AXIS0;
949                 sprintf(t->con.text, " along X axis");
950         }
951 }
952
953 static void setNearestAxis3d(TransInfo *t)
954 {
955         float zfac;
956         float mvec[3], axis[3], proj[3];
957         float len[3];
958         int i, icoord[2];
959         
960         /* calculate mouse movement */
961         mvec[0] = (float)(t->mval[0] - t->con.imval[0]);
962         mvec[1] = (float)(t->mval[1] - t->con.imval[1]);
963         mvec[2] = 0.0f;
964         
965         /* we need to correct axis length for the current zoomlevel of view,
966            this to prevent projected values to be clipped behind the camera
967            and to overflow the short integers.
968            The formula used is a bit stupid, just a simplification of the substraction
969            of two 2D points 30 pixels apart (that's the last factor in the formula) after
970            projecting them with window_to_3d_delta and then get the length of that vector.
971         */
972         zfac= t->persmat[0][3]*t->center[0]+ t->persmat[1][3]*t->center[1]+ t->persmat[2][3]*t->center[2]+ t->persmat[3][3];
973         zfac = VecLength(t->persinv[0]) * 2.0f/t->ar->winx * zfac * 30.0f;
974
975         for (i = 0; i<3; i++) {
976                 VECCOPY(axis, t->con.mtx[i]);
977                 
978                 VecMulf(axis, zfac);
979                 /* now we can project to get window coordinate */
980                 VecAddf(axis, axis, t->con.center);
981                 projectIntView(t, axis, icoord);
982                 
983                 axis[0] = (float)(icoord[0] - t->center2d[0]);
984                 axis[1] = (float)(icoord[1] - t->center2d[1]);
985                 axis[2] = 0.0f;
986
987                 if (Normalize(axis) != 0.0f) {
988                         Projf(proj, mvec, axis);
989                         VecSubf(axis, mvec, proj);
990                         len[i] = Normalize(axis);
991                 }
992                 else {
993                         len[i] = 10000000000.0f;
994                 }
995         }
996
997         if (len[0] <= len[1] && len[0] <= len[2]) {
998                 if (t->modifiers & MOD_CONSTRAINT_PLANE) {
999                         t->con.mode |= (CON_AXIS1|CON_AXIS2);
1000                         sprintf(t->con.text, " locking %s X axis", t->spacename);
1001                 }
1002                 else {
1003                         t->con.mode |= CON_AXIS0;
1004                         sprintf(t->con.text, " along %s X axis", t->spacename);
1005                 }
1006         }
1007         else if (len[1] <= len[0] && len[1] <= len[2]) {
1008                 if (t->modifiers & MOD_CONSTRAINT_PLANE) {
1009                         t->con.mode |= (CON_AXIS0|CON_AXIS2);
1010                         sprintf(t->con.text, " locking %s Y axis", t->spacename);
1011                 }
1012                 else {
1013                         t->con.mode |= CON_AXIS1;
1014                         sprintf(t->con.text, " along %s Y axis", t->spacename);
1015                 }
1016         }
1017         else if (len[2] <= len[1] && len[2] <= len[0]) {
1018                 if (t->modifiers & MOD_CONSTRAINT_PLANE) {
1019                         t->con.mode |= (CON_AXIS0|CON_AXIS1);
1020                         sprintf(t->con.text, " locking %s Z axis", t->spacename);
1021                 }
1022                 else {
1023                         t->con.mode |= CON_AXIS2;
1024                         sprintf(t->con.text, " along %s Z axis", t->spacename);
1025                 }
1026         }
1027 }
1028
1029 void setNearestAxis(TransInfo *t)
1030 {
1031         /* clear any prior constraint flags */
1032         t->con.mode &= ~CON_AXIS0;
1033         t->con.mode &= ~CON_AXIS1;
1034         t->con.mode &= ~CON_AXIS2;
1035
1036         /* constraint setting - depends on spacetype */
1037         if (t->spacetype == SPACE_VIEW3D) {
1038                 /* 3d-view */
1039                 setNearestAxis3d(t);    
1040         }
1041         else {
1042                 /* assume that this means a 2D-Editor */
1043                 setNearestAxis2d(t);
1044         }
1045         
1046         getConstraintMatrix(t);
1047 }
1048
1049 /*-------------- HELPER FUNCTIONS ----------------*/
1050
1051 char constraintModeToChar(TransInfo *t) {
1052         if ((t->con.mode & CON_APPLY)==0) {
1053                 return '\0';
1054         }
1055         switch (t->con.mode & (CON_AXIS0|CON_AXIS1|CON_AXIS2)) {
1056         case (CON_AXIS0):
1057         case (CON_AXIS1|CON_AXIS2):
1058                 return 'X';
1059         case (CON_AXIS1):
1060         case (CON_AXIS0|CON_AXIS2):
1061                 return 'Y';
1062         case (CON_AXIS2):
1063         case (CON_AXIS0|CON_AXIS1):
1064                 return 'Z';
1065         default:
1066                 return '\0';
1067         }
1068 }
1069
1070
1071 int isLockConstraint(TransInfo *t) {
1072         int mode = t->con.mode;
1073
1074         if ( (mode & (CON_AXIS0|CON_AXIS1)) == (CON_AXIS0|CON_AXIS1))
1075                 return 1;
1076
1077         if ( (mode & (CON_AXIS1|CON_AXIS2)) == (CON_AXIS1|CON_AXIS2))
1078                 return 1;
1079
1080         if ( (mode & (CON_AXIS0|CON_AXIS2)) == (CON_AXIS0|CON_AXIS2))
1081                 return 1;
1082
1083         return 0;
1084 }
1085
1086 /*
1087  * Returns the dimension of the constraint space.
1088  * 
1089  * For that reason, the flags always needs to be set to properly evaluate here,
1090  * even if they aren't actually used in the callback function. (Which could happen
1091  * for weird constraints not yet designed. Along a path for example.)
1092  */
1093
1094 int getConstraintSpaceDimension(TransInfo *t)
1095 {
1096         int n = 0;
1097
1098         if (t->con.mode & CON_AXIS0)
1099                 n++;
1100
1101         if (t->con.mode & CON_AXIS1)
1102                 n++;
1103
1104         if (t->con.mode & CON_AXIS2)
1105                 n++;
1106
1107         return n;
1108 /*
1109   Someone willing to do it criptically could do the following instead:
1110
1111   return t->con & (CON_AXIS0|CON_AXIS1|CON_AXIS2);
1112         
1113   Based on the assumptions that the axis flags are one after the other and start at 1
1114 */
1115 }