8b717664347fb751ab16e295e28a0d33240a9285
[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 #include "BLI_winstuff.h"
46 #endif
47
48 #include "MEM_guardedalloc.h"
49
50 #include "DNA_action_types.h"
51 #include "DNA_armature_types.h"
52 #include "DNA_camera_types.h"
53 #include "DNA_curve_types.h"
54 #include "DNA_effect_types.h"
55 #include "DNA_ika_types.h"
56 #include "DNA_image_types.h"
57 #include "DNA_ipo_types.h"
58 #include "DNA_key_types.h"
59 #include "DNA_lamp_types.h"
60 #include "DNA_lattice_types.h"
61 #include "DNA_mesh_types.h"
62 #include "DNA_meshdata_types.h"
63 #include "DNA_meta_types.h"
64 #include "DNA_object_types.h"
65 #include "DNA_scene_types.h"
66 #include "DNA_screen_types.h"
67 #include "DNA_texture_types.h"
68 #include "DNA_view3d_types.h"
69 #include "DNA_world_types.h"
70 #include "DNA_userdef_types.h"
71 #include "DNA_property_types.h"
72 #include "DNA_vfont_types.h"
73 #include "DNA_constraint_types.h"
74
75 #include "BIF_screen.h"
76 #include "BIF_space.h"
77 #include "BIF_editview.h"
78 #include "BIF_resources.h"
79 #include "BIF_mywindow.h"
80 #include "BIF_gl.h"
81 #include "BIF_editlattice.h"
82 #include "BIF_editarmature.h"
83 #include "BIF_editmesh.h"
84
85 #include "BKE_global.h"
86 #include "BKE_object.h"
87 #include "BKE_utildefines.h"
88 #include "BKE_lattice.h"
89 #include "BKE_armature.h"
90 #include "BKE_curve.h"
91 #include "BKE_displist.h"
92
93 #include "BSE_view.h"
94 #include "BSE_edit.h"
95
96 #include "BLI_arithb.h"
97 #include "BLI_editVert.h"
98
99 #include "BDR_drawobject.h"
100
101 #include "blendef.h"
102
103 #include "mydevice.h"
104
105 #include "transform.h"
106 #include "transform_constraints.h"
107 #include "transform_generics.h"
108
109 extern ListBase editNurb;
110 extern ListBase editelems;
111
112 void recalcData();
113
114 /* ************************** CONSTRAINTS ************************* */
115 void getConstraintMatrix(TransInfo *t);
116
117 void axisProjection(float axis[3], float in[3], float out[3]) {
118         float n[3], vec[3], factor;
119         Normalise(axis);
120
121         VECCOPY(n, axis);
122         Mat4MulVecfl(G.vd->viewmat, n);
123         n[2] = G.vd->viewmat[3][2];
124         Mat4MulVecfl(G.vd->viewinv, n);
125
126         if (Inpf(axis, G.vd->viewinv[2]) != 1.0f) {
127                 Projf(vec, in, n);
128                 factor = Normalise(vec);
129                 factor /= Inpf(axis, vec);
130
131                 VecMulf(axis, factor);
132                 VECCOPY(out, axis);
133
134         }
135         else {
136                 out[0] = out[1] = out[2] = 0.0f;
137         }
138 }
139
140 void planeProjection(float in[3], float out[3]) {
141         float vec[3], factor, angle;
142
143         VecSubf(vec, out, in);
144         factor = Normalise(vec);
145         angle = Inpf(vec, G.vd->viewinv[2]);
146
147         if (angle * angle >= 0.000001f) {
148                 factor /= angle;
149
150                 VECCOPY(vec, G.vd->viewinv[2]);
151                 VecMulf(vec, factor);
152
153                 VecAddf(out, in, vec);
154         }
155 }
156
157 void applyAxisConstraintVec(TransInfo *t, TransData *td, float in[3], float out[3])
158 {
159         VECCOPY(out, in);
160         if (!td && t->con.mode & APPLYCON) {
161                 Mat3MulVecfl(t->con.imtx, out);
162                 if (!(out[0] == out[1] == out[2] == 0.0f)) {
163                         if (getConstraintSpaceDimension(t) == 2) {
164                                 planeProjection(in, out);
165                         }
166                         else if (getConstraintSpaceDimension(t) == 1) {
167                                 float c[3];
168
169                                 if (t->con.mode & CONAXIS0) {
170                                         VECCOPY(c, t->con.mtx[0]);
171                                 }
172                                 else if (t->con.mode & CONAXIS1) {
173                                         VECCOPY(c, t->con.mtx[1]);
174                                 }
175                                 else if (t->con.mode & CONAXIS2) {
176                                         VECCOPY(c, t->con.mtx[2]);
177                                 }
178                                 axisProjection(c, in, out);
179                         }
180                 }
181                 
182                 /* THIS IS NO GOOD, only works with global axis constraint */
183                 if (t->num.flags & NULLONE && !(t->con.mode & CONAXIS0))
184                         out[0] = 1.0f;
185
186                 if (t->num.flags & NULLONE && !(t->con.mode & CONAXIS1))
187                         out[1] = 1.0f;
188
189                 if (t->num.flags & NULLONE && !(t->con.mode & CONAXIS2))
190                         out[2] = 1.0f;
191         }
192 }
193
194 /*
195  * Generic callback for constant spacial constraints applied to rotations
196  * 
197  * The rotation axis is copied into VEC.
198  *
199  * In the case of single axis constraints, the rotation axis is directly the one constrained to.
200  * For planar constraints (2 axis), the rotation axis is the normal of the plane.
201  *
202  * The vector is then modified to always point away from the screen (in global space)
203  * This insures that the rotation is always logically following the mouse.
204  * (ie: not doing counterclockwise rotations when the mouse moves clockwise).
205  */
206
207 void applyAxisConstraintRot(TransInfo *t, TransData *td, float vec[3])
208 {
209         if (!td && t->con.mode & APPLYCON) {
210                 int mode = t->con.mode & (CONAXIS0|CONAXIS1|CONAXIS2);
211
212                 switch(mode) {
213                 case CONAXIS0:
214                 case (CONAXIS1|CONAXIS2):
215                         VECCOPY(vec, t->con.mtx[0]);
216                         break;
217                 case CONAXIS1:
218                 case (CONAXIS0|CONAXIS2):
219                         VECCOPY(vec, t->con.mtx[1]);
220                         break;
221                 case CONAXIS2:
222                 case (CONAXIS0|CONAXIS1):
223                         VECCOPY(vec, t->con.mtx[2]);
224                         break;
225                 }
226                 if (Inpf(vec, G.vd->viewinv[2]) > 0.0f) {
227                         VecMulf(vec, -1.0f);
228                 }
229         }
230 }
231
232 /*
233  * Returns the dimension of the constraint space.
234  * 
235  * For that reason, the flags always needs to be set to properly evaluate here,
236  * even if they aren't actually used in the callback function. (Which could happen
237  * for weird constraints not yet designed. Along a path for example.)
238  */
239
240 int getConstraintSpaceDimension(TransInfo *t)
241 {
242         int n = 0;
243
244         if (t->con.mode & CONAXIS0)
245                 n++;
246
247         if (t->con.mode & CONAXIS1)
248                 n++;
249
250         if (t->con.mode & CONAXIS2)
251                 n++;
252
253         return n;
254 }
255
256 void BIF_setSingleAxisConstraint(float vec[3]) {
257         TransInfo *t = BIF_GetTransInfo();
258         float space[3][3], v[3];
259         VECCOPY(space[0], vec);
260
261         v[0] = vec[2];
262         v[1] = vec[0];
263         v[2] = vec[1];
264
265         Crossf(space[1], vec, v);
266         Crossf(space[2], vec, space[1]);
267
268         Mat3CpyMat3(t->con.mtx, space);
269         t->con.mode = (CONAXIS0|APPLYCON);
270         getConstraintMatrix(t);
271
272         VECCOPY(t->con.center, t->center);
273         if (G.obedit) {
274                 Mat4MulVecfl(G.obedit->obmat, t->con.center);
275         }
276
277         t->con.applyVec = applyAxisConstraintVec;
278         t->con.applyRot = applyAxisConstraintRot;
279         t->redraw = 1;
280 }
281
282 void setConstraint(TransInfo *t, float space[3][3], int mode) {
283         Mat3CpyMat3(t->con.mtx, space);
284         t->con.mode = mode;
285         getConstraintMatrix(t);
286
287         VECCOPY(t->con.center, t->center);
288         if (G.obedit) {
289                 Mat4MulVecfl(G.obedit->obmat, t->con.center);
290         }
291
292         t->con.applyVec = applyAxisConstraintVec;
293         t->con.applyRot = applyAxisConstraintRot;
294         t->redraw = 1;
295 }
296
297 void BIF_drawConstraint()
298 {
299         int i = -1;
300         TransInfo *t = BIF_GetTransInfo();
301         TransCon *tc = &(t->con);
302
303         if (tc->mode == 0)
304                 return;
305
306         if (!(tc->mode & APPLYCON)) {
307                 i = nearestAxisIndex(t);
308         }
309
310         if (tc->mode & CONAXIS0) {
311                 if (i == 0)
312                         drawLine(tc->center, tc->mtx[0], 255 - 'x');
313                 else
314                         drawLine(tc->center, tc->mtx[0], 'x');
315         }
316         if (tc->mode & CONAXIS1) {
317                 if (i == 1)
318                         drawLine(tc->center, tc->mtx[1], 255 - 'y');
319                 else
320                         drawLine(tc->center, tc->mtx[1], 'y');
321         }
322         if (tc->mode & CONAXIS2) {
323                 if (i == 2)
324                         drawLine(tc->center, tc->mtx[2], 255 - 'z');
325                 else
326                         drawLine(tc->center, tc->mtx[2], 'z');
327         }
328
329 }
330
331 /* called from drawview.c, as an extra per-window draw option */
332 void BIF_drawPropCircle()
333 {
334         TransInfo *t = BIF_GetTransInfo();
335
336         if (G.f & G_PROPORTIONAL) {
337                 float tmat[4][4], imat[4][4];
338
339                 BIF_ThemeColor(TH_GRID);
340                 
341                 /* if editmode we need to go into object space */
342                 if(G.obedit) mymultmatrix(G.obedit->obmat);
343                 
344                 mygetmatrix(tmat);
345                 Mat4Invert(imat, tmat);
346                 
347                 drawcircball(t->center, t->propsize, imat);
348                 
349                 /* if editmode we restore */
350                 if(G.obedit) myloadmatrix(G.vd->viewmat);
351         }
352 }
353
354 void getConstraintMatrix(TransInfo *t)
355 {
356         Mat3Inv(t->con.imtx, t->con.mtx);
357
358         if (!(t->con.mode & CONAXIS0)) {
359                 t->con.imtx[0][0]               =
360                         t->con.imtx[0][1]       =
361                         t->con.imtx[0][2]       = 0.0f;
362         }
363
364         if (!(t->con.mode & CONAXIS1)) {
365                 t->con.imtx[1][0]               =
366                         t->con.imtx[1][1]       =
367                         t->con.imtx[1][2]       = 0.0f;
368         }
369
370         if (!(t->con.mode & CONAXIS2)) {
371                 t->con.imtx[2][0]               =
372                         t->con.imtx[2][1]       =
373                         t->con.imtx[2][2]       = 0.0f;
374         }
375 }
376
377 void selectConstraint(TransInfo *t)
378 {
379         Mat3One(t->con.mtx);
380         Mat3One(t->con.imtx);
381         t->con.mode |= CONAXIS0;
382         t->con.mode |= CONAXIS1;
383         t->con.mode |= CONAXIS2;
384         t->con.mode &= ~APPLYCON;
385         VECCOPY(t->con.center, t->center);
386         if (G.obedit) {
387                 Mat4MulVecfl(G.obedit->obmat, t->con.center);
388         }
389 }
390
391 int nearestAxisIndex(TransInfo *t)
392 {
393         short coord[2];
394         float mvec[3], axis[3], center[3], proj[3];
395         float len[3];
396         int i;
397
398         VECCOPY(center, t->center);
399         if (G.obedit) {
400                 Mat4MulVecfl(G.obedit->obmat, center);
401         }
402
403         getmouseco_areawin(coord);
404         mvec[0] = (float)(coord[0] - t->center2d[0]);
405         mvec[1] = (float)(coord[1] - t->center2d[1]);
406         mvec[2] = 0.0f;
407
408         for (i = 0; i<3; i++) {
409                 VECCOPY(axis, t->con.mtx[i]);
410                 VecAddf(axis, axis, center);
411                 project_short_noclip(axis, coord);
412                 axis[0] = (float)(coord[0] - t->center2d[0]);
413                 axis[1] = (float)(coord[1] - t->center2d[1]);
414                 axis[2] = 0.0f;
415
416                 if (Normalise(axis) != 0.0f) {
417                         Projf(proj, mvec, axis);
418                         VecSubf(axis, mvec, proj);
419                         len[i] = Normalise(axis);
420                 }
421                 else {
422                         len[i] = 10000000000.0f;
423                 }
424         }
425
426         if (len[0] < len[1] && len[0] < len[2]) {
427                 return 0;
428         }
429         else if (len[1] < len[0] && len[1] < len[2]) {
430                 return 1;
431         }
432         else if (len[2] < len[1] && len[2] < len[0]) {
433                 return 2;
434         }
435         return -1;
436 }
437
438 void chooseConstraint(TransInfo *t)
439 {
440         t->con.mode &= ~CONAXIS0;
441         t->con.mode &= ~CONAXIS1;
442         t->con.mode &= ~CONAXIS2;
443
444         switch(nearestAxisIndex(t)) {
445         case 0:
446                 t->con.mode |= CONAXIS0;
447                 break;
448         case 1:
449                 t->con.mode |= CONAXIS1;
450                 break;
451         case 2:
452                 t->con.mode |= CONAXIS2;
453                 break;
454         }
455
456         t->con.mode |= APPLYCON;
457         VECCOPY(t->con.center, t->center);
458
459         getConstraintMatrix(t);
460         t->con.applyVec = applyAxisConstraintVec;
461         t->con.applyRot = applyAxisConstraintRot;
462         t->redraw = 1;
463 }