Removed casting warnings from transform_manipulator.
[blender.git] / source / blender / src / transform_constraints.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_screen.h"
75 #include "BIF_space.h"
76 #include "BIF_editview.h"
77 #include "BIF_resources.h"
78 #include "BIF_mywindow.h"
79 #include "BIF_gl.h"
80 #include "BIF_editlattice.h"
81 #include "BIF_editarmature.h"
82 #include "BIF_editmesh.h"
83
84 #include "BKE_global.h"
85 #include "BKE_object.h"
86 #include "BKE_utildefines.h"
87 #include "BKE_lattice.h"
88 #include "BKE_armature.h"
89 #include "BKE_curve.h"
90 #include "BKE_displist.h"
91
92 #include "BSE_view.h"
93 #include "BSE_edit.h"
94
95 #include "BLI_arithb.h"
96 #include "BLI_editVert.h"
97
98 #include "BDR_drawobject.h"
99
100 #include "blendef.h"
101
102 #include "mydevice.h"
103
104 #include "transform.h"
105 #include "transform_constraints.h"
106 #include "transform_generics.h"
107
108 extern ListBase editNurb;
109 extern ListBase editelems;
110
111 void recalcData();
112
113 /* ************************** CONSTRAINTS ************************* */
114 void getConstraintMatrix(TransInfo *t);
115
116 void constraintNumInput(TransInfo *t, float vec[3])
117 {
118         int mode = t->con.mode;
119         float nval = (t->flag & T_NULL_ONE)?1.0f:0.0f;
120
121         if (getConstraintSpaceDimension(t) == 2) {
122                 if (mode & (CON_AXIS0|CON_AXIS1)) {
123                         vec[2] = nval;
124                 }
125                 else if (mode & (CON_AXIS1|CON_AXIS2)) {
126                         vec[2] = vec[1];
127                         vec[1] = vec[0];
128                         vec[0] = nval;
129                 }
130                 else if (mode & (CON_AXIS0|CON_AXIS2)) {
131                         vec[2] = vec[1];
132                         vec[1] = nval;
133                 }
134         }
135         else if (getConstraintSpaceDimension(t) == 1) {
136                 if (mode & CON_AXIS0) {
137                         vec[1] = nval;
138                         vec[2] = nval;
139                 }
140                 else if (mode & CON_AXIS1) {
141                         vec[1] = vec[0];
142                         vec[0] = nval;
143                         vec[2] = nval;
144                 }
145                 else if (mode & CON_AXIS2) {
146                         vec[2] = vec[0];
147                         vec[0] = nval;
148                         vec[1] = nval;
149                 }
150         }
151 }
152
153 static void postConstraintChecks(TransInfo *t, float vec[3], float pvec[3]) {
154         int i = 0;
155
156         Mat3MulVecfl(t->con.imtx, vec);
157
158         snapGrid(t, vec);
159
160         if (t->num.flag & T_NULL_ONE) {
161                 if (!(t->con.mode & CON_AXIS0))
162                         vec[0] = 1.0f;
163
164                 if (!(t->con.mode & CON_AXIS1))
165                         vec[1] = 1.0f;
166
167                 if (!(t->con.mode & CON_AXIS2))
168                         vec[2] = 1.0f;
169         }
170
171         if (hasNumInput(&t->num)) {
172                 applyNumInput(&t->num, vec);
173                 constraintNumInput(t, vec);
174         }
175         
176         if (t->con.mode & CON_AXIS0) {
177                 pvec[i++] = vec[0];
178         }
179         if (t->con.mode & CON_AXIS1) {
180                 pvec[i++] = vec[1];
181         }
182         if (t->con.mode & CON_AXIS2) {
183                 pvec[i++] = vec[2];
184         }
185
186         Mat3MulVecfl(t->con.mtx, vec);
187 }
188
189
190 static void axisProjection(TransInfo *t, float axis[3], float in[3], float out[3]) {
191         float norm[3], n[3], vec[3], factor;
192
193         VecAddf(vec, in, t->con.center);
194         getViewVector(vec, norm);
195
196         Normalise(axis);
197
198         VECCOPY(n, axis);
199         Mat4MulVecfl(t->viewmat, n);
200         n[2] = t->viewmat[3][2];
201         Mat4MulVecfl(t->viewinv, n);
202
203         /* For when view is parallel to constraint... will cause NaNs otherwise
204            So we take vertical motion in 3D space and apply it to the
205            constraint axis. Nice for camera grab + MMB */
206         if(n[0]*n[0] + n[1]*n[1] + n[2]*n[2] < 0.000001f) {
207                 Projf(vec, in, t->viewinv[1]);
208                 factor = Inpf(t->viewinv[1], vec) * 2.0f;
209                 /* since camera distance is quite relative, use quadratic relationship. holding shift can compensate */
210                 if(factor<0.0f) factor*= -factor;
211                 else factor*= factor;
212                 
213                 VECCOPY(out, axis);
214                 Normalise(out);
215                 VecMulf(out, -factor);  /* -factor makes move down going backwards */
216         }
217         else {
218                 // prevent division by zero, happens on constrainting without initial delta transform */
219                 if(in[0]!=0.0f || in[1]!=0.0f || in[2]!=0.0) {
220                         Projf(vec, in, n);
221                         factor = Normalise(vec);
222                         // prevent NaN for 0.0/0.0
223                         if(factor!=0.0f)
224                                 factor /= Inpf(axis, vec);
225
226                         VecMulf(axis, factor);
227                         VECCOPY(out, axis);
228                 }
229         }
230 }
231
232 static void planeProjection(TransInfo *t, float in[3], float out[3]) {
233         float vec[3], factor, angle, norm[3];
234
235         VecAddf(vec, in, t->con.center);
236         getViewVector(vec, norm);
237
238         VecSubf(vec, out, in);
239         factor = Normalise(vec);
240         angle = Inpf(vec, norm);
241
242         if (angle * angle >= 0.000001f) {
243                 factor /= angle;
244
245                 VECCOPY(vec, norm);
246                 VecMulf(vec, factor);
247
248                 VecAddf(out, in, vec);
249         }
250 }
251
252 /*
253  * Generic callback for constant spacial constraints applied to linear motion
254  * 
255  * The IN vector in projected into the constrained space and then further
256  * projected along the view vector.
257  * (in perspective mode, the view vector is relative to the position on screen)
258  *
259  */
260
261 static void applyAxisConstraintVec(TransInfo *t, TransData *td, float in[3], float out[3], float pvec[3])
262 {
263         VECCOPY(out, in);
264         if (!td && t->con.mode & CON_APPLY) {
265                 Mat3MulVecfl(t->con.pmtx, out);
266                 if (getConstraintSpaceDimension(t) == 2) {
267                         if (out[0] != 0.0f || out[1] != 0.0f || out[2] != 0.0f) {
268                                 planeProjection(t, in, out);
269                         }
270                 }
271                 else if (getConstraintSpaceDimension(t) == 1) {
272                         float c[3];
273
274                         if (t->con.mode & CON_AXIS0) {
275                                 VECCOPY(c, t->con.mtx[0]);
276                         }
277                         else if (t->con.mode & CON_AXIS1) {
278                                 VECCOPY(c, t->con.mtx[1]);
279                         }
280                         else if (t->con.mode & CON_AXIS2) {
281                                 VECCOPY(c, t->con.mtx[2]);
282                         }
283                         axisProjection(t, c, in, out);
284                 }
285                 postConstraintChecks(t, out, pvec);
286         }
287 }
288
289 /*
290  * Generic callback for object based spacial constraints applied to linear motion
291  * 
292  * At first, the following is applied to the first data in the array
293  * The IN vector in projected into the constrained space and then further
294  * projected along the view vector.
295  * (in perspective mode, the view vector is relative to the position on screen)
296  *
297  * Further down, that vector is mapped to each data's space.
298  */
299
300 static void applyObjectConstraintVec(TransInfo *t, TransData *td, float in[3], float out[3], float pvec[3])
301 {
302         VECCOPY(out, in);
303         if (t->con.mode & CON_APPLY) {
304                 if (!td) {
305                         Mat3MulVecfl(t->con.pmtx, out);
306                         if (getConstraintSpaceDimension(t) == 2) {
307                                 if (out[0] != 0.0f || out[1] != 0.0f || out[2] != 0.0f) {
308                                         planeProjection(t, in, out);
309                                 }
310                         }
311                         else if (getConstraintSpaceDimension(t) == 1) {
312                                 float c[3];
313
314                                 if (t->con.mode & CON_AXIS0) {
315                                         VECCOPY(c, t->con.mtx[0]);
316                                 }
317                                 else if (t->con.mode & CON_AXIS1) {
318                                         VECCOPY(c, t->con.mtx[1]);
319                                 }
320                                 else if (t->con.mode & CON_AXIS2) {
321                                         VECCOPY(c, t->con.mtx[2]);
322                                 }
323                                 axisProjection(t, c, in, out);
324                         }
325                         postConstraintChecks(t, out, pvec);
326                         VECCOPY(out, pvec);
327                 }
328                 else {
329                         Mat3MulVecfl(td->axismtx, out);
330                 }
331         }
332 }
333
334 /*
335  * Generic callback for constant spacial constraints applied to resize motion
336  * 
337  *
338  */
339
340 static void applyAxisConstraintSize(TransInfo *t, TransData *td, float smat[3][3])
341 {
342         if (!td && t->con.mode & CON_APPLY) {
343                 float tmat[3][3];
344
345                 if (!(t->con.mode & CON_AXIS0)) {
346                         smat[0][0] = 1.0f;
347                 }
348                 if (!(t->con.mode & CON_AXIS1)) {
349                         smat[1][1] = 1.0f;
350                 }
351                 if (!(t->con.mode & CON_AXIS2)) {
352                         smat[2][2] = 1.0f;
353                 }
354
355                 Mat3MulMat3(tmat, smat, t->con.imtx);
356                 Mat3MulMat3(smat, t->con.mtx, tmat);
357         }
358 }
359
360 /*
361  * Callback for object based spacial constraints applied to resize motion
362  * 
363  *
364  */
365
366 static void applyObjectConstraintSize(TransInfo *t, TransData *td, float smat[3][3])
367 {
368         if (td && t->con.mode & CON_APPLY) {
369                 float tmat[3][3];
370                 float imat[3][3];
371
372                 Mat3Inv(imat, td->axismtx);
373
374                 if (!(t->con.mode & CON_AXIS0)) {
375                         smat[0][0] = 1.0f;
376                 }
377                 if (!(t->con.mode & CON_AXIS1)) {
378                         smat[1][1] = 1.0f;
379                 }
380                 if (!(t->con.mode & CON_AXIS2)) {
381                         smat[2][2] = 1.0f;
382                 }
383
384                 Mat3MulMat3(tmat, smat, imat);
385                 Mat3MulMat3(smat, td->axismtx, tmat);
386         }
387 }
388
389 /*
390  * Generic callback for constant spacial constraints applied to rotations
391  * 
392  * The rotation axis is copied into VEC.
393  *
394  * In the case of single axis constraints, the rotation axis is directly the one constrained to.
395  * For planar constraints (2 axis), the rotation axis is the normal of the plane.
396  *
397  * The following only applies when CON_NOFLIP is not set.
398  * The vector is then modified to always point away from the screen (in global space)
399  * This insures that the rotation is always logically following the mouse.
400  * (ie: not doing counterclockwise rotations when the mouse moves clockwise).
401  */
402
403 static void applyAxisConstraintRot(TransInfo *t, TransData *td, float vec[3])
404 {
405         if (!td && t->con.mode & CON_APPLY) {
406                 int mode = t->con.mode & (CON_AXIS0|CON_AXIS1|CON_AXIS2);
407
408                 switch(mode) {
409                 case CON_AXIS0:
410                 case (CON_AXIS1|CON_AXIS2):
411                         VECCOPY(vec, t->con.mtx[0]);
412                         break;
413                 case CON_AXIS1:
414                 case (CON_AXIS0|CON_AXIS2):
415                         VECCOPY(vec, t->con.mtx[1]);
416                         break;
417                 case CON_AXIS2:
418                 case (CON_AXIS0|CON_AXIS1):
419                         VECCOPY(vec, t->con.mtx[2]);
420                         break;
421                 }
422                 if (!(mode & CON_NOFLIP)) {
423                         if (Inpf(vec, G.vd->viewinv[2]) > 0.0f) {
424                                 VecMulf(vec, -1.0f);
425                         }
426                 }
427         }
428 }
429
430 /*
431  * Callback for object based spacial constraints applied to rotations
432  * 
433  * The rotation axis is copied into VEC.
434  *
435  * In the case of single axis constraints, the rotation axis is directly the one constrained to.
436  * For planar constraints (2 axis), the rotation axis is the normal of the plane.
437  *
438  * The following only applies when CON_NOFLIP is not set.
439  * The vector is then modified to always point away from the screen (in global space)
440  * This insures that the rotation is always logically following the mouse.
441  * (ie: not doing counterclockwise rotations when the mouse moves clockwise).
442  */
443
444 static void applyObjectConstraintRot(TransInfo *t, TransData *td, float vec[3])
445 {
446         if (td && t->con.mode & CON_APPLY) {
447                 int mode = t->con.mode & (CON_AXIS0|CON_AXIS1|CON_AXIS2);
448
449                 switch(mode) {
450                 case CON_AXIS0:
451                 case (CON_AXIS1|CON_AXIS2):
452                         VECCOPY(vec, td->axismtx[0]);
453                         break;
454                 case CON_AXIS1:
455                 case (CON_AXIS0|CON_AXIS2):
456                         VECCOPY(vec, td->axismtx[1]);
457                         break;
458                 case CON_AXIS2:
459                 case (CON_AXIS0|CON_AXIS1):
460                         VECCOPY(vec, td->axismtx[2]);
461                         break;
462                 }
463                 if (!(mode & CON_NOFLIP)) {
464                         if (Inpf(vec, G.vd->viewinv[2]) > 0.0f) {
465                                 VecMulf(vec, -1.0f);
466                         }
467                 }
468         }
469 }
470
471 static void drawObjectConstraint(TransInfo *t) {
472         int i;
473         TransData * td = t->data;
474
475         if (t->con.mode & CON_AXIS0) {
476                 drawLine(td->ob->obmat[3], td->axismtx[0], 'x', DRAWLIGHT);
477         }
478         if (t->con.mode & CON_AXIS1) {
479                 drawLine(td->ob->obmat[3], td->axismtx[1], 'y', DRAWLIGHT);
480         }
481         if (t->con.mode & CON_AXIS2) {
482                 drawLine(td->ob->obmat[3], td->axismtx[2], 'z', DRAWLIGHT);
483         }
484
485         td++;
486         for(i=1;i<t->total;i++,td++) {
487                 if (t->con.mode & CON_AXIS0) {
488                         drawLine(td->ob->obmat[3], td->axismtx[0], 'x', 0);
489                 }
490                 if (t->con.mode & CON_AXIS1) {
491                         drawLine(td->ob->obmat[3], td->axismtx[1], 'y', 0);
492                 }
493                 if (t->con.mode & CON_AXIS2) {
494                         drawLine(td->ob->obmat[3], td->axismtx[2], 'z', 0);
495                 }
496         }
497 }
498
499 /*
500  * Returns the dimension of the constraint space.
501  * 
502  * For that reason, the flags always needs to be set to properly evaluate here,
503  * even if they aren't actually used in the callback function. (Which could happen
504  * for weird constraints not yet designed. Along a path for example.)
505  */
506
507 int getConstraintSpaceDimension(TransInfo *t)
508 {
509         int n = 0;
510
511         if (t->con.mode & CON_AXIS0)
512                 n++;
513
514         if (t->con.mode & CON_AXIS1)
515                 n++;
516
517         if (t->con.mode & CON_AXIS2)
518                 n++;
519
520         return n;
521 /*
522   Someone willing to do it criptically could do the following instead:
523
524   return t->con & (CON_AXIS0|CON_AXIS1|CON_AXIS2);
525         
526   Based on the assumptions that the axis flags are one after the other and start at 1
527 */
528 }
529
530 void setConstraint(TransInfo *t, float space[3][3], int mode, const char text[]) {
531         strncpy(t->con.text + 1, text, 48);
532         Mat3CpyMat3(t->con.mtx, space);
533         t->con.mode = mode;
534         getConstraintMatrix(t);
535
536         startConstraint(t);
537
538         t->con.applyVec = applyAxisConstraintVec;
539         t->con.applySize = applyAxisConstraintSize;
540         t->con.applyRot = applyAxisConstraintRot;
541         t->redraw = 1;
542 }
543
544 void setLocalConstraint(TransInfo *t, int mode, const char text[]) {
545         if (t->flag & T_EDIT) {
546                 float obmat[3][3];
547                 Mat3CpyMat4(obmat, G.obedit->obmat);
548                 setConstraint(t, obmat, mode, text);
549         }
550         else {
551                 if (t->total == 1) {
552                         setConstraint(t, t->data->axismtx, mode, text);
553                 }
554                 else {
555                         strncpy(t->con.text + 1, text, 48);
556                         Mat3CpyMat3(t->con.mtx, t->data->axismtx);
557                         t->con.mode = mode;
558                         getConstraintMatrix(t);
559
560                         startConstraint(t);
561
562                         t->con.drawExtra = drawObjectConstraint;
563                         t->con.applyVec = applyObjectConstraintVec;
564                         t->con.applySize = applyObjectConstraintSize;
565                         t->con.applyRot = applyObjectConstraintRot;
566                         t->redraw = 1;
567                 }
568         }
569 }
570
571 /* text is optional, for header print */
572 void BIF_setSingleAxisConstraint(float vec[3], char *text) {
573         TransInfo *t = BIF_GetTransInfo();
574         float space[3][3], v[3];
575         
576         VECCOPY(space[0], vec);
577
578         v[0] = vec[2];
579         v[1] = vec[0];
580         v[2] = vec[1];
581
582         Crossf(space[1], vec, v);
583         Crossf(space[2], vec, space[1]);
584         Mat3Ortho(space);
585
586         Mat3Ortho(space);
587
588         Mat3CpyMat3(t->con.mtx, space);
589         t->con.mode = (CON_AXIS0|CON_APPLY);
590         getConstraintMatrix(t);
591
592         /* start copying with an offset of 1, to reserve a spot for the SPACE char */
593         if(text) strncpy(t->con.text+1, text, 48);      // 50 in struct
594
595         
596         t->con.drawExtra = NULL;
597         t->con.applyVec = applyAxisConstraintVec;
598         t->con.applySize = applyAxisConstraintSize;
599         t->con.applyRot = applyAxisConstraintRot;
600         t->redraw = 1;
601 }
602
603 void BIF_setDualAxisConstraint(float vec1[3], float vec2[3]) {
604         TransInfo *t = BIF_GetTransInfo();
605         float space[3][3];
606         
607         VECCOPY(space[0], vec1);
608         VECCOPY(space[1], vec2);
609         Crossf(space[2], space[0], space[1]);
610         Mat3Ortho(space);
611         
612         Mat3CpyMat3(t->con.mtx, space);
613         t->con.mode = (CON_AXIS0|CON_AXIS1|CON_APPLY);
614         getConstraintMatrix(t);
615         
616         t->con.drawExtra = NULL;
617         t->con.applyVec = applyAxisConstraintVec;
618         t->con.applySize = applyAxisConstraintSize;
619         t->con.applyRot = applyAxisConstraintRot;
620         t->redraw = 1;
621 }
622
623
624 void BIF_drawConstraint(void)
625 {
626         TransInfo *t = BIF_GetTransInfo();
627         TransCon *tc = &(t->con);
628
629         if (!(tc->mode & CON_APPLY))
630                 return;
631         if (t->flag & T_USES_MANIPULATOR)
632                 return;
633         
634         /* nasty exception for Z constraint in camera view */
635         if( (t->flag & T_OBJECT) && G.vd->camera==OBACT && G.vd->persp>1) 
636                 return;
637
638         if (tc->drawExtra) {
639                 tc->drawExtra(t);
640         }
641         else {
642                 if (tc->mode & CON_SELECT) {
643                         float vec[3];
644                         short mval[2];
645                         char col2[3] = {255,255,255};
646                         getmouseco_areawin(mval);
647                         window_to_3d(vec, (short)(mval[0] - t->con.imval[0]), (short)(mval[1] - t->con.imval[1]));
648                         VecAddf(vec, vec, tc->center);
649
650 //                      drawLine(tc->center, tc->mtx[0], 'x', 0);
651 //                      drawLine(tc->center, tc->mtx[1], 'y', 0);
652 //                      drawLine(tc->center, tc->mtx[2], 'z', 0);
653
654                         draw_manipulator_ext(curarea, t->mode, 'c', 2, tc->center, tc->mtx);
655                         glColor3ubv(col2);
656                         
657                         glDisable(GL_DEPTH_TEST);
658                         setlinestyle(1);
659                         glBegin(GL_LINE_STRIP); 
660                                 glVertex3fv(tc->center); 
661                                 glVertex3fv(vec); 
662                         glEnd();
663                         setlinestyle(0);
664                         if(G.zbuf) glEnable(GL_DEPTH_TEST);     // warning for global!
665                 }
666
667                 if (tc->mode & CON_AXIS0) {
668                         draw_manipulator_ext(curarea, t->mode, 'x', 0, tc->center, tc->mtx);
669                         draw_manipulator_ext(curarea, t->mode, 'x', 2, tc->center, tc->mtx);
670 //                      drawLine(tc->center, tc->mtx[0], 'x', DRAWLIGHT);
671                 }
672                 if (tc->mode & CON_AXIS1) {
673                         draw_manipulator_ext(curarea, t->mode, 'y', 0, tc->center, tc->mtx);
674                         draw_manipulator_ext(curarea, t->mode, 'y', 2, tc->center, tc->mtx);
675 //                      drawLine(tc->center, tc->mtx[1], 'y', DRAWLIGHT);
676                 }
677                 if (tc->mode & CON_AXIS2) {
678                         draw_manipulator_ext(curarea, t->mode, 'z', 0, tc->center, tc->mtx);
679                         draw_manipulator_ext(curarea, t->mode, 'z', 2, tc->center, tc->mtx);
680 //                      drawLine(tc->center, tc->mtx[2], 'z', DRAWLIGHT);
681                 }
682         }
683 }
684
685 /* called from drawview.c, as an extra per-window draw option */
686 void BIF_drawPropCircle()
687 {
688         TransInfo *t = BIF_GetTransInfo();
689
690         if (t->flag & T_PROP_EDIT) {
691                 float tmat[4][4], imat[4][4];
692
693                 BIF_ThemeColor(TH_GRID);
694                 
695                 /* if editmode we need to go into object space */
696                 if(G.obedit) mymultmatrix(G.obedit->obmat);
697                 
698                 mygetmatrix(tmat);
699                 Mat4Invert(imat, tmat);
700                 
701                 drawcircball(t->center, t->propsize, imat);
702                 
703                 /* if editmode we restore */
704                 if(G.obedit) myloadmatrix(G.vd->viewmat);
705         }
706 }
707
708 void initConstraint(TransInfo *t) {
709         if (t->con.mode & CON_APPLY) {
710                 startConstraint(t);
711         }
712 }
713
714 void startConstraint(TransInfo *t) {
715         t->con.mode |= CON_APPLY;
716         *t->con.text = ' ';
717         t->num.idx_max = MIN2(getConstraintSpaceDimension(t) - 1, t->idx_max);
718 }
719
720 void stopConstraint(TransInfo *t) {
721         t->con.mode &= ~CON_APPLY;
722         *t->con.text = '\0';
723         t->num.idx_max = t->idx_max;
724 }
725
726 void getConstraintMatrix(TransInfo *t)
727 {
728         float mat[3][3];
729         Mat3Inv(t->con.imtx, t->con.mtx);
730         Mat3One(t->con.pmtx);
731
732         if (!(t->con.mode & CON_AXIS0)) {
733                 t->con.pmtx[0][0]               =
734                         t->con.pmtx[0][1]       =
735                         t->con.pmtx[0][2]       = 0.0f;
736         }
737
738         if (!(t->con.mode & CON_AXIS1)) {
739                 t->con.pmtx[1][0]               =
740                         t->con.pmtx[1][1]       =
741                         t->con.pmtx[1][2]       = 0.0f;
742         }
743
744         if (!(t->con.mode & CON_AXIS2)) {
745                 t->con.pmtx[2][0]               =
746                         t->con.pmtx[2][1]       =
747                         t->con.pmtx[2][2]       = 0.0f;
748         }
749
750         Mat3MulMat3(mat, t->con.pmtx, t->con.imtx);
751         Mat3MulMat3(t->con.pmtx, t->con.mtx, mat);
752 }
753
754 void initSelectConstraint(TransInfo *t)
755 {
756         Mat3One(t->con.mtx);
757         Mat3One(t->con.pmtx);
758         t->con.mode |= CON_APPLY;
759         t->con.mode |= CON_SELECT;
760
761         setNearestAxis(t);
762         t->con.drawExtra = NULL;
763         t->con.applyVec = applyAxisConstraintVec;
764         t->con.applySize = applyAxisConstraintSize;
765         t->con.applyRot = applyAxisConstraintRot;
766 }
767
768 void selectConstraint(TransInfo *t) {
769         if (t->con.mode & CON_SELECT) {
770                 setNearestAxis(t);
771                 startConstraint(t);
772         }
773 }
774
775 void postSelectConstraint(TransInfo *t)
776 {
777         if (!(t->con.mode & CON_SELECT))
778                 return;
779
780         t->con.mode &= ~CON_AXIS0;
781         t->con.mode &= ~CON_AXIS1;
782         t->con.mode &= ~CON_AXIS2;
783         t->con.mode &= ~CON_SELECT;
784
785         setNearestAxis(t);
786
787         startConstraint(t);
788         t->redraw = 1;
789 }
790
791 void setNearestAxis(TransInfo *t)
792 {
793         short coord[2];
794         float mvec[3], axis[3], proj[3];
795         float len[3];
796         int i;
797
798         t->con.mode &= ~CON_AXIS0;
799         t->con.mode &= ~CON_AXIS1;
800         t->con.mode &= ~CON_AXIS2;
801
802         getmouseco_areawin(coord);
803         mvec[0] = (float)(coord[0] - t->con.imval[0]);
804         mvec[1] = (float)(coord[1] - t->con.imval[1]);
805         mvec[2] = 0.0f;
806
807         for (i = 0; i<3; i++) {
808                 VECCOPY(axis, t->con.mtx[i]);
809                 VecAddf(axis, axis, t->con.center);
810                 project_short_noclip(axis, coord);
811                 axis[0] = (float)(coord[0] - t->center2d[0]);
812                 axis[1] = (float)(coord[1] - t->center2d[1]);
813                 axis[2] = 0.0f;
814
815                 if (Normalise(axis) != 0.0f) {
816                         Projf(proj, mvec, axis);
817                         VecSubf(axis, mvec, proj);
818                         len[i] = Normalise(axis);
819                 }
820                 else {
821                         len[i] = 10000000000.0f;
822                 }
823         }
824
825         if (len[0] <= len[1] && len[0] <= len[2]) {
826                 if (G.qual & LR_SHIFTKEY) {
827                         t->con.mode |= (CON_AXIS1|CON_AXIS2);
828                         strcpy(t->con.text, " locking global X");
829                 }
830                 else {
831                         t->con.mode |= CON_AXIS0;
832                         strcpy(t->con.text, " along global X");
833                 }
834         }
835         else if (len[1] <= len[0] && len[1] <= len[2]) {
836                 if (G.qual & LR_SHIFTKEY) {
837                         t->con.mode |= (CON_AXIS0|CON_AXIS2);
838                         strcpy(t->con.text, " locking global Y");
839                 }
840                 else {
841                         t->con.mode |= CON_AXIS1;
842                         strcpy(t->con.text, " along global Y");
843                 }
844         }
845         else if (len[2] <= len[1] && len[2] <= len[0]) {
846                 if (G.qual & LR_SHIFTKEY) {
847                         t->con.mode |= (CON_AXIS0|CON_AXIS1);
848                         strcpy(t->con.text, " locking global Z");
849                 }
850                 else {
851                         t->con.mode |= CON_AXIS2;
852                         strcpy(t->con.text, " along global Z");
853                 }
854         }
855         getConstraintMatrix(t);
856 }