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