|
Blender
V2.59
|
00001 /* 00002 * $Id: transform_manipulator.c 38085 2011-07-04 13:48:18Z blendix $ 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) 2005 Blender Foundation 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 <string.h> 00037 #include <math.h> 00038 #include <float.h> 00039 00040 #ifndef WIN32 00041 #include <unistd.h> 00042 #else 00043 #include <io.h> 00044 #endif 00045 00046 #include "MEM_guardedalloc.h" 00047 00048 #include "DNA_armature_types.h" 00049 #include "DNA_curve_types.h" 00050 #include "DNA_lattice_types.h" 00051 #include "DNA_meta_types.h" 00052 #include "DNA_screen_types.h" 00053 #include "DNA_scene_types.h" 00054 #include "DNA_view3d_types.h" 00055 00056 #include "RNA_access.h" 00057 00058 #include "BKE_action.h" 00059 #include "BKE_context.h" 00060 #include "BKE_global.h" 00061 #include "BKE_mesh.h" 00062 #include "BKE_particle.h" 00063 #include "BKE_pointcache.h" 00064 00065 #include "BLI_math.h" 00066 #include "BLI_editVert.h" 00067 #include "BLI_utildefines.h" 00068 00069 #include "BIF_gl.h" 00070 00071 #include "WM_api.h" 00072 #include "WM_types.h" 00073 00074 #include "ED_armature.h" 00075 #include "ED_mesh.h" 00076 #include "ED_particle.h" 00077 #include "ED_view3d.h" 00078 #include "ED_curve.h" /* for ED_curve_editnurbs */ 00079 00080 #include "UI_resources.h" 00081 00082 /* local module include */ 00083 #include "transform.h" 00084 00085 /* return codes for select, and drawing flags */ 00086 00087 #define MAN_TRANS_X 1 00088 #define MAN_TRANS_Y 2 00089 #define MAN_TRANS_Z 4 00090 #define MAN_TRANS_C 7 00091 00092 #define MAN_ROT_X 8 00093 #define MAN_ROT_Y 16 00094 #define MAN_ROT_Z 32 00095 #define MAN_ROT_V 64 00096 #define MAN_ROT_T 128 00097 #define MAN_ROT_C 248 00098 00099 #define MAN_SCALE_X 256 00100 #define MAN_SCALE_Y 512 00101 #define MAN_SCALE_Z 1024 00102 #define MAN_SCALE_C 1792 00103 00104 /* color codes */ 00105 00106 #define MAN_RGB 0 00107 #define MAN_GHOST 1 00108 #define MAN_MOVECOL 2 00109 00110 /* transform widget center calc helper for below */ 00111 static void calc_tw_center(Scene *scene, float *co) 00112 { 00113 float *twcent= scene->twcent; 00114 float *min= scene->twmin; 00115 float *max= scene->twmax; 00116 00117 DO_MINMAX(co, min, max); 00118 add_v3_v3(twcent, co); 00119 } 00120 00121 static void protectflag_to_drawflags(short protectflag, short *drawflags) 00122 { 00123 if(protectflag & OB_LOCK_LOCX) 00124 *drawflags &= ~MAN_TRANS_X; 00125 if(protectflag & OB_LOCK_LOCY) 00126 *drawflags &= ~MAN_TRANS_Y; 00127 if(protectflag & OB_LOCK_LOCZ) 00128 *drawflags &= ~MAN_TRANS_Z; 00129 00130 if(protectflag & OB_LOCK_ROTX) 00131 *drawflags &= ~MAN_ROT_X; 00132 if(protectflag & OB_LOCK_ROTY) 00133 *drawflags &= ~MAN_ROT_Y; 00134 if(protectflag & OB_LOCK_ROTZ) 00135 *drawflags &= ~MAN_ROT_Z; 00136 00137 if(protectflag & OB_LOCK_SCALEX) 00138 *drawflags &= ~MAN_SCALE_X; 00139 if(protectflag & OB_LOCK_SCALEY) 00140 *drawflags &= ~MAN_SCALE_Y; 00141 if(protectflag & OB_LOCK_SCALEZ) 00142 *drawflags &= ~MAN_SCALE_Z; 00143 } 00144 00145 /* for pose mode */ 00146 static void stats_pose(Scene *scene, RegionView3D *rv3d, bPoseChannel *pchan) 00147 { 00148 Bone *bone= pchan->bone; 00149 00150 if(bone) { 00151 if (bone->flag & BONE_TRANSFORM) { 00152 calc_tw_center(scene, pchan->pose_head); 00153 protectflag_to_drawflags(pchan->protectflag, &rv3d->twdrawflag); 00154 } 00155 } 00156 } 00157 00158 /* for editmode*/ 00159 static void stats_editbone(RegionView3D *rv3d, EditBone *ebo) 00160 { 00161 if (ebo->flag & BONE_EDITMODE_LOCKED) 00162 protectflag_to_drawflags(OB_LOCK_LOC|OB_LOCK_ROT|OB_LOCK_SCALE, &rv3d->twdrawflag); 00163 } 00164 00165 /* could move into BLI_math however this is only useful for display/editing purposes */ 00166 static void axis_angle_to_gimbal_axis(float gmat[3][3], float axis[3], float angle) 00167 { 00168 /* X/Y are arbitrary axies, most importantly Z is the axis of rotation */ 00169 00170 float cross_vec[3]; 00171 float quat[4]; 00172 00173 /* this is an un-scientific method to get a vector to cross with 00174 * XYZ intentionally YZX */ 00175 cross_vec[0]= axis[1]; 00176 cross_vec[1]= axis[2]; 00177 cross_vec[2]= axis[0]; 00178 00179 /* X-axis */ 00180 cross_v3_v3v3(gmat[0], cross_vec, axis); 00181 normalize_v3(gmat[0]); 00182 axis_angle_to_quat(quat, axis, angle); 00183 mul_qt_v3(quat, gmat[0]); 00184 00185 /* Y-axis */ 00186 axis_angle_to_quat(quat, axis, M_PI/2.0); 00187 copy_v3_v3(gmat[1], gmat[0]); 00188 mul_qt_v3(quat, gmat[1]); 00189 00190 /* Z-axis */ 00191 copy_v3_v3(gmat[2], axis); 00192 00193 normalize_m3(gmat); 00194 } 00195 00196 00197 static int test_rotmode_euler(short rotmode) 00198 { 00199 return (ELEM(rotmode, ROT_MODE_AXISANGLE, ROT_MODE_QUAT)) ? 0:1; 00200 } 00201 00202 int gimbal_axis(Object *ob, float gmat[][3]) 00203 { 00204 if (ob) { 00205 if(ob->mode & OB_MODE_POSE) 00206 { 00207 bPoseChannel *pchan= get_active_posechannel(ob); 00208 00209 if(pchan) { 00210 float mat[3][3], tmat[3][3], obmat[3][3]; 00211 if(test_rotmode_euler(pchan->rotmode)) { 00212 eulO_to_gimbal_axis(mat, pchan->eul, pchan->rotmode); 00213 } 00214 else if (pchan->rotmode == ROT_MODE_AXISANGLE) { 00215 axis_angle_to_gimbal_axis(mat, pchan->rotAxis, pchan->rotAngle); 00216 } 00217 else { /* quat */ 00218 return 0; 00219 } 00220 00221 00222 /* apply bone transformation */ 00223 mul_m3_m3m3(tmat, pchan->bone->bone_mat, mat); 00224 00225 if (pchan->parent) 00226 { 00227 float parent_mat[3][3]; 00228 00229 copy_m3_m4(parent_mat, pchan->parent->pose_mat); 00230 mul_m3_m3m3(mat, parent_mat, tmat); 00231 00232 /* needed if object transformation isn't identity */ 00233 copy_m3_m4(obmat, ob->obmat); 00234 mul_m3_m3m3(gmat, obmat, mat); 00235 } 00236 else 00237 { 00238 /* needed if object transformation isn't identity */ 00239 copy_m3_m4(obmat, ob->obmat); 00240 mul_m3_m3m3(gmat, obmat, tmat); 00241 } 00242 00243 normalize_m3(gmat); 00244 return 1; 00245 } 00246 } 00247 else { 00248 if(test_rotmode_euler(ob->rotmode)) { 00249 eulO_to_gimbal_axis(gmat, ob->rot, ob->rotmode); 00250 } 00251 else if(ob->rotmode == ROT_MODE_AXISANGLE) { 00252 axis_angle_to_gimbal_axis(gmat, ob->rotAxis, ob->rotAngle); 00253 } 00254 else { /* quat */ 00255 return 0; 00256 } 00257 00258 if (ob->parent) 00259 { 00260 float parent_mat[3][3]; 00261 copy_m3_m4(parent_mat, ob->parent->obmat); 00262 normalize_m3(parent_mat); 00263 mul_m3_m3m3(gmat, parent_mat, gmat); 00264 } 00265 return 1; 00266 } 00267 } 00268 00269 return 0; 00270 } 00271 00272 00273 /* centroid, boundbox, of selection */ 00274 /* returns total items selected */ 00275 int calc_manipulator_stats(const bContext *C) 00276 { 00277 ScrArea *sa= CTX_wm_area(C); 00278 ARegion *ar= CTX_wm_region(C); 00279 Scene *scene= CTX_data_scene(C); 00280 Object *obedit= CTX_data_edit_object(C); 00281 ToolSettings *ts = CTX_data_tool_settings(C); 00282 View3D *v3d= sa->spacedata.first; 00283 RegionView3D *rv3d= ar->regiondata; 00284 Base *base; 00285 Object *ob= OBACT; 00286 int a, totsel= 0; 00287 00288 /* transform widget matrix */ 00289 unit_m4(rv3d->twmat); 00290 00291 rv3d->twdrawflag= 0xFFFF; 00292 00293 /* transform widget centroid/center */ 00294 scene->twcent[0]= scene->twcent[1]= scene->twcent[2]= 0.0f; 00295 INIT_MINMAX(scene->twmin, scene->twmax); 00296 00297 if(obedit) { 00298 ob= obedit; 00299 if((ob->lay & v3d->lay)==0) return 0; 00300 00301 if(obedit->type==OB_MESH) { 00302 EditMesh *em = BKE_mesh_get_editmesh(obedit->data); 00303 EditVert *eve; 00304 EditSelection ese; 00305 float vec[3]= {0,0,0}; 00306 00307 /* USE LAST SELECTE WITH ACTIVE */ 00308 if (v3d->around==V3D_ACTIVE && EM_get_actSelection(em, &ese)) { 00309 EM_editselection_center(vec, &ese); 00310 calc_tw_center(scene, vec); 00311 totsel= 1; 00312 } else { 00313 /* do vertices/edges/faces for center depending on selection 00314 mode. note we can't use just vertex selection flag because 00315 it is not flush down on changes */ 00316 if(ts->selectmode & SCE_SELECT_VERTEX) { 00317 for(eve= em->verts.first; eve; eve= eve->next) { 00318 if(eve->f & SELECT) { 00319 totsel++; 00320 calc_tw_center(scene, eve->co); 00321 } 00322 } 00323 } 00324 else if(ts->selectmode & SCE_SELECT_EDGE) { 00325 EditEdge *eed; 00326 00327 for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0; 00328 for(eed= em->edges.first; eed; eed= eed->next) { 00329 if(eed->h==0 && (eed->f & SELECT)) { 00330 if(!eed->v1->f1) { 00331 eed->v1->f1= 1; 00332 totsel++; 00333 calc_tw_center(scene, eed->v1->co); 00334 } 00335 if(!eed->v2->f1) { 00336 eed->v2->f1= 1; 00337 totsel++; 00338 calc_tw_center(scene, eed->v2->co); 00339 } 00340 } 00341 } 00342 } 00343 else { 00344 EditFace *efa; 00345 00346 for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0; 00347 for(efa= em->faces.first; efa; efa= efa->next) { 00348 if(efa->h==0 && (efa->f & SELECT)) { 00349 if(!efa->v1->f1) { 00350 efa->v1->f1= 1; 00351 totsel++; 00352 calc_tw_center(scene, efa->v1->co); 00353 } 00354 if(!efa->v2->f1) { 00355 efa->v2->f1= 1; 00356 totsel++; 00357 calc_tw_center(scene, efa->v2->co); 00358 } 00359 if(!efa->v3->f1) { 00360 efa->v3->f1= 1; 00361 totsel++; 00362 calc_tw_center(scene, efa->v3->co); 00363 } 00364 if(efa->v4 && !efa->v4->f1) { 00365 efa->v4->f1= 1; 00366 totsel++; 00367 calc_tw_center(scene, efa->v4->co); 00368 } 00369 } 00370 } 00371 } 00372 } 00373 } /* end editmesh */ 00374 else if (obedit->type==OB_ARMATURE){ 00375 bArmature *arm= obedit->data; 00376 EditBone *ebo; 00377 for (ebo= arm->edbo->first; ebo; ebo=ebo->next){ 00378 if(EBONE_VISIBLE(arm, ebo)) { 00379 if (ebo->flag & BONE_TIPSEL) { 00380 calc_tw_center(scene, ebo->tail); 00381 totsel++; 00382 } 00383 if (ebo->flag & BONE_ROOTSEL) { 00384 calc_tw_center(scene, ebo->head); 00385 totsel++; 00386 } 00387 if (ebo->flag & BONE_SELECTED) { 00388 stats_editbone(rv3d, ebo); 00389 } 00390 } 00391 } 00392 } 00393 else if ELEM(obedit->type, OB_CURVE, OB_SURF) { 00394 Curve *cu= obedit->data; 00395 Nurb *nu; 00396 BezTriple *bezt; 00397 BPoint *bp; 00398 ListBase *nurbs= ED_curve_editnurbs(cu); 00399 00400 nu= nurbs->first; 00401 while(nu) { 00402 if(nu->type == CU_BEZIER) { 00403 bezt= nu->bezt; 00404 a= nu->pntsu; 00405 while(a--) { 00406 /* exceptions 00407 * if handles are hidden then only check the center points. 00408 * If the center knot is selected then only use this as the center point. 00409 */ 00410 if (cu->drawflag & CU_HIDE_HANDLES) { 00411 if (bezt->f2 & SELECT) { 00412 calc_tw_center(scene, bezt->vec[1]); 00413 totsel++; 00414 } 00415 } 00416 else if (bezt->f2 & SELECT) { 00417 calc_tw_center(scene, bezt->vec[1]); 00418 totsel++; 00419 } 00420 else { 00421 if(bezt->f1) { 00422 calc_tw_center(scene, bezt->vec[0]); 00423 totsel++; 00424 } 00425 if(bezt->f3) { 00426 calc_tw_center(scene, bezt->vec[2]); 00427 totsel++; 00428 } 00429 } 00430 bezt++; 00431 } 00432 } 00433 else { 00434 bp= nu->bp; 00435 a= nu->pntsu*nu->pntsv; 00436 while(a--) { 00437 if(bp->f1 & SELECT) { 00438 calc_tw_center(scene, bp->vec); 00439 totsel++; 00440 } 00441 bp++; 00442 } 00443 } 00444 nu= nu->next; 00445 } 00446 } 00447 else if(obedit->type==OB_MBALL) { 00448 MetaBall *mb = (MetaBall*)obedit->data; 00449 MetaElem *ml, *ml_sel=NULL; 00450 00451 ml= mb->editelems->first; 00452 while(ml) { 00453 if(ml->flag & SELECT) { 00454 calc_tw_center(scene, &ml->x); 00455 ml_sel = ml; 00456 totsel++; 00457 } 00458 ml= ml->next; 00459 } 00460 } 00461 else if(obedit->type==OB_LATTICE) { 00462 BPoint *bp; 00463 Lattice *lt= obedit->data; 00464 00465 bp= lt->editlatt->latt->def; 00466 00467 a= lt->editlatt->latt->pntsu*lt->editlatt->latt->pntsv*lt->editlatt->latt->pntsw; 00468 while(a--) { 00469 if(bp->f1 & SELECT) { 00470 calc_tw_center(scene, bp->vec); 00471 totsel++; 00472 } 00473 bp++; 00474 } 00475 } 00476 00477 /* selection center */ 00478 if(totsel) { 00479 mul_v3_fl(scene->twcent, 1.0f/(float)totsel); // centroid! 00480 mul_m4_v3(obedit->obmat, scene->twcent); 00481 mul_m4_v3(obedit->obmat, scene->twmin); 00482 mul_m4_v3(obedit->obmat, scene->twmax); 00483 } 00484 } 00485 else if(ob && (ob->mode & OB_MODE_POSE)) { 00486 bPoseChannel *pchan; 00487 int mode = TFM_ROTATION; // mislead counting bones... bah. We don't know the manipulator mode, could be mixed 00488 00489 if((ob->lay & v3d->lay)==0) return 0; 00490 00491 totsel = count_set_pose_transflags(&mode, 0, ob); 00492 00493 if(totsel) { 00494 /* use channels to get stats */ 00495 for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { 00496 stats_pose(scene, rv3d, pchan); 00497 } 00498 00499 mul_v3_fl(scene->twcent, 1.0f/(float)totsel); // centroid! 00500 mul_m4_v3(ob->obmat, scene->twcent); 00501 mul_m4_v3(ob->obmat, scene->twmin); 00502 mul_m4_v3(ob->obmat, scene->twmax); 00503 } 00504 } 00505 else if(ob && (ob->mode & OB_MODE_ALL_PAINT)) { 00506 ; 00507 } 00508 else if(ob && ob->mode & OB_MODE_PARTICLE_EDIT) { 00509 PTCacheEdit *edit= PE_get_current(scene, ob); 00510 PTCacheEditPoint *point; 00511 PTCacheEditKey *ek; 00512 int k; 00513 00514 if(edit) { 00515 point = edit->points; 00516 for(a=0; a<edit->totpoint; a++,point++) { 00517 if(point->flag & PEP_HIDE) continue; 00518 00519 for(k=0, ek=point->keys; k<point->totkey; k++, ek++) { 00520 if(ek->flag & PEK_SELECT) { 00521 calc_tw_center(scene, ek->flag & PEK_USE_WCO ? ek->world_co : ek->co); 00522 totsel++; 00523 } 00524 } 00525 } 00526 00527 /* selection center */ 00528 if(totsel) 00529 mul_v3_fl(scene->twcent, 1.0f/(float)totsel); // centroid! 00530 } 00531 } 00532 else { 00533 00534 /* we need the one selected object, if its not active */ 00535 ob= OBACT; 00536 if(ob && !(ob->flag & SELECT)) ob= NULL; 00537 00538 for(base= scene->base.first; base; base= base->next) { 00539 if TESTBASELIB(v3d, base) { 00540 if(ob==NULL) 00541 ob= base->object; 00542 calc_tw_center(scene, base->object->obmat[3]); 00543 protectflag_to_drawflags(base->object->protectflag, &rv3d->twdrawflag); 00544 totsel++; 00545 } 00546 } 00547 00548 /* selection center */ 00549 if(totsel) { 00550 mul_v3_fl(scene->twcent, 1.0f/(float)totsel); // centroid! 00551 } 00552 } 00553 00554 /* global, local or normal orientation? */ 00555 if(ob && totsel) { 00556 00557 switch(v3d->twmode) { 00558 00559 case V3D_MANIP_GLOBAL: 00560 break; /* nothing to do */ 00561 00562 case V3D_MANIP_GIMBAL: 00563 { 00564 float mat[3][3]; 00565 if (gimbal_axis(ob, mat)) { 00566 copy_m4_m3(rv3d->twmat, mat); 00567 break; 00568 } 00569 /* if not gimbal, fall through to normal */ 00570 } 00571 case V3D_MANIP_NORMAL: 00572 if(obedit || ob->mode & OB_MODE_POSE) { 00573 float mat[3][3]; 00574 ED_getTransformOrientationMatrix(C, mat, (v3d->around == V3D_ACTIVE)); 00575 copy_m4_m3(rv3d->twmat, mat); 00576 break; 00577 } 00578 /* no break we define 'normal' as 'local' in Object mode */ 00579 case V3D_MANIP_LOCAL: 00580 copy_m4_m4(rv3d->twmat, ob->obmat); 00581 normalize_m4(rv3d->twmat); 00582 break; 00583 00584 case V3D_MANIP_VIEW: 00585 { 00586 float mat[3][3]; 00587 copy_m3_m4(mat, rv3d->viewinv); 00588 normalize_m3(mat); 00589 copy_m4_m3(rv3d->twmat, mat); 00590 } 00591 break; 00592 default: /* V3D_MANIP_CUSTOM */ 00593 { 00594 float mat[3][3]; 00595 applyTransformOrientation(C, mat, NULL); 00596 copy_m4_m3(rv3d->twmat, mat); 00597 break; 00598 } 00599 } 00600 00601 } 00602 00603 return totsel; 00604 } 00605 00606 /* don't draw axis perpendicular to the view */ 00607 static void test_manipulator_axis(const bContext *C) 00608 { 00609 RegionView3D *rv3d= CTX_wm_region_view3d(C); 00610 float angle; 00611 float vec[3]; 00612 00613 ED_view3d_global_to_vector(rv3d, rv3d->twmat[3], vec); 00614 00615 angle = fabs(angle_v3v3(rv3d->twmat[0], vec)); 00616 if (angle > (float)M_PI / 2.0f) { 00617 angle = (float)M_PI - angle; 00618 } 00619 angle = rv3d->twangle[0] = RAD2DEGF(angle); 00620 if (angle < 5.0f) { 00621 rv3d->twdrawflag &= ~(MAN_TRANS_X|MAN_SCALE_X); 00622 } 00623 00624 angle = fabs(angle_v3v3(rv3d->twmat[1], vec)); 00625 if (angle > (float)M_PI / 2.0f) { 00626 angle = (float)M_PI - angle; 00627 } 00628 angle = rv3d->twangle[1] = RAD2DEGF(angle); 00629 if (angle < 5.0f) { 00630 rv3d->twdrawflag &= ~(MAN_TRANS_Y|MAN_SCALE_Y); 00631 } 00632 00633 angle = fabs(angle_v3v3(rv3d->twmat[2], vec)); 00634 if (angle > (float)M_PI / 2.0f) { 00635 angle = (float)M_PI - angle; 00636 } 00637 angle = rv3d->twangle[2] = RAD2DEGF(angle); 00638 if (angle < 5.0f) { 00639 rv3d->twdrawflag &= ~(MAN_TRANS_Z|MAN_SCALE_Z); 00640 } 00641 } 00642 00643 00644 /* ******************** DRAWING STUFFIES *********** */ 00645 00646 static float screen_aligned(RegionView3D *rv3d, float mat[][4]) 00647 { 00648 glTranslatef(mat[3][0], mat[3][1], mat[3][2]); 00649 00650 /* sets view screen aligned */ 00651 glRotatef( -360.0f*saacos(rv3d->viewquat[0])/(float)M_PI, rv3d->viewquat[1], rv3d->viewquat[2], rv3d->viewquat[3]); 00652 00653 return len_v3(mat[0]); /* draw scale */ 00654 } 00655 00656 00657 /* radring = radius of donut rings 00658 radhole = radius hole 00659 start = starting segment (based on nrings) 00660 end = end segment 00661 nsides = amount of points in ring 00662 nrigns = amount of rings 00663 */ 00664 static void partial_donut(float radring, float radhole, int start, int end, int nsides, int nrings) 00665 { 00666 float theta, phi, theta1; 00667 float cos_theta, sin_theta; 00668 float cos_theta1, sin_theta1; 00669 float ring_delta, side_delta; 00670 int i, j, docaps= 1; 00671 00672 if(start==0 && end==nrings) docaps= 0; 00673 00674 ring_delta= 2.0f*(float)M_PI/(float)nrings; 00675 side_delta= 2.0f*(float)M_PI/(float)nsides; 00676 00677 theta= (float)M_PI+0.5f*ring_delta; 00678 cos_theta= (float)cos(theta); 00679 sin_theta= (float)sin(theta); 00680 00681 for(i= nrings - 1; i >= 0; i--) { 00682 theta1= theta + ring_delta; 00683 cos_theta1= (float)cos(theta1); 00684 sin_theta1= (float)sin(theta1); 00685 00686 if(docaps && i==start) { // cap 00687 glBegin(GL_POLYGON); 00688 phi= 0.0; 00689 for(j= nsides; j >= 0; j--) { 00690 float cos_phi, sin_phi, dist; 00691 00692 phi += side_delta; 00693 cos_phi= (float)cos(phi); 00694 sin_phi= (float)sin(phi); 00695 dist= radhole + radring * cos_phi; 00696 00697 glVertex3f(cos_theta1 * dist, -sin_theta1 * dist, radring * sin_phi); 00698 } 00699 glEnd(); 00700 } 00701 if(i>=start && i<=end) { 00702 glBegin(GL_QUAD_STRIP); 00703 phi= 0.0; 00704 for(j= nsides; j >= 0; j--) { 00705 float cos_phi, sin_phi, dist; 00706 00707 phi += side_delta; 00708 cos_phi= (float)cos(phi); 00709 sin_phi= (float)sin(phi); 00710 dist= radhole + radring * cos_phi; 00711 00712 glVertex3f(cos_theta1 * dist, -sin_theta1 * dist, radring * sin_phi); 00713 glVertex3f(cos_theta * dist, -sin_theta * dist, radring * sin_phi); 00714 } 00715 glEnd(); 00716 } 00717 00718 if(docaps && i==end) { // cap 00719 glBegin(GL_POLYGON); 00720 phi= 0.0; 00721 for(j= nsides; j >= 0; j--) { 00722 float cos_phi, sin_phi, dist; 00723 00724 phi -= side_delta; 00725 cos_phi= (float)cos(phi); 00726 sin_phi= (float)sin(phi); 00727 dist= radhole + radring * cos_phi; 00728 00729 glVertex3f(cos_theta * dist, -sin_theta * dist, radring * sin_phi); 00730 } 00731 glEnd(); 00732 } 00733 00734 00735 theta= theta1; 00736 cos_theta= cos_theta1; 00737 sin_theta= sin_theta1; 00738 } 00739 } 00740 00741 static char axisBlendAngle(float angle) 00742 { 00743 if (angle > 20) 00744 return 255; 00745 00746 if (angle < 5) 00747 return 0; 00748 00749 return (char)(255.0f * (angle - 5) / 15.0f); 00750 } 00751 00752 /* three colors can be set; 00753 grey for ghosting 00754 moving: in transform theme color 00755 else the red/green/blue 00756 */ 00757 static void manipulator_setcolor(View3D *v3d, char axis, int colcode, unsigned char alpha) 00758 { 00759 unsigned char col[4]= {0}; 00760 col[3]= alpha; 00761 00762 if(colcode==MAN_GHOST) { 00763 col[3]= 70; 00764 } 00765 else if(colcode==MAN_MOVECOL) { 00766 UI_GetThemeColor3ubv(TH_TRANSFORM, col); 00767 } 00768 else { 00769 switch(axis) { 00770 case 'C': 00771 UI_GetThemeColor3ubv(TH_TRANSFORM, col); 00772 if(v3d->twmode == V3D_MANIP_LOCAL) { 00773 col[0]= col[0]>200?255:col[0]+55; 00774 col[1]= col[1]>200?255:col[1]+55; 00775 col[2]= col[2]>200?255:col[2]+55; 00776 } 00777 else if(v3d->twmode == V3D_MANIP_NORMAL) { 00778 col[0]= col[0]<55?0:col[0]-55; 00779 col[1]= col[1]<55?0:col[1]-55; 00780 col[2]= col[2]<55?0:col[2]-55; 00781 } 00782 break; 00783 case 'X': 00784 col[0]= 220; 00785 break; 00786 case 'Y': 00787 col[1]= 220; 00788 break; 00789 case 'Z': 00790 col[0]= 30; 00791 col[1]= 30; 00792 col[2]= 220; 00793 break; 00794 default: 00795 BLI_assert(!"invalid axis arg"); 00796 } 00797 } 00798 00799 glColor4ubv(col); 00800 } 00801 00802 /* viewmatrix should have been set OK, also no shademode! */ 00803 static void draw_manipulator_axes(View3D *v3d, RegionView3D *rv3d, int colcode, int flagx, int flagy, int flagz) 00804 { 00805 00806 /* axes */ 00807 if(flagx) { 00808 manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->twangle[0])); 00809 if(flagx & MAN_SCALE_X) glLoadName(MAN_SCALE_X); 00810 else if(flagx & MAN_TRANS_X) glLoadName(MAN_TRANS_X); 00811 glBegin(GL_LINES); 00812 glVertex3f(0.2f, 0.0f, 0.0f); 00813 glVertex3f(1.0f, 0.0f, 0.0f); 00814 glEnd(); 00815 } 00816 if(flagy) { 00817 if(flagy & MAN_SCALE_Y) glLoadName(MAN_SCALE_Y); 00818 else if(flagy & MAN_TRANS_Y) glLoadName(MAN_TRANS_Y); 00819 manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->twangle[1])); 00820 glBegin(GL_LINES); 00821 glVertex3f(0.0f, 0.2f, 0.0f); 00822 glVertex3f(0.0f, 1.0f, 0.0f); 00823 glEnd(); 00824 } 00825 if(flagz) { 00826 if(flagz & MAN_SCALE_Z) glLoadName(MAN_SCALE_Z); 00827 else if(flagz & MAN_TRANS_Z) glLoadName(MAN_TRANS_Z); 00828 manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->twangle[2])); 00829 glBegin(GL_LINES); 00830 glVertex3f(0.0f, 0.0f, 0.2f); 00831 glVertex3f(0.0f, 0.0f, 1.0f); 00832 glEnd(); 00833 } 00834 } 00835 00836 static void preOrthoFront(int ortho, float twmat[][4], int axis) 00837 { 00838 if (ortho == 0) { 00839 float omat[4][4]; 00840 copy_m4_m4(omat, twmat); 00841 orthogonalize_m4(omat, axis); 00842 glPushMatrix(); 00843 glMultMatrixf(omat); 00844 glFrontFace(is_negative_m4(omat) ? GL_CW:GL_CCW); 00845 } 00846 } 00847 00848 static void postOrtho(int ortho) 00849 { 00850 if (ortho == 0) { 00851 glPopMatrix(); 00852 } 00853 } 00854 00855 static void draw_manipulator_rotate(View3D *v3d, RegionView3D *rv3d, int moving, int drawflags, int combo) 00856 { 00857 GLUquadricObj *qobj; 00858 double plane[4]; 00859 float matt[4][4]; 00860 float size, unitmat[4][4]; 00861 float cywid= 0.33f*0.01f*(float)U.tw_handlesize; 00862 float cusize= cywid*0.65f; 00863 int arcs= (G.rt!=2); 00864 int colcode; 00865 int ortho; 00866 00867 if(moving) colcode= MAN_MOVECOL; 00868 else colcode= MAN_RGB; 00869 00870 /* when called while moving in mixed mode, do not draw when... */ 00871 if((drawflags & MAN_ROT_C)==0) return; 00872 00873 /* Init stuff */ 00874 glDisable(GL_DEPTH_TEST); 00875 unit_m4(unitmat); 00876 00877 qobj= gluNewQuadric(); 00878 gluQuadricDrawStyle(qobj, GLU_FILL); 00879 00880 /* prepare for screen aligned draw */ 00881 size= len_v3(rv3d->twmat[0]); 00882 glPushMatrix(); 00883 glTranslatef(rv3d->twmat[3][0], rv3d->twmat[3][1], rv3d->twmat[3][2]); 00884 00885 if(arcs) { 00886 /* clipplane makes nice handles, calc here because of multmatrix but with translate! */ 00887 VECCOPY(plane, rv3d->viewinv[2]); 00888 plane[3]= -0.02f*size; // clip just a bit more 00889 glClipPlane(GL_CLIP_PLANE0, plane); 00890 } 00891 /* sets view screen aligned */ 00892 glRotatef( -360.0f*saacos(rv3d->viewquat[0])/(float)M_PI, rv3d->viewquat[1], rv3d->viewquat[2], rv3d->viewquat[3]); 00893 00894 /* Screen aligned help circle */ 00895 if(arcs) { 00896 if((G.f & G_PICKSEL)==0) { 00897 UI_ThemeColorShade(TH_BACK, -30); 00898 drawcircball(GL_LINE_LOOP, unitmat[3], size, unitmat); 00899 } 00900 } 00901 00902 /* Screen aligned trackball rot circle */ 00903 if(drawflags & MAN_ROT_T) { 00904 if(G.f & G_PICKSEL) glLoadName(MAN_ROT_T); 00905 00906 UI_ThemeColor(TH_TRANSFORM); 00907 drawcircball(GL_LINE_LOOP, unitmat[3], 0.2f*size, unitmat); 00908 } 00909 00910 /* Screen aligned view rot circle */ 00911 if(drawflags & MAN_ROT_V) { 00912 if(G.f & G_PICKSEL) glLoadName(MAN_ROT_V); 00913 UI_ThemeColor(TH_TRANSFORM); 00914 drawcircball(GL_LINE_LOOP, unitmat[3], 1.2f*size, unitmat); 00915 00916 if(moving) { 00917 float vec[3]; 00918 vec[0]= 0; // XXX (float)(t->imval[0] - t->center2d[0]); 00919 vec[1]= 0; // XXX (float)(t->imval[1] - t->center2d[1]); 00920 vec[2]= 0.0f; 00921 normalize_v3(vec); 00922 mul_v3_fl(vec, 1.2f*size); 00923 glBegin(GL_LINES); 00924 glVertex3f(0.0f, 0.0f, 0.0f); 00925 glVertex3fv(vec); 00926 glEnd(); 00927 } 00928 } 00929 glPopMatrix(); 00930 00931 00932 ortho = is_orthogonal_m4(rv3d->twmat); 00933 00934 /* apply the transform delta */ 00935 if(moving) { 00936 copy_m4_m4(matt, rv3d->twmat); // to copy the parts outside of [3][3] 00937 // XXX mul_m4_m3m4(matt, t->mat, rv3d->twmat); 00938 if (ortho) { 00939 glMultMatrixf(matt); 00940 glFrontFace(is_negative_m4(matt) ? GL_CW:GL_CCW); 00941 } 00942 } 00943 else { 00944 if (ortho) { 00945 glFrontFace(is_negative_m4(rv3d->twmat) ? GL_CW:GL_CCW); 00946 glMultMatrixf(rv3d->twmat); 00947 } 00948 } 00949 00950 /* axes */ 00951 if(arcs==0) { 00952 if(!(G.f & G_PICKSEL)) { 00953 if( (combo & V3D_MANIP_SCALE)==0) { 00954 /* axis */ 00955 if( (drawflags & MAN_ROT_X) || (moving && (drawflags & MAN_ROT_Z)) ) { 00956 preOrthoFront(ortho, rv3d->twmat, 2); 00957 manipulator_setcolor(v3d, 'X', colcode, 255); 00958 glBegin(GL_LINES); 00959 glVertex3f(0.2f, 0.0f, 0.0f); 00960 glVertex3f(1.0f, 0.0f, 0.0f); 00961 glEnd(); 00962 postOrtho(ortho); 00963 } 00964 if( (drawflags & MAN_ROT_Y) || (moving && (drawflags & MAN_ROT_X)) ) { 00965 preOrthoFront(ortho, rv3d->twmat, 0); 00966 manipulator_setcolor(v3d, 'Y', colcode, 255); 00967 glBegin(GL_LINES); 00968 glVertex3f(0.0f, 0.2f, 0.0f); 00969 glVertex3f(0.0f, 1.0f, 0.0f); 00970 glEnd(); 00971 postOrtho(ortho); 00972 } 00973 if( (drawflags & MAN_ROT_Z) || (moving && (drawflags & MAN_ROT_Y)) ) { 00974 preOrthoFront(ortho, rv3d->twmat, 1); 00975 manipulator_setcolor(v3d, 'Z', colcode, 255); 00976 glBegin(GL_LINES); 00977 glVertex3f(0.0f, 0.0f, 0.2f); 00978 glVertex3f(0.0f, 0.0f, 1.0f); 00979 glEnd(); 00980 postOrtho(ortho); 00981 } 00982 } 00983 } 00984 } 00985 00986 if(arcs==0 && moving) { 00987 00988 /* Z circle */ 00989 if(drawflags & MAN_ROT_Z) { 00990 preOrthoFront(ortho, matt, 2); 00991 if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Z); 00992 manipulator_setcolor(v3d, 'Z', colcode, 255); 00993 drawcircball(GL_LINE_LOOP, unitmat[3], 1.0, unitmat); 00994 postOrtho(ortho); 00995 } 00996 /* X circle */ 00997 if(drawflags & MAN_ROT_X) { 00998 preOrthoFront(ortho, matt, 0); 00999 if(G.f & G_PICKSEL) glLoadName(MAN_ROT_X); 01000 glRotatef(90.0, 0.0, 1.0, 0.0); 01001 manipulator_setcolor(v3d, 'X', colcode, 255); 01002 drawcircball(GL_LINE_LOOP, unitmat[3], 1.0, unitmat); 01003 glRotatef(-90.0, 0.0, 1.0, 0.0); 01004 postOrtho(ortho); 01005 } 01006 /* Y circle */ 01007 if(drawflags & MAN_ROT_Y) { 01008 preOrthoFront(ortho, matt, 1); 01009 if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Y); 01010 glRotatef(-90.0, 1.0, 0.0, 0.0); 01011 manipulator_setcolor(v3d, 'Y', colcode, 255); 01012 drawcircball(GL_LINE_LOOP, unitmat[3], 1.0, unitmat); 01013 glRotatef(90.0, 1.0, 0.0, 0.0); 01014 postOrtho(ortho); 01015 } 01016 01017 if(arcs) glDisable(GL_CLIP_PLANE0); 01018 } 01019 // donut arcs 01020 if(arcs) { 01021 glEnable(GL_CLIP_PLANE0); 01022 01023 /* Z circle */ 01024 if(drawflags & MAN_ROT_Z) { 01025 preOrthoFront(ortho, rv3d->twmat, 2); 01026 if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Z); 01027 manipulator_setcolor(v3d, 'Z', colcode, 255); 01028 partial_donut(cusize/4.0f, 1.0f, 0, 48, 8, 48); 01029 postOrtho(ortho); 01030 } 01031 /* X circle */ 01032 if(drawflags & MAN_ROT_X) { 01033 preOrthoFront(ortho, rv3d->twmat, 0); 01034 if(G.f & G_PICKSEL) glLoadName(MAN_ROT_X); 01035 glRotatef(90.0, 0.0, 1.0, 0.0); 01036 manipulator_setcolor(v3d, 'X', colcode, 255); 01037 partial_donut(cusize/4.0f, 1.0f, 0, 48, 8, 48); 01038 glRotatef(-90.0, 0.0, 1.0, 0.0); 01039 postOrtho(ortho); 01040 } 01041 /* Y circle */ 01042 if(drawflags & MAN_ROT_Y) { 01043 preOrthoFront(ortho, rv3d->twmat, 1); 01044 if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Y); 01045 glRotatef(-90.0, 1.0, 0.0, 0.0); 01046 manipulator_setcolor(v3d, 'Y', colcode, 255); 01047 partial_donut(cusize/4.0f, 1.0f, 0, 48, 8, 48); 01048 glRotatef(90.0, 1.0, 0.0, 0.0); 01049 postOrtho(ortho); 01050 } 01051 01052 glDisable(GL_CLIP_PLANE0); 01053 } 01054 01055 if(arcs==0) { 01056 01057 /* Z handle on X axis */ 01058 if(drawflags & MAN_ROT_Z) { 01059 preOrthoFront(ortho, rv3d->twmat, 2); 01060 glPushMatrix(); 01061 if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Z); 01062 manipulator_setcolor(v3d, 'Z', colcode, 255); 01063 01064 partial_donut(0.7f*cusize, 1.0f, 31, 33, 8, 64); 01065 01066 glPopMatrix(); 01067 postOrtho(ortho); 01068 } 01069 01070 /* Y handle on X axis */ 01071 if(drawflags & MAN_ROT_Y) { 01072 preOrthoFront(ortho, rv3d->twmat, 1); 01073 glPushMatrix(); 01074 if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Y); 01075 manipulator_setcolor(v3d, 'Y', colcode, 255); 01076 01077 glRotatef(90.0, 1.0, 0.0, 0.0); 01078 glRotatef(90.0, 0.0, 0.0, 1.0); 01079 partial_donut(0.7f*cusize, 1.0f, 31, 33, 8, 64); 01080 01081 glPopMatrix(); 01082 postOrtho(ortho); 01083 } 01084 01085 /* X handle on Z axis */ 01086 if(drawflags & MAN_ROT_X) { 01087 preOrthoFront(ortho, rv3d->twmat, 0); 01088 glPushMatrix(); 01089 if(G.f & G_PICKSEL) glLoadName(MAN_ROT_X); 01090 manipulator_setcolor(v3d, 'X', colcode, 255); 01091 01092 glRotatef(-90.0, 0.0, 1.0, 0.0); 01093 glRotatef(90.0, 0.0, 0.0, 1.0); 01094 partial_donut(0.7f*cusize, 1.0f, 31, 33, 8, 64); 01095 01096 glPopMatrix(); 01097 postOrtho(ortho); 01098 } 01099 01100 } 01101 01102 /* restore */ 01103 glLoadMatrixf(rv3d->viewmat); 01104 gluDeleteQuadric(qobj); 01105 if(v3d->zbuf) glEnable(GL_DEPTH_TEST); 01106 01107 } 01108 01109 static void drawsolidcube(float size) 01110 { 01111 static float cube[8][3] = { 01112 {-1.0, -1.0, -1.0}, 01113 {-1.0, -1.0, 1.0}, 01114 {-1.0, 1.0, 1.0}, 01115 {-1.0, 1.0, -1.0}, 01116 { 1.0, -1.0, -1.0}, 01117 { 1.0, -1.0, 1.0}, 01118 { 1.0, 1.0, 1.0}, 01119 { 1.0, 1.0, -1.0}, }; 01120 float n[3]; 01121 01122 glPushMatrix(); 01123 glScalef(size, size, size); 01124 01125 n[0]=0; n[1]=0; n[2]=0; 01126 glBegin(GL_QUADS); 01127 n[0]= -1.0; 01128 glNormal3fv(n); 01129 glVertex3fv(cube[0]); glVertex3fv(cube[1]); glVertex3fv(cube[2]); glVertex3fv(cube[3]); 01130 n[0]=0; 01131 glEnd(); 01132 01133 glBegin(GL_QUADS); 01134 n[1]= -1.0; 01135 glNormal3fv(n); 01136 glVertex3fv(cube[0]); glVertex3fv(cube[4]); glVertex3fv(cube[5]); glVertex3fv(cube[1]); 01137 n[1]=0; 01138 glEnd(); 01139 01140 glBegin(GL_QUADS); 01141 n[0]= 1.0; 01142 glNormal3fv(n); 01143 glVertex3fv(cube[4]); glVertex3fv(cube[7]); glVertex3fv(cube[6]); glVertex3fv(cube[5]); 01144 n[0]=0; 01145 glEnd(); 01146 01147 glBegin(GL_QUADS); 01148 n[1]= 1.0; 01149 glNormal3fv(n); 01150 glVertex3fv(cube[7]); glVertex3fv(cube[3]); glVertex3fv(cube[2]); glVertex3fv(cube[6]); 01151 n[1]=0; 01152 glEnd(); 01153 01154 glBegin(GL_QUADS); 01155 n[2]= 1.0; 01156 glNormal3fv(n); 01157 glVertex3fv(cube[1]); glVertex3fv(cube[5]); glVertex3fv(cube[6]); glVertex3fv(cube[2]); 01158 n[2]=0; 01159 glEnd(); 01160 01161 glBegin(GL_QUADS); 01162 n[2]= -1.0; 01163 glNormal3fv(n); 01164 glVertex3fv(cube[7]); glVertex3fv(cube[4]); glVertex3fv(cube[0]); glVertex3fv(cube[3]); 01165 glEnd(); 01166 01167 glPopMatrix(); 01168 } 01169 01170 01171 static void draw_manipulator_scale(View3D *v3d, RegionView3D *rv3d, int moving, int drawflags, int combo, int colcode) 01172 { 01173 float cywid= 0.25f*0.01f*(float)U.tw_handlesize; 01174 float cusize= cywid*0.75f, dz; 01175 01176 /* when called while moving in mixed mode, do not draw when... */ 01177 if((drawflags & MAN_SCALE_C)==0) return; 01178 01179 glDisable(GL_DEPTH_TEST); 01180 01181 /* not in combo mode */ 01182 if( (combo & (V3D_MANIP_TRANSLATE|V3D_MANIP_ROTATE))==0) { 01183 float size, unitmat[4][4]; 01184 int shift= 0; // XXX 01185 01186 /* center circle, do not add to selection when shift is pressed (planar constraint) */ 01187 if( (G.f & G_PICKSEL) && shift==0) glLoadName(MAN_SCALE_C); 01188 01189 manipulator_setcolor(v3d, 'C', colcode, 255); 01190 glPushMatrix(); 01191 size= screen_aligned(rv3d, rv3d->twmat); 01192 unit_m4(unitmat); 01193 drawcircball(GL_LINE_LOOP, unitmat[3], 0.2f*size, unitmat); 01194 glPopMatrix(); 01195 01196 dz= 1.0; 01197 } 01198 else dz= 1.0f-4.0f*cusize; 01199 01200 if(moving) { 01201 float matt[4][4]; 01202 01203 copy_m4_m4(matt, rv3d->twmat); // to copy the parts outside of [3][3] 01204 // XXX mul_m4_m3m4(matt, t->mat, rv3d->twmat); 01205 glMultMatrixf(matt); 01206 glFrontFace(is_negative_m4(matt) ? GL_CW:GL_CCW); 01207 } 01208 else { 01209 glMultMatrixf(rv3d->twmat); 01210 glFrontFace(is_negative_m4(rv3d->twmat) ? GL_CW:GL_CCW); 01211 } 01212 01213 /* axis */ 01214 01215 /* in combo mode, this is always drawn as first type */ 01216 draw_manipulator_axes(v3d, rv3d, colcode, drawflags & MAN_SCALE_X, drawflags & MAN_SCALE_Y, drawflags & MAN_SCALE_Z); 01217 01218 /* Z cube */ 01219 glTranslatef(0.0, 0.0, dz); 01220 if(drawflags & MAN_SCALE_Z) { 01221 if(G.f & G_PICKSEL) glLoadName(MAN_SCALE_Z); 01222 manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->twangle[2])); 01223 drawsolidcube(cusize); 01224 } 01225 /* X cube */ 01226 glTranslatef(dz, 0.0, -dz); 01227 if(drawflags & MAN_SCALE_X) { 01228 if(G.f & G_PICKSEL) glLoadName(MAN_SCALE_X); 01229 manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->twangle[0])); 01230 drawsolidcube(cusize); 01231 } 01232 /* Y cube */ 01233 glTranslatef(-dz, dz, 0.0); 01234 if(drawflags & MAN_SCALE_Y) { 01235 if(G.f & G_PICKSEL) glLoadName(MAN_SCALE_Y); 01236 manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->twangle[1])); 01237 drawsolidcube(cusize); 01238 } 01239 01240 /* if shiftkey, center point as last, for selectbuffer order */ 01241 if(G.f & G_PICKSEL) { 01242 int shift= 0; // XXX 01243 01244 if(shift) { 01245 glTranslatef(0.0, -dz, 0.0); 01246 glLoadName(MAN_SCALE_C); 01247 glBegin(GL_POINTS); 01248 glVertex3f(0.0, 0.0, 0.0); 01249 glEnd(); 01250 } 01251 } 01252 01253 /* restore */ 01254 glLoadMatrixf(rv3d->viewmat); 01255 01256 if(v3d->zbuf) glEnable(GL_DEPTH_TEST); 01257 glFrontFace(GL_CCW); 01258 } 01259 01260 01261 static void draw_cone(GLUquadricObj *qobj, float len, float width) 01262 { 01263 glTranslatef(0.0, 0.0, -0.5f*len); 01264 gluCylinder(qobj, width, 0.0, len, 8, 1); 01265 gluQuadricOrientation(qobj, GLU_INSIDE); 01266 gluDisk(qobj, 0.0, width, 8, 1); 01267 gluQuadricOrientation(qobj, GLU_OUTSIDE); 01268 glTranslatef(0.0, 0.0, 0.5f*len); 01269 } 01270 01271 static void draw_cylinder(GLUquadricObj *qobj, float len, float width) 01272 { 01273 01274 width*= 0.8f; // just for beauty 01275 01276 glTranslatef(0.0, 0.0, -0.5f*len); 01277 gluCylinder(qobj, width, width, len, 8, 1); 01278 gluQuadricOrientation(qobj, GLU_INSIDE); 01279 gluDisk(qobj, 0.0, width, 8, 1); 01280 gluQuadricOrientation(qobj, GLU_OUTSIDE); 01281 glTranslatef(0.0, 0.0, len); 01282 gluDisk(qobj, 0.0, width, 8, 1); 01283 glTranslatef(0.0, 0.0, -0.5f*len); 01284 } 01285 01286 01287 static void draw_manipulator_translate(View3D *v3d, RegionView3D *rv3d, int UNUSED(moving), int drawflags, int combo, int colcode) 01288 { 01289 GLUquadricObj *qobj; 01290 float cylen= 0.01f*(float)U.tw_handlesize; 01291 float cywid= 0.25f*cylen, dz, size; 01292 float unitmat[4][4]; 01293 int shift= 0; // XXX 01294 01295 /* when called while moving in mixed mode, do not draw when... */ 01296 if((drawflags & MAN_TRANS_C)==0) return; 01297 01298 // XXX if(moving) glTranslatef(t->vec[0], t->vec[1], t->vec[2]); 01299 glDisable(GL_DEPTH_TEST); 01300 01301 qobj= gluNewQuadric(); 01302 gluQuadricDrawStyle(qobj, GLU_FILL); 01303 01304 /* center circle, do not add to selection when shift is pressed (planar constraint) */ 01305 if( (G.f & G_PICKSEL) && shift==0) glLoadName(MAN_TRANS_C); 01306 01307 manipulator_setcolor(v3d, 'C', colcode, 255); 01308 glPushMatrix(); 01309 size= screen_aligned(rv3d, rv3d->twmat); 01310 unit_m4(unitmat); 01311 drawcircball(GL_LINE_LOOP, unitmat[3], 0.2f*size, unitmat); 01312 glPopMatrix(); 01313 01314 /* and now apply matrix, we move to local matrix drawing */ 01315 glMultMatrixf(rv3d->twmat); 01316 01317 /* axis */ 01318 glLoadName(-1); 01319 01320 // translate drawn as last, only axis when no combo with scale, or for ghosting 01321 if((combo & V3D_MANIP_SCALE)==0 || colcode==MAN_GHOST) 01322 draw_manipulator_axes(v3d, rv3d, colcode, drawflags & MAN_TRANS_X, drawflags & MAN_TRANS_Y, drawflags & MAN_TRANS_Z); 01323 01324 01325 /* offset in combo mode, for rotate a bit more */ 01326 if(combo & (V3D_MANIP_ROTATE)) dz= 1.0f+2.0f*cylen; 01327 else if(combo & (V3D_MANIP_SCALE)) dz= 1.0f+0.5f*cylen; 01328 else dz= 1.0f; 01329 01330 /* Z Cone */ 01331 glTranslatef(0.0, 0.0, dz); 01332 if(drawflags & MAN_TRANS_Z) { 01333 if(G.f & G_PICKSEL) glLoadName(MAN_TRANS_Z); 01334 manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->twangle[2])); 01335 draw_cone(qobj, cylen, cywid); 01336 } 01337 /* X Cone */ 01338 glTranslatef(dz, 0.0, -dz); 01339 if(drawflags & MAN_TRANS_X) { 01340 if(G.f & G_PICKSEL) glLoadName(MAN_TRANS_X); 01341 glRotatef(90.0, 0.0, 1.0, 0.0); 01342 manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->twangle[0])); 01343 draw_cone(qobj, cylen, cywid); 01344 glRotatef(-90.0, 0.0, 1.0, 0.0); 01345 } 01346 /* Y Cone */ 01347 glTranslatef(-dz, dz, 0.0); 01348 if(drawflags & MAN_TRANS_Y) { 01349 if(G.f & G_PICKSEL) glLoadName(MAN_TRANS_Y); 01350 glRotatef(-90.0, 1.0, 0.0, 0.0); 01351 manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->twangle[1])); 01352 draw_cone(qobj, cylen, cywid); 01353 } 01354 01355 gluDeleteQuadric(qobj); 01356 glLoadMatrixf(rv3d->viewmat); 01357 01358 if(v3d->zbuf) glEnable(GL_DEPTH_TEST); 01359 01360 } 01361 01362 static void draw_manipulator_rotate_cyl(View3D *v3d, RegionView3D *rv3d, int moving, int drawflags, int combo, int colcode) 01363 { 01364 GLUquadricObj *qobj; 01365 float size; 01366 float cylen= 0.01f*(float)U.tw_handlesize; 01367 float cywid= 0.25f*cylen; 01368 01369 /* when called while moving in mixed mode, do not draw when... */ 01370 if((drawflags & MAN_ROT_C)==0) return; 01371 01372 /* prepare for screen aligned draw */ 01373 glPushMatrix(); 01374 size= screen_aligned(rv3d, rv3d->twmat); 01375 01376 glDisable(GL_DEPTH_TEST); 01377 01378 qobj= gluNewQuadric(); 01379 01380 /* Screen aligned view rot circle */ 01381 if(drawflags & MAN_ROT_V) { 01382 float unitmat[4][4]= MAT4_UNITY; 01383 01384 if(G.f & G_PICKSEL) glLoadName(MAN_ROT_V); 01385 UI_ThemeColor(TH_TRANSFORM); 01386 drawcircball(GL_LINE_LOOP, unitmat[3], 1.2f*size, unitmat); 01387 01388 if(moving) { 01389 float vec[3]; 01390 vec[0]= 0; // XXX (float)(t->imval[0] - t->center2d[0]); 01391 vec[1]= 0; // XXX (float)(t->imval[1] - t->center2d[1]); 01392 vec[2]= 0.0f; 01393 normalize_v3(vec); 01394 mul_v3_fl(vec, 1.2f*size); 01395 glBegin(GL_LINES); 01396 glVertex3f(0.0, 0.0, 0.0); 01397 glVertex3fv(vec); 01398 glEnd(); 01399 } 01400 } 01401 glPopMatrix(); 01402 01403 /* apply the transform delta */ 01404 if(moving) { 01405 float matt[4][4]; 01406 copy_m4_m4(matt, rv3d->twmat); // to copy the parts outside of [3][3] 01407 // XXX if (t->flag & T_USES_MANIPULATOR) { 01408 // XXX mul_m4_m3m4(matt, t->mat, rv3d->twmat); 01409 // XXX } 01410 glMultMatrixf(matt); 01411 } 01412 else { 01413 glMultMatrixf(rv3d->twmat); 01414 } 01415 01416 glFrontFace(is_negative_m4(rv3d->twmat) ? GL_CW:GL_CCW); 01417 01418 /* axis */ 01419 if( (G.f & G_PICKSEL)==0 ) { 01420 01421 // only draw axis when combo didn't draw scale axes 01422 if((combo & V3D_MANIP_SCALE)==0) 01423 draw_manipulator_axes(v3d, rv3d, colcode, drawflags & MAN_ROT_X, drawflags & MAN_ROT_Y, drawflags & MAN_ROT_Z); 01424 01425 /* only has to be set when not in picking */ 01426 gluQuadricDrawStyle(qobj, GLU_FILL); 01427 } 01428 01429 /* Z cyl */ 01430 glTranslatef(0.0, 0.0, 1.0); 01431 if(drawflags & MAN_ROT_Z) { 01432 if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Z); 01433 manipulator_setcolor(v3d, 'Z', colcode, 255); 01434 draw_cylinder(qobj, cylen, cywid); 01435 } 01436 /* X cyl */ 01437 glTranslatef(1.0, 0.0, -1.0); 01438 if(drawflags & MAN_ROT_X) { 01439 if(G.f & G_PICKSEL) glLoadName(MAN_ROT_X); 01440 glRotatef(90.0, 0.0, 1.0, 0.0); 01441 manipulator_setcolor(v3d, 'X', colcode, 255); 01442 draw_cylinder(qobj, cylen, cywid); 01443 glRotatef(-90.0, 0.0, 1.0, 0.0); 01444 } 01445 /* Y cylinder */ 01446 glTranslatef(-1.0, 1.0, 0.0); 01447 if(drawflags & MAN_ROT_Y) { 01448 if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Y); 01449 glRotatef(-90.0, 1.0, 0.0, 0.0); 01450 manipulator_setcolor(v3d, 'Y', colcode, 255); 01451 draw_cylinder(qobj, cylen, cywid); 01452 } 01453 01454 /* restore */ 01455 01456 gluDeleteQuadric(qobj); 01457 glLoadMatrixf(rv3d->viewmat); 01458 01459 if(v3d->zbuf) glEnable(GL_DEPTH_TEST); 01460 01461 } 01462 01463 01464 /* ********************************************* */ 01465 01466 /* main call, does calc centers & orientation too */ 01467 /* uses global G.moving */ 01468 static int drawflags= 0xFFFF; // only for the calls below, belongs in scene...? 01469 01470 void BIF_draw_manipulator(const bContext *C) 01471 { 01472 ScrArea *sa= CTX_wm_area(C); 01473 ARegion *ar= CTX_wm_region(C); 01474 Scene *scene= CTX_data_scene(C); 01475 View3D *v3d= sa->spacedata.first; 01476 RegionView3D *rv3d= ar->regiondata; 01477 int totsel; 01478 01479 if(!(v3d->twflag & V3D_USE_MANIPULATOR)) return; 01480 // if(G.moving && (G.moving & G_TRANSFORM_MANIP)==0) return; 01481 01482 // if(G.moving==0) { 01483 { 01484 v3d->twflag &= ~V3D_DRAW_MANIPULATOR; 01485 01486 totsel= calc_manipulator_stats(C); 01487 if(totsel==0) return; 01488 01489 v3d->twflag |= V3D_DRAW_MANIPULATOR; 01490 01491 /* now we can define center */ 01492 switch(v3d->around) { 01493 case V3D_CENTER: 01494 case V3D_ACTIVE: 01495 rv3d->twmat[3][0]= (scene->twmin[0] + scene->twmax[0])/2.0f; 01496 rv3d->twmat[3][1]= (scene->twmin[1] + scene->twmax[1])/2.0f; 01497 rv3d->twmat[3][2]= (scene->twmin[2] + scene->twmax[2])/2.0f; 01498 if(v3d->around==V3D_ACTIVE && scene->obedit==NULL) { 01499 Object *ob= OBACT; 01500 if(ob && !(ob->mode & OB_MODE_POSE)) 01501 VECCOPY(rv3d->twmat[3], ob->obmat[3]); 01502 } 01503 break; 01504 case V3D_LOCAL: 01505 case V3D_CENTROID: 01506 VECCOPY(rv3d->twmat[3], scene->twcent); 01507 break; 01508 case V3D_CURSOR: 01509 VECCOPY(rv3d->twmat[3], give_cursor(scene, v3d)); 01510 break; 01511 } 01512 01513 mul_mat3_m4_fl(rv3d->twmat, ED_view3d_pixel_size(rv3d, rv3d->twmat[3]) * U.tw_size * 5.0f); 01514 } 01515 01516 test_manipulator_axis(C); 01517 drawflags= rv3d->twdrawflag; /* set in calc_manipulator_stats */ 01518 01519 if(v3d->twflag & V3D_DRAW_MANIPULATOR) { 01520 01521 glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); 01522 glEnable(GL_BLEND); 01523 if(v3d->twtype & V3D_MANIP_ROTATE) { 01524 01525 if(G.rt==3) { 01526 if(G.moving) draw_manipulator_rotate_cyl(v3d, rv3d, 1, drawflags, v3d->twtype, MAN_MOVECOL); 01527 else draw_manipulator_rotate_cyl(v3d, rv3d, 0, drawflags, v3d->twtype, MAN_RGB); 01528 } 01529 else 01530 draw_manipulator_rotate(v3d, rv3d, 0 /* G.moving*/, drawflags, v3d->twtype); 01531 } 01532 if(v3d->twtype & V3D_MANIP_SCALE) { 01533 draw_manipulator_scale(v3d, rv3d, 0, drawflags, v3d->twtype, MAN_RGB); 01534 } 01535 if(v3d->twtype & V3D_MANIP_TRANSLATE) { 01536 draw_manipulator_translate(v3d, rv3d, 0, drawflags, v3d->twtype, MAN_RGB); 01537 } 01538 01539 glDisable(GL_BLEND); 01540 } 01541 } 01542 01543 static int manipulator_selectbuf(ScrArea *sa, ARegion *ar, const int mval[2], float hotspot) 01544 { 01545 View3D *v3d= sa->spacedata.first; 01546 RegionView3D *rv3d= ar->regiondata; 01547 rctf rect; 01548 GLuint buffer[64]; // max 4 items per select, so large enuf 01549 short hits; 01550 extern void setwinmatrixview3d(ARegion *ar, View3D *v3d, rctf *rect); // XXX check a bit later on this... (ton) 01551 01552 G.f |= G_PICKSEL; 01553 01554 rect.xmin= mval[0]-hotspot; 01555 rect.xmax= mval[0]+hotspot; 01556 rect.ymin= mval[1]-hotspot; 01557 rect.ymax= mval[1]+hotspot; 01558 01559 setwinmatrixview3d(ar, v3d, &rect); 01560 mul_m4_m4m4(rv3d->persmat, rv3d->viewmat, rv3d->winmat); 01561 01562 glSelectBuffer( 64, buffer); 01563 glRenderMode(GL_SELECT); 01564 glInitNames(); /* these two calls whatfor? It doesnt work otherwise */ 01565 glPushName(-2); 01566 01567 /* do the drawing */ 01568 if(v3d->twtype & V3D_MANIP_ROTATE) { 01569 if(G.rt==3) draw_manipulator_rotate_cyl(v3d, rv3d, 0, MAN_ROT_C & rv3d->twdrawflag, v3d->twtype, MAN_RGB); 01570 else draw_manipulator_rotate(v3d, rv3d, 0, MAN_ROT_C & rv3d->twdrawflag, v3d->twtype); 01571 } 01572 if(v3d->twtype & V3D_MANIP_SCALE) 01573 draw_manipulator_scale(v3d, rv3d, 0, MAN_SCALE_C & rv3d->twdrawflag, v3d->twtype, MAN_RGB); 01574 if(v3d->twtype & V3D_MANIP_TRANSLATE) 01575 draw_manipulator_translate(v3d, rv3d, 0, MAN_TRANS_C & rv3d->twdrawflag, v3d->twtype, MAN_RGB); 01576 01577 glPopName(); 01578 hits= glRenderMode(GL_RENDER); 01579 01580 G.f &= ~G_PICKSEL; 01581 setwinmatrixview3d(ar, v3d, NULL); 01582 mul_m4_m4m4(rv3d->persmat, rv3d->viewmat, rv3d->winmat); 01583 01584 if(hits==1) return buffer[3]; 01585 else if(hits>1) { 01586 GLuint val, dep, mindep=0, mindeprot=0, minval=0, minvalrot=0; 01587 int a; 01588 01589 /* we compare the hits in buffer, but value centers highest */ 01590 /* we also store the rotation hits separate (because of arcs) and return hits on other widgets if there are */ 01591 01592 for(a=0; a<hits; a++) { 01593 dep= buffer[4*a + 1]; 01594 val= buffer[4*a + 3]; 01595 01596 if(val==MAN_TRANS_C) return MAN_TRANS_C; 01597 else if(val==MAN_SCALE_C) return MAN_SCALE_C; 01598 else { 01599 if(val & MAN_ROT_C) { 01600 if(minvalrot==0 || dep<mindeprot) { 01601 mindeprot= dep; 01602 minvalrot= val; 01603 } 01604 } 01605 else { 01606 if(minval==0 || dep<mindep) { 01607 mindep= dep; 01608 minval= val; 01609 } 01610 } 01611 } 01612 } 01613 01614 if(minval) 01615 return minval; 01616 else 01617 return minvalrot; 01618 } 01619 return 0; 01620 } 01621 01622 01623 /* return 0; nothing happened */ 01624 int BIF_do_manipulator(bContext *C, struct wmEvent *event, wmOperator *op) 01625 { 01626 ScrArea *sa= CTX_wm_area(C); 01627 View3D *v3d= sa->spacedata.first; 01628 ARegion *ar= CTX_wm_region(C); 01629 int constraint_axis[3] = {0, 0, 0}; 01630 int val; 01631 int shift = event->shift; 01632 01633 if(!(v3d->twflag & V3D_USE_MANIPULATOR)) return 0; 01634 if(!(v3d->twflag & V3D_DRAW_MANIPULATOR)) return 0; 01635 01636 /* Force orientation */ 01637 RNA_enum_set(op->ptr, "constraint_orientation", v3d->twmode); 01638 01639 // find the hotspots first test narrow hotspot 01640 val= manipulator_selectbuf(sa, ar, event->mval, 0.5f*(float)U.tw_hotspot); 01641 if(val) { 01642 01643 // drawflags still global, for drawing call above 01644 drawflags= manipulator_selectbuf(sa, ar, event->mval, 0.2f*(float)U.tw_hotspot); 01645 if(drawflags==0) drawflags= val; 01646 01647 if (drawflags & MAN_TRANS_C) { 01648 switch(drawflags) { 01649 case MAN_TRANS_C: 01650 break; 01651 case MAN_TRANS_X: 01652 if(shift) { 01653 constraint_axis[1] = 1; 01654 constraint_axis[2] = 1; 01655 } 01656 else 01657 constraint_axis[0] = 1; 01658 break; 01659 case MAN_TRANS_Y: 01660 if(shift) { 01661 constraint_axis[0] = 1; 01662 constraint_axis[2] = 1; 01663 } 01664 else 01665 constraint_axis[1] = 1; 01666 break; 01667 case MAN_TRANS_Z: 01668 if(shift) { 01669 constraint_axis[0] = 1; 01670 constraint_axis[1] = 1; 01671 } 01672 else 01673 constraint_axis[2] = 1; 01674 break; 01675 } 01676 RNA_boolean_set_array(op->ptr, "constraint_axis", constraint_axis); 01677 WM_operator_name_call(C, "TRANSFORM_OT_translate", WM_OP_INVOKE_DEFAULT, op->ptr); 01678 //wm_operator_invoke(C, WM_operatortype_find("TRANSFORM_OT_translate", 0), event, op->ptr, NULL, FALSE); 01679 } 01680 else if (drawflags & MAN_SCALE_C) { 01681 switch(drawflags) { 01682 case MAN_SCALE_X: 01683 if(shift) { 01684 constraint_axis[1] = 1; 01685 constraint_axis[2] = 1; 01686 } 01687 else 01688 constraint_axis[0] = 1; 01689 break; 01690 case MAN_SCALE_Y: 01691 if(shift) { 01692 constraint_axis[0] = 1; 01693 constraint_axis[2] = 1; 01694 } 01695 else 01696 constraint_axis[1] = 1; 01697 break; 01698 case MAN_SCALE_Z: 01699 if(shift) { 01700 constraint_axis[0] = 1; 01701 constraint_axis[1] = 1; 01702 } 01703 else 01704 constraint_axis[2] = 1; 01705 break; 01706 } 01707 RNA_boolean_set_array(op->ptr, "constraint_axis", constraint_axis); 01708 WM_operator_name_call(C, "TRANSFORM_OT_resize", WM_OP_INVOKE_DEFAULT, op->ptr); 01709 //wm_operator_invoke(C, WM_operatortype_find("TRANSFORM_OT_resize", 0), event, op->ptr, NULL, FALSE); 01710 } 01711 else if (drawflags == MAN_ROT_T) { /* trackball need special case, init is different */ 01712 WM_operator_name_call(C, "TRANSFORM_OT_trackball", WM_OP_INVOKE_DEFAULT, op->ptr); 01713 //wm_operator_invoke(C, WM_operatortype_find("TRANSFORM_OT_trackball", 0), event, op->ptr, NULL, FALSE); 01714 } 01715 else if (drawflags & MAN_ROT_C) { 01716 switch(drawflags) { 01717 case MAN_ROT_X: 01718 constraint_axis[0] = 1; 01719 break; 01720 case MAN_ROT_Y: 01721 constraint_axis[1] = 1; 01722 break; 01723 case MAN_ROT_Z: 01724 constraint_axis[2] = 1; 01725 break; 01726 } 01727 RNA_boolean_set_array(op->ptr, "constraint_axis", constraint_axis); 01728 WM_operator_name_call(C, "TRANSFORM_OT_rotate", WM_OP_INVOKE_DEFAULT, op->ptr); 01729 //wm_operator_invoke(C, WM_operatortype_find("TRANSFORM_OT_rotate", 0), event, op->ptr, NULL, FALSE); 01730 } 01731 } 01732 /* after transform, restore drawflags */ 01733 drawflags= 0xFFFF; 01734 01735 return val; 01736 } 01737