|
Blender
V2.59
|
00001 /* 00002 * $Id: transform_constraints.c 37836 2011-06-27 03:36:14Z campbellbarton $ 00003 * 00004 * ***** BEGIN GPL LICENSE BLOCK ***** 00005 * 00006 * This program is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU General Public License 00008 * as published by the Free Software Foundation; either version 2 00009 * of the License, or (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software Foundation, 00018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00019 * 00020 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. 00021 * All rights reserved. 00022 * 00023 * The Original Code is: all of this file. 00024 * 00025 * Contributor(s): none yet. 00026 * 00027 * ***** END GPL LICENSE BLOCK ***** 00028 */ 00029 00035 #include <stdlib.h> 00036 #include <stdio.h> 00037 #include <string.h> 00038 #include <math.h> 00039 00040 #ifndef WIN32 00041 #include <unistd.h> 00042 #else 00043 #include <io.h> 00044 #endif 00045 00046 00047 #include "DNA_object_types.h" 00048 #include "DNA_scene_types.h" 00049 #include "DNA_screen_types.h" 00050 #include "DNA_space_types.h" 00051 #include "DNA_view3d_types.h" 00052 00053 #include "BIF_gl.h" 00054 #include "BIF_glutil.h" 00055 00056 #include "BKE_context.h" 00057 00058 00059 #include "ED_image.h" 00060 #include "ED_view3d.h" 00061 00062 #include "BLI_math.h" 00063 #include "BLI_utildefines.h" 00064 00065 //#include "blendef.h" 00066 // 00067 //#include "mydevice.h" 00068 00069 #include "UI_resources.h" 00070 00071 00072 #include "transform.h" 00073 00074 static void drawObjectConstraint(TransInfo *t); 00075 00076 /* ************************** CONSTRAINTS ************************* */ 00077 static void constraintAutoValues(TransInfo *t, float vec[3]) 00078 { 00079 int mode = t->con.mode; 00080 if (mode & CON_APPLY) 00081 { 00082 float nval = (t->flag & T_NULL_ONE)?1.0f:0.0f; 00083 00084 if ((mode & CON_AXIS0) == 0) 00085 { 00086 vec[0] = nval; 00087 } 00088 if ((mode & CON_AXIS1) == 0) 00089 { 00090 vec[1] = nval; 00091 } 00092 if ((mode & CON_AXIS2) == 0) 00093 { 00094 vec[2] = nval; 00095 } 00096 } 00097 } 00098 00099 void constraintNumInput(TransInfo *t, float vec[3]) 00100 { 00101 int mode = t->con.mode; 00102 if (mode & CON_APPLY) { 00103 float nval = (t->flag & T_NULL_ONE)?1.0f:0.0f; 00104 00105 if (getConstraintSpaceDimension(t) == 2) { 00106 int axis = mode & (CON_AXIS0|CON_AXIS1|CON_AXIS2); 00107 if (axis == (CON_AXIS0|CON_AXIS1)) { 00108 /* vec[0] = vec[0]; */ /* same */ 00109 /* vec[1] = vec[1]; */ /* same */ 00110 vec[2] = nval; 00111 } 00112 else if (axis == (CON_AXIS1|CON_AXIS2)) { 00113 vec[2] = vec[1]; 00114 vec[1] = vec[0]; 00115 vec[0] = nval; 00116 } 00117 else if (axis == (CON_AXIS0|CON_AXIS2)) { 00118 /* vec[0] = vec[0]; */ /* same */ 00119 vec[2] = vec[1]; 00120 vec[1] = nval; 00121 } 00122 } 00123 else if (getConstraintSpaceDimension(t) == 1) { 00124 if (mode & CON_AXIS0) { 00125 /* vec[0] = vec[0]; */ /* same */ 00126 vec[1] = nval; 00127 vec[2] = nval; 00128 } 00129 else if (mode & CON_AXIS1) { 00130 vec[1] = vec[0]; 00131 vec[0] = nval; 00132 vec[2] = nval; 00133 } 00134 else if (mode & CON_AXIS2) { 00135 vec[2] = vec[0]; 00136 vec[0] = nval; 00137 vec[1] = nval; 00138 } 00139 } 00140 } 00141 } 00142 00143 static void postConstraintChecks(TransInfo *t, float vec[3], float pvec[3]) { 00144 int i = 0; 00145 00146 mul_m3_v3(t->con.imtx, vec); 00147 00148 snapGrid(t, vec); 00149 00150 if (t->num.flag & T_NULL_ONE) { 00151 if (!(t->con.mode & CON_AXIS0)) 00152 vec[0] = 1.0f; 00153 00154 if (!(t->con.mode & CON_AXIS1)) 00155 vec[1] = 1.0f; 00156 00157 if (!(t->con.mode & CON_AXIS2)) 00158 vec[2] = 1.0f; 00159 } 00160 00161 if (hasNumInput(&t->num)) { 00162 applyNumInput(&t->num, vec); 00163 removeAspectRatio(t, vec); 00164 constraintNumInput(t, vec); 00165 } 00166 00167 /* autovalues is operator param, use that directly but not if snapping is forced */ 00168 if (t->flag & T_AUTOVALUES && (t->tsnap.status & SNAP_FORCED) == 0) 00169 { 00170 mul_v3_m3v3(vec, t->con.imtx, t->auto_values); 00171 constraintAutoValues(t, vec); 00172 /* inverse transformation at the end */ 00173 } 00174 00175 if (t->con.mode & CON_AXIS0) { 00176 pvec[i++] = vec[0]; 00177 } 00178 if (t->con.mode & CON_AXIS1) { 00179 pvec[i++] = vec[1]; 00180 } 00181 if (t->con.mode & CON_AXIS2) { 00182 pvec[i++] = vec[2]; 00183 } 00184 00185 mul_m3_v3(t->con.mtx, vec); 00186 } 00187 00188 static void viewAxisCorrectCenter(TransInfo *t, float t_con_center[3]) 00189 { 00190 if(t->spacetype == SPACE_VIEW3D) { 00191 // View3D *v3d = t->sa->spacedata.first; 00192 const float min_dist= 1.0f; // v3d->near; 00193 float dir[3]; 00194 float l; 00195 00196 sub_v3_v3v3(dir, t_con_center, t->viewinv[3]); 00197 if(dot_v3v3(dir, t->viewinv[2]) < 0.0f) { 00198 negate_v3(dir); 00199 } 00200 project_v3_v3v3(dir, dir, t->viewinv[2]); 00201 00202 l= len_v3(dir); 00203 00204 if(l < min_dist) { 00205 float diff[3]; 00206 normalize_v3_v3(diff, t->viewinv[2]); 00207 mul_v3_fl(diff, min_dist - l); 00208 00209 sub_v3_v3(t_con_center, diff); 00210 } 00211 } 00212 } 00213 00214 static void axisProjection(TransInfo *t, float axis[3], float in[3], float out[3]) { 00215 float norm[3], vec[3], factor, angle; 00216 float t_con_center[3]; 00217 00218 if(in[0]==0.0f && in[1]==0.0f && in[2]==0.0f) 00219 return; 00220 00221 copy_v3_v3(t_con_center, t->con.center); 00222 00223 /* checks for center being too close to the view center */ 00224 viewAxisCorrectCenter(t, t_con_center); 00225 00226 angle = fabsf(angle_v3v3(axis, t->viewinv[2])); 00227 if (angle > (float)M_PI / 2.0f) { 00228 angle = (float)M_PI - angle; 00229 } 00230 angle = RAD2DEGF(angle); 00231 00232 /* For when view is parallel to constraint... will cause NaNs otherwise 00233 So we take vertical motion in 3D space and apply it to the 00234 constraint axis. Nice for camera grab + MMB */ 00235 if(angle < 5.0f) { 00236 project_v3_v3v3(vec, in, t->viewinv[1]); 00237 factor = dot_v3v3(t->viewinv[1], vec) * 2.0f; 00238 /* since camera distance is quite relative, use quadratic relationship. holding shift can compensate */ 00239 if(factor<0.0f) factor*= -factor; 00240 else factor*= factor; 00241 00242 VECCOPY(out, axis); 00243 normalize_v3(out); 00244 mul_v3_fl(out, -factor); /* -factor makes move down going backwards */ 00245 } 00246 else { 00247 float v[3], i1[3], i2[3]; 00248 float v2[3], v4[3]; 00249 float norm_center[3]; 00250 float plane[3]; 00251 00252 getViewVector(t, t_con_center, norm_center); 00253 cross_v3_v3v3(plane, norm_center, axis); 00254 00255 project_v3_v3v3(vec, in, plane); 00256 sub_v3_v3v3(vec, in, vec); 00257 00258 add_v3_v3v3(v, vec, t_con_center); 00259 getViewVector(t, v, norm); 00260 00261 /* give arbitrary large value if projection is impossible */ 00262 factor = dot_v3v3(axis, norm); 00263 if (1.0f - fabsf(factor) < 0.0002f) { 00264 VECCOPY(out, axis); 00265 if (factor > 0) { 00266 mul_v3_fl(out, 1000000000.0f); 00267 } else { 00268 mul_v3_fl(out, -1000000000.0f); 00269 } 00270 } else { 00271 add_v3_v3v3(v2, t_con_center, axis); 00272 add_v3_v3v3(v4, v, norm); 00273 00274 isect_line_line_v3(t_con_center, v2, v, v4, i1, i2); 00275 00276 sub_v3_v3v3(v, i2, v); 00277 00278 sub_v3_v3v3(out, i1, t_con_center); 00279 00280 /* possible some values become nan when 00281 * viewpoint and object are both zero */ 00282 if(!finite(out[0])) out[0]= 0.0f; 00283 if(!finite(out[1])) out[1]= 0.0f; 00284 if(!finite(out[2])) out[2]= 0.0f; 00285 } 00286 } 00287 } 00288 00289 static void planeProjection(TransInfo *t, float in[3], float out[3]) { 00290 float vec[3], factor, norm[3]; 00291 00292 add_v3_v3v3(vec, in, t->con.center); 00293 getViewVector(t, vec, norm); 00294 00295 sub_v3_v3v3(vec, out, in); 00296 00297 factor = dot_v3v3(vec, norm); 00298 if (fabs(factor) <= 0.001) { 00299 return; /* prevent divide by zero */ 00300 } 00301 factor = dot_v3v3(vec, vec) / factor; 00302 00303 VECCOPY(vec, norm); 00304 mul_v3_fl(vec, factor); 00305 00306 add_v3_v3v3(out, in, vec); 00307 } 00308 00309 /* 00310 * Generic callback for constant spacial constraints applied to linear motion 00311 * 00312 * The IN vector in projected into the constrained space and then further 00313 * projected along the view vector. 00314 * (in perspective mode, the view vector is relative to the position on screen) 00315 * 00316 */ 00317 00318 static void applyAxisConstraintVec(TransInfo *t, TransData *td, float in[3], float out[3], float pvec[3]) 00319 { 00320 VECCOPY(out, in); 00321 if (!td && t->con.mode & CON_APPLY) { 00322 mul_m3_v3(t->con.pmtx, out); 00323 00324 // With snap, a projection is alright, no need to correct for view alignment 00325 if (!(t->tsnap.mode != SCE_SNAP_MODE_INCREMENT && activeSnap(t))) { 00326 if (getConstraintSpaceDimension(t) == 2) { 00327 if (out[0] != 0.0f || out[1] != 0.0f || out[2] != 0.0f) { 00328 planeProjection(t, in, out); 00329 } 00330 } 00331 else if (getConstraintSpaceDimension(t) == 1) { 00332 float c[3]; 00333 00334 if (t->con.mode & CON_AXIS0) { 00335 VECCOPY(c, t->con.mtx[0]); 00336 } 00337 else if (t->con.mode & CON_AXIS1) { 00338 VECCOPY(c, t->con.mtx[1]); 00339 } 00340 else if (t->con.mode & CON_AXIS2) { 00341 VECCOPY(c, t->con.mtx[2]); 00342 } 00343 axisProjection(t, c, in, out); 00344 } 00345 } 00346 postConstraintChecks(t, out, pvec); 00347 } 00348 } 00349 00350 /* 00351 * Generic callback for object based spatial constraints applied to linear motion 00352 * 00353 * At first, the following is applied to the first data in the array 00354 * The IN vector in projected into the constrained space and then further 00355 * projected along the view vector. 00356 * (in perspective mode, the view vector is relative to the position on screen) 00357 * 00358 * Further down, that vector is mapped to each data's space. 00359 */ 00360 00361 static void applyObjectConstraintVec(TransInfo *t, TransData *td, float in[3], float out[3], float pvec[3]) 00362 { 00363 VECCOPY(out, in); 00364 if (t->con.mode & CON_APPLY) { 00365 if (!td) { 00366 mul_m3_v3(t->con.pmtx, out); 00367 if (getConstraintSpaceDimension(t) == 2) { 00368 if (out[0] != 0.0f || out[1] != 0.0f || out[2] != 0.0f) { 00369 planeProjection(t, in, out); 00370 } 00371 } 00372 else if (getConstraintSpaceDimension(t) == 1) { 00373 float c[3]; 00374 00375 if (t->con.mode & CON_AXIS0) { 00376 VECCOPY(c, t->con.mtx[0]); 00377 } 00378 else if (t->con.mode & CON_AXIS1) { 00379 VECCOPY(c, t->con.mtx[1]); 00380 } 00381 else if (t->con.mode & CON_AXIS2) { 00382 VECCOPY(c, t->con.mtx[2]); 00383 } 00384 axisProjection(t, c, in, out); 00385 } 00386 postConstraintChecks(t, out, pvec); 00387 VECCOPY(out, pvec); 00388 } 00389 else { 00390 int i=0; 00391 00392 out[0] = out[1] = out[2] = 0.0f; 00393 if (t->con.mode & CON_AXIS0) { 00394 out[0] = in[i++]; 00395 } 00396 if (t->con.mode & CON_AXIS1) { 00397 out[1] = in[i++]; 00398 } 00399 if (t->con.mode & CON_AXIS2) { 00400 out[2] = in[i++]; 00401 } 00402 mul_m3_v3(td->axismtx, out); 00403 } 00404 } 00405 } 00406 00407 /* 00408 * Generic callback for constant spacial constraints applied to resize motion 00409 * 00410 * 00411 */ 00412 00413 static void applyAxisConstraintSize(TransInfo *t, TransData *td, float smat[3][3]) 00414 { 00415 if (!td && t->con.mode & CON_APPLY) { 00416 float tmat[3][3]; 00417 00418 if (!(t->con.mode & CON_AXIS0)) { 00419 smat[0][0] = 1.0f; 00420 } 00421 if (!(t->con.mode & CON_AXIS1)) { 00422 smat[1][1] = 1.0f; 00423 } 00424 if (!(t->con.mode & CON_AXIS2)) { 00425 smat[2][2] = 1.0f; 00426 } 00427 00428 mul_m3_m3m3(tmat, smat, t->con.imtx); 00429 mul_m3_m3m3(smat, t->con.mtx, tmat); 00430 } 00431 } 00432 00433 /* 00434 * Callback for object based spacial constraints applied to resize motion 00435 * 00436 * 00437 */ 00438 00439 static void applyObjectConstraintSize(TransInfo *t, TransData *td, float smat[3][3]) 00440 { 00441 if (td && t->con.mode & CON_APPLY) { 00442 float tmat[3][3]; 00443 float imat[3][3]; 00444 00445 invert_m3_m3(imat, td->axismtx); 00446 00447 if (!(t->con.mode & CON_AXIS0)) { 00448 smat[0][0] = 1.0f; 00449 } 00450 if (!(t->con.mode & CON_AXIS1)) { 00451 smat[1][1] = 1.0f; 00452 } 00453 if (!(t->con.mode & CON_AXIS2)) { 00454 smat[2][2] = 1.0f; 00455 } 00456 00457 mul_m3_m3m3(tmat, smat, imat); 00458 mul_m3_m3m3(smat, td->axismtx, tmat); 00459 } 00460 } 00461 00462 /* 00463 * Generic callback for constant spacial constraints applied to rotations 00464 * 00465 * The rotation axis is copied into VEC. 00466 * 00467 * In the case of single axis constraints, the rotation axis is directly the one constrained to. 00468 * For planar constraints (2 axis), the rotation axis is the normal of the plane. 00469 * 00470 * The following only applies when CON_NOFLIP is not set. 00471 * The vector is then modified to always point away from the screen (in global space) 00472 * This insures that the rotation is always logically following the mouse. 00473 * (ie: not doing counterclockwise rotations when the mouse moves clockwise). 00474 */ 00475 00476 static void applyAxisConstraintRot(TransInfo *t, TransData *td, float vec[3], float *angle) 00477 { 00478 if (!td && t->con.mode & CON_APPLY) { 00479 int mode = t->con.mode & (CON_AXIS0|CON_AXIS1|CON_AXIS2); 00480 00481 switch(mode) { 00482 case CON_AXIS0: 00483 case (CON_AXIS1|CON_AXIS2): 00484 VECCOPY(vec, t->con.mtx[0]); 00485 break; 00486 case CON_AXIS1: 00487 case (CON_AXIS0|CON_AXIS2): 00488 VECCOPY(vec, t->con.mtx[1]); 00489 break; 00490 case CON_AXIS2: 00491 case (CON_AXIS0|CON_AXIS1): 00492 VECCOPY(vec, t->con.mtx[2]); 00493 break; 00494 } 00495 /* don't flip axis if asked to or if num input */ 00496 if (angle && (mode & CON_NOFLIP) == 0 && hasNumInput(&t->num) == 0) { 00497 if (dot_v3v3(vec, t->viewinv[2]) > 0.0f) { 00498 *angle = -(*angle); 00499 } 00500 } 00501 } 00502 } 00503 00504 /* 00505 * Callback for object based spacial constraints applied to rotations 00506 * 00507 * The rotation axis is copied into VEC. 00508 * 00509 * In the case of single axis constraints, the rotation axis is directly the one constrained to. 00510 * For planar constraints (2 axis), the rotation axis is the normal of the plane. 00511 * 00512 * The following only applies when CON_NOFLIP is not set. 00513 * The vector is then modified to always point away from the screen (in global space) 00514 * This insures that the rotation is always logically following the mouse. 00515 * (ie: not doing counterclockwise rotations when the mouse moves clockwise). 00516 */ 00517 00518 static void applyObjectConstraintRot(TransInfo *t, TransData *td, float vec[3], float *angle) 00519 { 00520 if (t->con.mode & CON_APPLY) { 00521 int mode = t->con.mode & (CON_AXIS0|CON_AXIS1|CON_AXIS2); 00522 00523 /* on setup call, use first object */ 00524 if (td == NULL) { 00525 td= t->data; 00526 } 00527 00528 switch(mode) { 00529 case CON_AXIS0: 00530 case (CON_AXIS1|CON_AXIS2): 00531 VECCOPY(vec, td->axismtx[0]); 00532 break; 00533 case CON_AXIS1: 00534 case (CON_AXIS0|CON_AXIS2): 00535 VECCOPY(vec, td->axismtx[1]); 00536 break; 00537 case CON_AXIS2: 00538 case (CON_AXIS0|CON_AXIS1): 00539 VECCOPY(vec, td->axismtx[2]); 00540 break; 00541 } 00542 if (angle && (mode & CON_NOFLIP) == 0 && hasNumInput(&t->num) == 0) { 00543 if (dot_v3v3(vec, t->viewinv[2]) > 0.0f) { 00544 *angle = -(*angle); 00545 } 00546 } 00547 } 00548 } 00549 00550 /*--------------------- INTERNAL SETUP CALLS ------------------*/ 00551 00552 void setConstraint(TransInfo *t, float space[3][3], int mode, const char text[]) { 00553 strncpy(t->con.text + 1, text, 48); 00554 copy_m3_m3(t->con.mtx, space); 00555 t->con.mode = mode; 00556 getConstraintMatrix(t); 00557 00558 startConstraint(t); 00559 00560 t->con.drawExtra = NULL; 00561 t->con.applyVec = applyAxisConstraintVec; 00562 t->con.applySize = applyAxisConstraintSize; 00563 t->con.applyRot = applyAxisConstraintRot; 00564 t->redraw = 1; 00565 } 00566 00567 void setLocalConstraint(TransInfo *t, int mode, const char text[]) { 00568 if (t->flag & T_EDIT) { 00569 float obmat[3][3]; 00570 copy_m3_m4(obmat, t->scene->obedit->obmat); 00571 normalize_m3(obmat); 00572 setConstraint(t, obmat, mode, text); 00573 } 00574 else { 00575 if (t->total == 1) { 00576 setConstraint(t, t->data->axismtx, mode, text); 00577 } 00578 else { 00579 strncpy(t->con.text + 1, text, 48); 00580 copy_m3_m3(t->con.mtx, t->data->axismtx); 00581 t->con.mode = mode; 00582 getConstraintMatrix(t); 00583 00584 startConstraint(t); 00585 00586 t->con.drawExtra = drawObjectConstraint; 00587 t->con.applyVec = applyObjectConstraintVec; 00588 t->con.applySize = applyObjectConstraintSize; 00589 t->con.applyRot = applyObjectConstraintRot; 00590 t->redraw = 1; 00591 } 00592 } 00593 } 00594 00595 /* 00596 Set the constraint according to the user defined orientation 00597 00598 ftext is a format string passed to sprintf. It will add the name of 00599 the orientation where %s is (logically). 00600 */ 00601 void setUserConstraint(TransInfo *t, short orientation, int mode, const char ftext[]) { 00602 char text[40]; 00603 00604 switch(orientation) { 00605 case V3D_MANIP_GLOBAL: 00606 { 00607 float mtx[3][3]= MAT3_UNITY; 00608 sprintf(text, ftext, "global"); 00609 setConstraint(t, mtx, mode, text); 00610 } 00611 break; 00612 case V3D_MANIP_LOCAL: 00613 sprintf(text, ftext, "local"); 00614 setLocalConstraint(t, mode, text); 00615 break; 00616 case V3D_MANIP_NORMAL: 00617 sprintf(text, ftext, "normal"); 00618 setConstraint(t, t->spacemtx, mode, text); 00619 break; 00620 case V3D_MANIP_VIEW: 00621 sprintf(text, ftext, "view"); 00622 setConstraint(t, t->spacemtx, mode, text); 00623 break; 00624 case V3D_MANIP_GIMBAL: 00625 sprintf(text, ftext, "gimbal"); 00626 setConstraint(t, t->spacemtx, mode, text); 00627 break; 00628 default: /* V3D_MANIP_CUSTOM */ 00629 sprintf(text, ftext, t->spacename); 00630 setConstraint(t, t->spacemtx, mode, text); 00631 break; 00632 } 00633 00634 t->con.orientation = orientation; 00635 00636 t->con.mode |= CON_USER; 00637 } 00638 00639 /*----------------- DRAWING CONSTRAINTS -------------------*/ 00640 00641 void drawConstraint(TransInfo *t) 00642 { 00643 TransCon *tc = &(t->con); 00644 00645 if (!ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE)) 00646 return; 00647 if (!(tc->mode & CON_APPLY)) 00648 return; 00649 if (t->flag & T_USES_MANIPULATOR) 00650 return; 00651 if (t->flag & T_NO_CONSTRAINT) 00652 return; 00653 00654 /* nasty exception for Z constraint in camera view */ 00655 // TRANSFORM_FIX_ME 00656 // if((t->flag & T_OBJECT) && G.vd->camera==OBACT && G.vd->persp==V3D_CAMOB) 00657 // return; 00658 00659 if (tc->drawExtra) { 00660 tc->drawExtra(t); 00661 } 00662 else { 00663 if (tc->mode & CON_SELECT) { 00664 float vec[3]; 00665 char col2[3] = {255,255,255}; 00666 int depth_test_enabled; 00667 00668 convertViewVec(t, vec, (t->mval[0] - t->con.imval[0]), (t->mval[1] - t->con.imval[1])); 00669 add_v3_v3(vec, tc->center); 00670 00671 drawLine(t, tc->center, tc->mtx[0], 'X', 0); 00672 drawLine(t, tc->center, tc->mtx[1], 'Y', 0); 00673 drawLine(t, tc->center, tc->mtx[2], 'Z', 0); 00674 00675 glColor3ubv((GLubyte *)col2); 00676 00677 depth_test_enabled = glIsEnabled(GL_DEPTH_TEST); 00678 if(depth_test_enabled) 00679 glDisable(GL_DEPTH_TEST); 00680 00681 setlinestyle(1); 00682 glBegin(GL_LINE_STRIP); 00683 glVertex3fv(tc->center); 00684 glVertex3fv(vec); 00685 glEnd(); 00686 setlinestyle(0); 00687 00688 if(depth_test_enabled) 00689 glEnable(GL_DEPTH_TEST); 00690 } 00691 00692 if (tc->mode & CON_AXIS0) { 00693 drawLine(t, tc->center, tc->mtx[0], 'X', DRAWLIGHT); 00694 } 00695 if (tc->mode & CON_AXIS1) { 00696 drawLine(t, tc->center, tc->mtx[1], 'Y', DRAWLIGHT); 00697 } 00698 if (tc->mode & CON_AXIS2) { 00699 drawLine(t, tc->center, tc->mtx[2], 'Z', DRAWLIGHT); 00700 } 00701 } 00702 } 00703 00704 /* called from drawview.c, as an extra per-window draw option */ 00705 void drawPropCircle(const struct bContext *C, TransInfo *t) 00706 { 00707 if (t->flag & T_PROP_EDIT) { 00708 RegionView3D *rv3d = CTX_wm_region_view3d(C); 00709 float tmat[4][4], imat[4][4]; 00710 float center[3]; 00711 00712 UI_ThemeColor(TH_GRID); 00713 00714 if(t->spacetype == SPACE_VIEW3D && rv3d != NULL) 00715 { 00716 copy_m4_m4(tmat, rv3d->viewmat); 00717 invert_m4_m4(imat, tmat); 00718 } 00719 else 00720 { 00721 unit_m4(tmat); 00722 unit_m4(imat); 00723 } 00724 00725 glPushMatrix(); 00726 00727 VECCOPY(center, t->center); 00728 00729 if((t->spacetype == SPACE_VIEW3D) && t->obedit) 00730 { 00731 mul_m4_v3(t->obedit->obmat, center); /* because t->center is in local space */ 00732 } 00733 else if(t->spacetype == SPACE_IMAGE) 00734 { 00735 float aspx, aspy; 00736 00737 ED_space_image_uv_aspect(t->sa->spacedata.first, &aspx, &aspy); 00738 glScalef(1.0f/aspx, 1.0f/aspy, 1.0); 00739 } 00740 00741 set_inverted_drawing(1); 00742 drawcircball(GL_LINE_LOOP, center, t->prop_size, imat); 00743 set_inverted_drawing(0); 00744 00745 glPopMatrix(); 00746 } 00747 } 00748 00749 static void drawObjectConstraint(TransInfo *t) { 00750 int i; 00751 TransData * td = t->data; 00752 00753 /* Draw the first one lighter because that's the one who controls the others. 00754 Meaning the transformation is projected on that one and just copied on the others 00755 constraint space. 00756 In a nutshell, the object with light axis is controlled by the user and the others follow. 00757 Without drawing the first light, users have little clue what they are doing. 00758 */ 00759 if (t->con.mode & CON_AXIS0) { 00760 drawLine(t, td->ob->obmat[3], td->axismtx[0], 'X', DRAWLIGHT); 00761 } 00762 if (t->con.mode & CON_AXIS1) { 00763 drawLine(t, td->ob->obmat[3], td->axismtx[1], 'Y', DRAWLIGHT); 00764 } 00765 if (t->con.mode & CON_AXIS2) { 00766 drawLine(t, td->ob->obmat[3], td->axismtx[2], 'Z', DRAWLIGHT); 00767 } 00768 00769 td++; 00770 00771 for(i=1;i<t->total;i++,td++) { 00772 if (t->con.mode & CON_AXIS0) { 00773 drawLine(t, td->ob->obmat[3], td->axismtx[0], 'X', 0); 00774 } 00775 if (t->con.mode & CON_AXIS1) { 00776 drawLine(t, td->ob->obmat[3], td->axismtx[1], 'Y', 0); 00777 } 00778 if (t->con.mode & CON_AXIS2) { 00779 drawLine(t, td->ob->obmat[3], td->axismtx[2], 'Z', 0); 00780 } 00781 } 00782 } 00783 00784 /*--------------------- START / STOP CONSTRAINTS ---------------------- */ 00785 00786 void startConstraint(TransInfo *t) { 00787 t->con.mode |= CON_APPLY; 00788 *t->con.text = ' '; 00789 t->num.idx_max = MIN2(getConstraintSpaceDimension(t) - 1, t->idx_max); 00790 } 00791 00792 void stopConstraint(TransInfo *t) { 00793 t->con.mode &= ~(CON_APPLY|CON_SELECT); 00794 *t->con.text = '\0'; 00795 t->num.idx_max = t->idx_max; 00796 } 00797 00798 void getConstraintMatrix(TransInfo *t) 00799 { 00800 float mat[3][3]; 00801 invert_m3_m3(t->con.imtx, t->con.mtx); 00802 unit_m3(t->con.pmtx); 00803 00804 if (!(t->con.mode & CON_AXIS0)) { 00805 t->con.pmtx[0][0] = 00806 t->con.pmtx[0][1] = 00807 t->con.pmtx[0][2] = 0.0f; 00808 } 00809 00810 if (!(t->con.mode & CON_AXIS1)) { 00811 t->con.pmtx[1][0] = 00812 t->con.pmtx[1][1] = 00813 t->con.pmtx[1][2] = 0.0f; 00814 } 00815 00816 if (!(t->con.mode & CON_AXIS2)) { 00817 t->con.pmtx[2][0] = 00818 t->con.pmtx[2][1] = 00819 t->con.pmtx[2][2] = 0.0f; 00820 } 00821 00822 mul_m3_m3m3(mat, t->con.pmtx, t->con.imtx); 00823 mul_m3_m3m3(t->con.pmtx, t->con.mtx, mat); 00824 } 00825 00826 /*------------------------- MMB Select -------------------------------*/ 00827 00828 void initSelectConstraint(TransInfo *t, float mtx[3][3]) 00829 { 00830 copy_m3_m3(t->con.mtx, mtx); 00831 t->con.mode |= CON_APPLY; 00832 t->con.mode |= CON_SELECT; 00833 00834 setNearestAxis(t); 00835 t->con.drawExtra = NULL; 00836 t->con.applyVec = applyAxisConstraintVec; 00837 t->con.applySize = applyAxisConstraintSize; 00838 t->con.applyRot = applyAxisConstraintRot; 00839 } 00840 00841 void selectConstraint(TransInfo *t) { 00842 if (t->con.mode & CON_SELECT) { 00843 setNearestAxis(t); 00844 startConstraint(t); 00845 } 00846 } 00847 00848 void postSelectConstraint(TransInfo *t) 00849 { 00850 if (!(t->con.mode & CON_SELECT)) 00851 return; 00852 00853 t->con.mode &= ~CON_AXIS0; 00854 t->con.mode &= ~CON_AXIS1; 00855 t->con.mode &= ~CON_AXIS2; 00856 t->con.mode &= ~CON_SELECT; 00857 00858 setNearestAxis(t); 00859 00860 startConstraint(t); 00861 t->redraw = 1; 00862 } 00863 00864 static void setNearestAxis2d(TransInfo *t) 00865 { 00866 /* no correction needed... just use whichever one is lower */ 00867 if ( abs(t->mval[0]-t->con.imval[0]) < abs(t->mval[1]-t->con.imval[1]) ) { 00868 t->con.mode |= CON_AXIS1; 00869 sprintf(t->con.text, " along Y axis"); 00870 } 00871 else { 00872 t->con.mode |= CON_AXIS0; 00873 sprintf(t->con.text, " along X axis"); 00874 } 00875 } 00876 00877 static void setNearestAxis3d(TransInfo *t) 00878 { 00879 float zfac; 00880 float mvec[3], axis[3], proj[3]; 00881 float len[3]; 00882 int i, icoord[2]; 00883 00884 /* calculate mouse movement */ 00885 mvec[0] = (float)(t->mval[0] - t->con.imval[0]); 00886 mvec[1] = (float)(t->mval[1] - t->con.imval[1]); 00887 mvec[2] = 0.0f; 00888 00889 /* we need to correct axis length for the current zoomlevel of view, 00890 this to prevent projected values to be clipped behind the camera 00891 and to overflow the short integers. 00892 The formula used is a bit stupid, just a simplification of the substraction 00893 of two 2D points 30 pixels apart (that's the last factor in the formula) after 00894 projecting them with window_to_3d_delta and then get the length of that vector. 00895 */ 00896 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]; 00897 zfac = len_v3(t->persinv[0]) * 2.0f/t->ar->winx * zfac * 30.0f; 00898 00899 for (i = 0; i<3; i++) { 00900 VECCOPY(axis, t->con.mtx[i]); 00901 00902 mul_v3_fl(axis, zfac); 00903 /* now we can project to get window coordinate */ 00904 add_v3_v3(axis, t->con.center); 00905 projectIntView(t, axis, icoord); 00906 00907 axis[0] = (float)(icoord[0] - t->center2d[0]); 00908 axis[1] = (float)(icoord[1] - t->center2d[1]); 00909 axis[2] = 0.0f; 00910 00911 if (normalize_v3(axis) != 0.0f) { 00912 project_v3_v3v3(proj, mvec, axis); 00913 sub_v3_v3v3(axis, mvec, proj); 00914 len[i] = normalize_v3(axis); 00915 } 00916 else { 00917 len[i] = 10000000000.0f; 00918 } 00919 } 00920 00921 if (len[0] <= len[1] && len[0] <= len[2]) { 00922 if (t->modifiers & MOD_CONSTRAINT_PLANE) { 00923 t->con.mode |= (CON_AXIS1|CON_AXIS2); 00924 sprintf(t->con.text, " locking %s X axis", t->spacename); 00925 } 00926 else { 00927 t->con.mode |= CON_AXIS0; 00928 sprintf(t->con.text, " along %s X axis", t->spacename); 00929 } 00930 } 00931 else if (len[1] <= len[0] && len[1] <= len[2]) { 00932 if (t->modifiers & MOD_CONSTRAINT_PLANE) { 00933 t->con.mode |= (CON_AXIS0|CON_AXIS2); 00934 sprintf(t->con.text, " locking %s Y axis", t->spacename); 00935 } 00936 else { 00937 t->con.mode |= CON_AXIS1; 00938 sprintf(t->con.text, " along %s Y axis", t->spacename); 00939 } 00940 } 00941 else if (len[2] <= len[1] && len[2] <= len[0]) { 00942 if (t->modifiers & MOD_CONSTRAINT_PLANE) { 00943 t->con.mode |= (CON_AXIS0|CON_AXIS1); 00944 sprintf(t->con.text, " locking %s Z axis", t->spacename); 00945 } 00946 else { 00947 t->con.mode |= CON_AXIS2; 00948 sprintf(t->con.text, " along %s Z axis", t->spacename); 00949 } 00950 } 00951 } 00952 00953 void setNearestAxis(TransInfo *t) 00954 { 00955 /* clear any prior constraint flags */ 00956 t->con.mode &= ~CON_AXIS0; 00957 t->con.mode &= ~CON_AXIS1; 00958 t->con.mode &= ~CON_AXIS2; 00959 00960 /* constraint setting - depends on spacetype */ 00961 if (t->spacetype == SPACE_VIEW3D) { 00962 /* 3d-view */ 00963 setNearestAxis3d(t); 00964 } 00965 else { 00966 /* assume that this means a 2D-Editor */ 00967 setNearestAxis2d(t); 00968 } 00969 00970 getConstraintMatrix(t); 00971 } 00972 00973 /*-------------- HELPER FUNCTIONS ----------------*/ 00974 00975 char constraintModeToChar(TransInfo *t) { 00976 if ((t->con.mode & CON_APPLY)==0) { 00977 return '\0'; 00978 } 00979 switch (t->con.mode & (CON_AXIS0|CON_AXIS1|CON_AXIS2)) { 00980 case (CON_AXIS0): 00981 case (CON_AXIS1|CON_AXIS2): 00982 return 'X'; 00983 case (CON_AXIS1): 00984 case (CON_AXIS0|CON_AXIS2): 00985 return 'Y'; 00986 case (CON_AXIS2): 00987 case (CON_AXIS0|CON_AXIS1): 00988 return 'Z'; 00989 default: 00990 return '\0'; 00991 } 00992 } 00993 00994 00995 int isLockConstraint(TransInfo *t) { 00996 int mode = t->con.mode; 00997 00998 if ( (mode & (CON_AXIS0|CON_AXIS1)) == (CON_AXIS0|CON_AXIS1)) 00999 return 1; 01000 01001 if ( (mode & (CON_AXIS1|CON_AXIS2)) == (CON_AXIS1|CON_AXIS2)) 01002 return 1; 01003 01004 if ( (mode & (CON_AXIS0|CON_AXIS2)) == (CON_AXIS0|CON_AXIS2)) 01005 return 1; 01006 01007 return 0; 01008 } 01009 01010 /* 01011 * Returns the dimension of the constraint space. 01012 * 01013 * For that reason, the flags always needs to be set to properly evaluate here, 01014 * even if they aren't actually used in the callback function. (Which could happen 01015 * for weird constraints not yet designed. Along a path for example.) 01016 */ 01017 01018 int getConstraintSpaceDimension(TransInfo *t) 01019 { 01020 int n = 0; 01021 01022 if (t->con.mode & CON_AXIS0) 01023 n++; 01024 01025 if (t->con.mode & CON_AXIS1) 01026 n++; 01027 01028 if (t->con.mode & CON_AXIS2) 01029 n++; 01030 01031 return n; 01032 /* 01033 Someone willing to do it criptically could do the following instead: 01034 01035 return t->con & (CON_AXIS0|CON_AXIS1|CON_AXIS2); 01036 01037 Based on the assumptions that the axis flags are one after the other and start at 1 01038 */ 01039 }