4 * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
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
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.
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.
23 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24 * All rights reserved.
26 * The Original Code is: all of this file.
28 * Contributor(s): none yet.
30 * ***** END GPL/BL DUAL LICENSE BLOCK *****
47 #include "MEM_guardedalloc.h"
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"
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"
80 #include "BIF_editlattice.h"
81 #include "BIF_editarmature.h"
82 #include "BIF_editmesh.h"
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"
95 #include "BLI_arithb.h"
96 #include "BLI_editVert.h"
98 #include "BDR_drawobject.h"
102 #include "mydevice.h"
104 #include "transform.h"
105 #include "transform_constraints.h"
106 #include "transform_generics.h"
108 extern ListBase editNurb;
109 extern ListBase editelems;
113 /* ************************** CONSTRAINTS ************************* */
114 void getConstraintMatrix(TransInfo *t);
116 void constraintNumInput(TransInfo *t, float vec[3])
118 int mode = t->con.mode;
119 float nval = (t->flag & T_NULL_ONE)?1.0f:0.0f;
121 if (getConstraintSpaceDimension(t) == 2) {
122 if (mode & (CON_AXIS0|CON_AXIS1)) {
125 else if (mode & (CON_AXIS1|CON_AXIS2)) {
130 else if (mode & (CON_AXIS0|CON_AXIS2)) {
135 else if (getConstraintSpaceDimension(t) == 1) {
136 if (mode & CON_AXIS0) {
140 else if (mode & CON_AXIS1) {
145 else if (mode & CON_AXIS2) {
153 static void postConstraintChecks(TransInfo *t, float vec[3], float pvec[3]) {
156 Mat3MulVecfl(t->con.imtx, vec);
160 if (t->num.flag & T_NULL_ONE) {
161 if (!(t->con.mode & CON_AXIS0))
164 if (!(t->con.mode & CON_AXIS1))
167 if (!(t->con.mode & CON_AXIS2))
171 if (hasNumInput(&t->num)) {
172 applyNumInput(&t->num, vec);
173 constraintNumInput(t, vec);
176 if (t->con.mode & CON_AXIS0) {
179 if (t->con.mode & CON_AXIS1) {
182 if (t->con.mode & CON_AXIS2) {
186 Mat3MulVecfl(t->con.mtx, vec);
190 static void axisProjection(TransInfo *t, float axis[3], float in[3], float out[3]) {
191 float norm[3], n[3], vec[3], factor;
193 VecAddf(vec, in, t->con.center);
194 getViewVector(vec, norm);
199 Mat4MulVecfl(t->viewmat, n);
200 n[2] = t->viewmat[3][2];
201 Mat4MulVecfl(t->viewinv, n);
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;
215 VecMulf(out, -factor); /* -factor makes move down going backwards */
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) {
221 factor = Normalise(vec);
222 // prevent NaN for 0.0/0.0
224 factor /= Inpf(axis, vec);
226 VecMulf(axis, factor);
232 static void planeProjection(TransInfo *t, float in[3], float out[3]) {
233 float vec[3], factor, angle, norm[3];
235 VecAddf(vec, in, t->con.center);
236 getViewVector(vec, norm);
238 VecSubf(vec, out, in);
239 factor = Normalise(vec);
240 angle = Inpf(vec, norm);
242 if (angle * angle >= 0.000001f) {
246 VecMulf(vec, factor);
248 VecAddf(out, in, vec);
253 * Generic callback for constant spacial constraints applied to linear motion
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)
261 static void applyAxisConstraintVec(TransInfo *t, TransData *td, float in[3], float out[3], float pvec[3])
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);
271 else if (getConstraintSpaceDimension(t) == 1) {
274 if (t->con.mode & CON_AXIS0) {
275 VECCOPY(c, t->con.mtx[0]);
277 else if (t->con.mode & CON_AXIS1) {
278 VECCOPY(c, t->con.mtx[1]);
280 else if (t->con.mode & CON_AXIS2) {
281 VECCOPY(c, t->con.mtx[2]);
283 axisProjection(t, c, in, out);
285 postConstraintChecks(t, out, pvec);
290 * Generic callback for object based spacial constraints applied to linear motion
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)
297 * Further down, that vector is mapped to each data's space.
300 static void applyObjectConstraintVec(TransInfo *t, TransData *td, float in[3], float out[3], float pvec[3])
303 if (t->con.mode & CON_APPLY) {
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);
311 else if (getConstraintSpaceDimension(t) == 1) {
314 if (t->con.mode & CON_AXIS0) {
315 VECCOPY(c, t->con.mtx[0]);
317 else if (t->con.mode & CON_AXIS1) {
318 VECCOPY(c, t->con.mtx[1]);
320 else if (t->con.mode & CON_AXIS2) {
321 VECCOPY(c, t->con.mtx[2]);
323 axisProjection(t, c, in, out);
325 postConstraintChecks(t, out, pvec);
329 Mat3MulVecfl(td->axismtx, out);
335 * Generic callback for constant spacial constraints applied to resize motion
340 static void applyAxisConstraintSize(TransInfo *t, TransData *td, float smat[3][3])
342 if (!td && t->con.mode & CON_APPLY) {
345 if (!(t->con.mode & CON_AXIS0)) {
348 if (!(t->con.mode & CON_AXIS1)) {
351 if (!(t->con.mode & CON_AXIS2)) {
355 Mat3MulMat3(tmat, smat, t->con.imtx);
356 Mat3MulMat3(smat, t->con.mtx, tmat);
361 * Callback for object based spacial constraints applied to resize motion
366 static void applyObjectConstraintSize(TransInfo *t, TransData *td, float smat[3][3])
368 if (td && t->con.mode & CON_APPLY) {
372 Mat3Inv(imat, td->axismtx);
374 if (!(t->con.mode & CON_AXIS0)) {
377 if (!(t->con.mode & CON_AXIS1)) {
380 if (!(t->con.mode & CON_AXIS2)) {
384 Mat3MulMat3(tmat, smat, imat);
385 Mat3MulMat3(smat, td->axismtx, tmat);
390 * Generic callback for constant spacial constraints applied to rotations
392 * The rotation axis is copied into VEC.
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.
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).
403 static void applyAxisConstraintRot(TransInfo *t, TransData *td, float vec[3])
405 if (!td && t->con.mode & CON_APPLY) {
406 int mode = t->con.mode & (CON_AXIS0|CON_AXIS1|CON_AXIS2);
410 case (CON_AXIS1|CON_AXIS2):
411 VECCOPY(vec, t->con.mtx[0]);
414 case (CON_AXIS0|CON_AXIS2):
415 VECCOPY(vec, t->con.mtx[1]);
418 case (CON_AXIS0|CON_AXIS1):
419 VECCOPY(vec, t->con.mtx[2]);
422 if (!(mode & CON_NOFLIP)) {
423 if (Inpf(vec, G.vd->viewinv[2]) > 0.0f) {
431 * Callback for object based spacial constraints applied to rotations
433 * The rotation axis is copied into VEC.
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.
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).
444 static void applyObjectConstraintRot(TransInfo *t, TransData *td, float vec[3])
446 if (td && t->con.mode & CON_APPLY) {
447 int mode = t->con.mode & (CON_AXIS0|CON_AXIS1|CON_AXIS2);
451 case (CON_AXIS1|CON_AXIS2):
452 VECCOPY(vec, td->axismtx[0]);
455 case (CON_AXIS0|CON_AXIS2):
456 VECCOPY(vec, td->axismtx[1]);
459 case (CON_AXIS0|CON_AXIS1):
460 VECCOPY(vec, td->axismtx[2]);
463 if (!(mode & CON_NOFLIP)) {
464 if (Inpf(vec, G.vd->viewinv[2]) > 0.0f) {
471 static void drawObjectConstraint(TransInfo *t) {
473 TransData * td = t->data;
475 if (t->con.mode & CON_AXIS0) {
476 drawLine(td->ob->obmat[3], td->axismtx[0], 'x', DRAWLIGHT);
478 if (t->con.mode & CON_AXIS1) {
479 drawLine(td->ob->obmat[3], td->axismtx[1], 'y', DRAWLIGHT);
481 if (t->con.mode & CON_AXIS2) {
482 drawLine(td->ob->obmat[3], td->axismtx[2], 'z', DRAWLIGHT);
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);
490 if (t->con.mode & CON_AXIS1) {
491 drawLine(td->ob->obmat[3], td->axismtx[1], 'y', 0);
493 if (t->con.mode & CON_AXIS2) {
494 drawLine(td->ob->obmat[3], td->axismtx[2], 'z', 0);
500 * Returns the dimension of the constraint space.
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.)
507 int getConstraintSpaceDimension(TransInfo *t)
511 if (t->con.mode & CON_AXIS0)
514 if (t->con.mode & CON_AXIS1)
517 if (t->con.mode & CON_AXIS2)
522 Someone willing to do it criptically could do the following instead:
524 return t->con & (CON_AXIS0|CON_AXIS1|CON_AXIS2);
526 Based on the assumptions that the axis flags are one after the other and start at 1
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);
534 getConstraintMatrix(t);
538 t->con.applyVec = applyAxisConstraintVec;
539 t->con.applySize = applyAxisConstraintSize;
540 t->con.applyRot = applyAxisConstraintRot;
544 void setLocalConstraint(TransInfo *t, int mode, const char text[]) {
545 if (t->flag & T_EDIT) {
547 Mat3CpyMat4(obmat, G.obedit->obmat);
548 setConstraint(t, obmat, mode, text);
552 setConstraint(t, t->data->axismtx, mode, text);
555 strncpy(t->con.text + 1, text, 48);
556 Mat3CpyMat3(t->con.mtx, t->data->axismtx);
558 getConstraintMatrix(t);
562 t->con.drawExtra = drawObjectConstraint;
563 t->con.applyVec = applyObjectConstraintVec;
564 t->con.applySize = applyObjectConstraintSize;
565 t->con.applyRot = applyObjectConstraintRot;
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];
576 VECCOPY(space[0], vec);
582 Crossf(space[1], vec, v);
583 Crossf(space[2], vec, space[1]);
588 Mat3CpyMat3(t->con.mtx, space);
589 t->con.mode = (CON_AXIS0|CON_APPLY);
590 getConstraintMatrix(t);
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
596 t->con.drawExtra = NULL;
597 t->con.applyVec = applyAxisConstraintVec;
598 t->con.applySize = applyAxisConstraintSize;
599 t->con.applyRot = applyAxisConstraintRot;
603 void BIF_setDualAxisConstraint(float vec1[3], float vec2[3]) {
604 TransInfo *t = BIF_GetTransInfo();
607 VECCOPY(space[0], vec1);
608 VECCOPY(space[1], vec2);
609 Crossf(space[2], space[0], space[1]);
612 Mat3CpyMat3(t->con.mtx, space);
613 t->con.mode = (CON_AXIS0|CON_AXIS1|CON_APPLY);
614 getConstraintMatrix(t);
616 t->con.drawExtra = NULL;
617 t->con.applyVec = applyAxisConstraintVec;
618 t->con.applySize = applyAxisConstraintSize;
619 t->con.applyRot = applyAxisConstraintRot;
624 void BIF_drawConstraint(void)
626 TransInfo *t = BIF_GetTransInfo();
627 TransCon *tc = &(t->con);
629 if (!(tc->mode & CON_APPLY))
631 if (t->flag & T_USES_MANIPULATOR)
634 /* nasty exception for Z constraint in camera view */
635 if( (t->flag & T_OBJECT) && G.vd->camera==OBACT && G.vd->persp>1)
642 if (tc->mode & CON_SELECT) {
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);
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);
654 draw_manipulator_ext(curarea, t->mode, 'c', 2, tc->center, tc->mtx);
657 glDisable(GL_DEPTH_TEST);
659 glBegin(GL_LINE_STRIP);
660 glVertex3fv(tc->center);
664 if(G.zbuf) glEnable(GL_DEPTH_TEST); // warning for global!
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);
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);
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);
685 /* called from drawview.c, as an extra per-window draw option */
686 void BIF_drawPropCircle()
688 TransInfo *t = BIF_GetTransInfo();
690 if (t->flag & T_PROP_EDIT) {
691 float tmat[4][4], imat[4][4];
693 BIF_ThemeColor(TH_GRID);
695 /* if editmode we need to go into object space */
696 if(G.obedit) mymultmatrix(G.obedit->obmat);
699 Mat4Invert(imat, tmat);
701 drawcircball(t->center, t->propsize, imat);
703 /* if editmode we restore */
704 if(G.obedit) myloadmatrix(G.vd->viewmat);
708 void initConstraint(TransInfo *t) {
709 if (t->con.mode & CON_APPLY) {
714 void startConstraint(TransInfo *t) {
715 t->con.mode |= CON_APPLY;
717 t->num.idx_max = MIN2(getConstraintSpaceDimension(t) - 1, t->idx_max);
720 void stopConstraint(TransInfo *t) {
721 t->con.mode &= ~CON_APPLY;
723 t->num.idx_max = t->idx_max;
726 void getConstraintMatrix(TransInfo *t)
729 Mat3Inv(t->con.imtx, t->con.mtx);
730 Mat3One(t->con.pmtx);
732 if (!(t->con.mode & CON_AXIS0)) {
735 t->con.pmtx[0][2] = 0.0f;
738 if (!(t->con.mode & CON_AXIS1)) {
741 t->con.pmtx[1][2] = 0.0f;
744 if (!(t->con.mode & CON_AXIS2)) {
747 t->con.pmtx[2][2] = 0.0f;
750 Mat3MulMat3(mat, t->con.pmtx, t->con.imtx);
751 Mat3MulMat3(t->con.pmtx, t->con.mtx, mat);
754 void initSelectConstraint(TransInfo *t)
757 Mat3One(t->con.pmtx);
758 t->con.mode |= CON_APPLY;
759 t->con.mode |= CON_SELECT;
762 t->con.drawExtra = NULL;
763 t->con.applyVec = applyAxisConstraintVec;
764 t->con.applySize = applyAxisConstraintSize;
765 t->con.applyRot = applyAxisConstraintRot;
768 void selectConstraint(TransInfo *t) {
769 if (t->con.mode & CON_SELECT) {
775 void postSelectConstraint(TransInfo *t)
777 if (!(t->con.mode & CON_SELECT))
780 t->con.mode &= ~CON_AXIS0;
781 t->con.mode &= ~CON_AXIS1;
782 t->con.mode &= ~CON_AXIS2;
783 t->con.mode &= ~CON_SELECT;
791 void setNearestAxis(TransInfo *t)
794 float mvec[3], axis[3], proj[3];
798 t->con.mode &= ~CON_AXIS0;
799 t->con.mode &= ~CON_AXIS1;
800 t->con.mode &= ~CON_AXIS2;
802 getmouseco_areawin(coord);
803 mvec[0] = (float)(coord[0] - t->con.imval[0]);
804 mvec[1] = (float)(coord[1] - t->con.imval[1]);
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]);
815 if (Normalise(axis) != 0.0f) {
816 Projf(proj, mvec, axis);
817 VecSubf(axis, mvec, proj);
818 len[i] = Normalise(axis);
821 len[i] = 10000000000.0f;
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");
831 t->con.mode |= CON_AXIS0;
832 strcpy(t->con.text, " along global X");
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");
841 t->con.mode |= CON_AXIS1;
842 strcpy(t->con.text, " along global Y");
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");
851 t->con.mode |= CON_AXIS2;
852 strcpy(t->con.text, " along global Z");
855 getConstraintMatrix(t);