Blender  V2.59
transform_orientations.c
Go to the documentation of this file.
00001 /*
00002  * $Id: transform_orientations.c 35242 2011-02-27 20:29:51Z jesterking $
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  * Contributor(s): Martin Poirier
00021  *
00022  * ***** END GPL LICENSE BLOCK *****
00023  */
00024 
00030 #include <string.h>
00031 #include <ctype.h>
00032 
00033 #include "MEM_guardedalloc.h"
00034 
00035 #include "DNA_armature_types.h"
00036 #include "DNA_curve_types.h"
00037 #include "DNA_object_types.h"
00038 #include "DNA_scene_types.h"
00039 #include "DNA_screen_types.h"
00040 #include "DNA_view3d_types.h"
00041 
00042 
00043 #include "BKE_armature.h"
00044 #include "BKE_context.h"
00045 #include "BKE_report.h"
00046 
00047 #include "BLI_math.h"
00048 #include "BLI_blenlib.h"
00049 #include "BLI_editVert.h"
00050 #include "BLI_utildefines.h"
00051 
00052 //#include "BIF_editmesh.h"
00053 //#include "BIF_interface.h"
00054 //#include "BIF_space.h"
00055 //#include "BIF_toolbox.h"
00056 
00057 #include "ED_armature.h"
00058 #include "ED_mesh.h"
00059 #include "ED_curve.h" /* for ED_curve_editnurbs */
00060 
00061 
00062 #include "RNA_define.h"
00063 
00064 #include "transform.h"
00065 
00066 /* *********************** TransSpace ************************** */
00067 
00068 void BIF_clearTransformOrientation(bContext *C)
00069 {
00070         View3D *v3d = CTX_wm_view3d(C);
00071 
00072         ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces;
00073         BLI_freelistN(transform_spaces);
00074         
00075         // Need to loop over all view3d
00076         if(v3d && v3d->twmode >= V3D_MANIP_CUSTOM) {
00077                 v3d->twmode = V3D_MANIP_GLOBAL; /* fallback to global   */
00078         }
00079 }
00080 
00081 static TransformOrientation* findOrientationName(ListBase *lb, const char *name)
00082 {
00083         TransformOrientation *ts= NULL;
00084 
00085         for (ts= lb->first; ts; ts = ts->next) {
00086                 if (strncmp(ts->name, name, sizeof(ts->name)-1) == 0) {
00087                         return ts;
00088                 }
00089         }
00090         
00091         return NULL;
00092 }
00093 
00094 static int uniqueOrientationNameCheck(void *arg, const char *name)
00095 {
00096         return findOrientationName((ListBase *)arg, name) != NULL;
00097 }
00098 
00099 static void uniqueOrientationName(ListBase *lb, char *name)
00100 {
00101         BLI_uniquename_cb(uniqueOrientationNameCheck, lb, "Space", '.', name, sizeof(((TransformOrientation *)NULL)->name));
00102 }
00103 
00104 void BIF_createTransformOrientation(bContext *C, ReportList *reports, char *name, int use, int overwrite)
00105 {
00106         Object *obedit = CTX_data_edit_object(C);
00107         Object *ob = CTX_data_active_object(C);
00108         TransformOrientation *ts = NULL;
00109         
00110         if (obedit) {
00111                 if (obedit->type == OB_MESH)
00112                         ts = createMeshSpace(C, reports, name, overwrite);
00113                 else if (obedit->type == OB_ARMATURE)
00114                         ts = createBoneSpace(C, reports, name, overwrite);
00115         }
00116         else if (ob && (ob->mode & OB_MODE_POSE)) {
00117                         ts = createBoneSpace(C, reports, name, overwrite);
00118         }
00119         else {
00120                 ts = createObjectSpace(C, reports, name, overwrite);
00121         }
00122         
00123         if (use && ts != NULL)
00124         {
00125                 BIF_selectTransformOrientation(C, ts);
00126         }
00127 }
00128 
00129 TransformOrientation *createObjectSpace(bContext *C, ReportList *UNUSED(reports), char *name, int overwrite) {
00130         Base *base = CTX_data_active_base(C);
00131         Object *ob;
00132         float mat[3][3];
00133 
00134         if (base == NULL)
00135                 return NULL;
00136 
00137 
00138         ob = base->object;
00139         
00140         copy_m3_m4(mat, ob->obmat);
00141         normalize_m3(mat);
00142 
00143         /* use object name if no name is given */
00144         if (name[0] == 0)
00145         {
00146                 strncpy(name, ob->id.name+2, 35);
00147         }
00148 
00149         return addMatrixSpace(C, mat, name, overwrite); 
00150 }
00151 
00152 TransformOrientation *createBoneSpace(bContext *C, ReportList *reports, char *name, int overwrite) {
00153         float mat[3][3];
00154         float normal[3], plane[3];
00155 
00156         getTransformOrientation(C, normal, plane, 0);
00157 
00158         if (createSpaceNormalTangent(mat, normal, plane) == 0) {
00159                 BKE_reports_prepend(reports, "Cannot use zero-length bone");
00160                 return NULL;
00161         }
00162 
00163         if (name[0] == 0)
00164         {
00165                 strcpy(name, "Bone");
00166         }
00167 
00168         return addMatrixSpace(C, mat, name, overwrite);
00169 }
00170 
00171 TransformOrientation *createMeshSpace(bContext *C, ReportList *reports, char *name, int overwrite) {
00172         float mat[3][3];
00173         float normal[3], plane[3];
00174         int type;
00175 
00176         type = getTransformOrientation(C, normal, plane, 0);
00177         
00178         switch (type)
00179         {
00180                 case ORIENTATION_VERT:
00181                         if (createSpaceNormal(mat, normal) == 0) {
00182                                 BKE_reports_prepend(reports, "Cannot use vertex with zero-length normal");
00183                                 return NULL;
00184                         }
00185         
00186                         if (name[0] == 0)
00187                         {
00188                                 strcpy(name, "Vertex");
00189                         }
00190                         break;
00191                 case ORIENTATION_EDGE:
00192                         if (createSpaceNormalTangent(mat, normal, plane) == 0) {
00193                                 BKE_reports_prepend(reports, "Cannot use zero-length edge");
00194                                 return NULL;
00195                         }
00196         
00197                         if (name[0] == 0)
00198                         {
00199                                 strcpy(name, "Edge");
00200                         }
00201                         break;
00202                 case ORIENTATION_FACE:
00203                         if (createSpaceNormalTangent(mat, normal, plane) == 0) {
00204                                 BKE_reports_prepend(reports, "Cannot use zero-area face");
00205                                 return NULL;
00206                         }
00207         
00208                         if (name[0] == 0)
00209                         {
00210                                 strcpy(name, "Face");
00211                         }
00212                         break;
00213                 default:
00214                         return NULL;
00215                         break;
00216         }
00217 
00218         return addMatrixSpace(C, mat, name, overwrite);
00219 }
00220 
00221 int createSpaceNormal(float mat[3][3], float normal[3])
00222 {
00223         float tangent[3] = {0.0f, 0.0f, 1.0f};
00224         
00225         VECCOPY(mat[2], normal);
00226         if (normalize_v3(mat[2]) == 0.0f) {
00227                 return 0; /* error return */
00228         }
00229 
00230         cross_v3_v3v3(mat[0], mat[2], tangent);
00231         if (dot_v3v3(mat[0], mat[0]) == 0.0f) {
00232                 tangent[0] = 1.0f;
00233                 tangent[1] = tangent[2] = 0.0f;
00234                 cross_v3_v3v3(mat[0], tangent, mat[2]);
00235         }
00236 
00237         cross_v3_v3v3(mat[1], mat[2], mat[0]);
00238 
00239         normalize_m3(mat);
00240         
00241         return 1;
00242 }
00243 
00244 int createSpaceNormalTangent(float mat[3][3], float normal[3], float tangent[3])
00245 {
00246         VECCOPY(mat[2], normal);
00247         if (normalize_v3(mat[2]) == 0.0f) {
00248                 return 0; /* error return */
00249         }
00250         
00251         /* preempt zero length tangent from causing trouble */
00252         if (tangent[0] == 0 && tangent[1] == 0 && tangent[2] == 0)
00253         {
00254                 tangent[2] = 1;
00255         }
00256 
00257         cross_v3_v3v3(mat[0], mat[2], tangent);
00258         if (normalize_v3(mat[0]) == 0.0f) {
00259                 return 0; /* error return */
00260         }
00261         
00262         cross_v3_v3v3(mat[1], mat[2], mat[0]);
00263 
00264         normalize_m3(mat);
00265         
00266         return 1;
00267 }
00268 
00269 TransformOrientation* addMatrixSpace(bContext *C, float mat[3][3], char name[], int overwrite) {
00270         ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces;
00271         TransformOrientation *ts = NULL;
00272 
00273         if (overwrite)
00274         {
00275                 ts = findOrientationName(transform_spaces, name);
00276         }
00277         else
00278         {
00279                 uniqueOrientationName(transform_spaces, name);
00280         }
00281 
00282         /* if not, create a new one */
00283         if (ts == NULL)
00284         {
00285                 ts = MEM_callocN(sizeof(TransformOrientation), "UserTransSpace from matrix");
00286                 BLI_addtail(transform_spaces, ts);
00287                 strncpy(ts->name, name, 35);
00288         }
00289 
00290         /* copy matrix into transform space */
00291         copy_m3_m3(ts->mat, mat);
00292 
00293         return ts;
00294 }
00295 
00296 void BIF_removeTransformOrientation(bContext *C, TransformOrientation *target) {
00297         ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces;
00298         TransformOrientation *ts;
00299         int i;
00300         
00301         for (i = 0, ts = transform_spaces->first; ts; ts = ts->next, i++) {
00302                 if (ts == target) {
00303                         View3D *v3d = CTX_wm_view3d(C);
00304                         if(v3d) {
00305                                 int selected_index = (v3d->twmode - V3D_MANIP_CUSTOM);
00306                                 
00307                                 // Transform_fix_me NEED TO DO THIS FOR ALL VIEW3D
00308                                 if (selected_index == i) {
00309                                         v3d->twmode = V3D_MANIP_GLOBAL; /* fallback to global   */
00310                                 }
00311                                 else if (selected_index > i) {
00312                                         v3d->twmode--;
00313                                 }
00314                                 
00315                         }
00316 
00317                         BLI_freelinkN(transform_spaces, ts);
00318                         break;
00319                 }
00320         }
00321 }
00322 
00323 void BIF_removeTransformOrientationIndex(bContext *C, int index) {
00324         ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces;
00325         TransformOrientation *ts= BLI_findlink(transform_spaces, index);
00326 
00327         if (ts) {
00328                 View3D *v3d = CTX_wm_view3d(C);
00329                 if(v3d) {
00330                         int selected_index = (v3d->twmode - V3D_MANIP_CUSTOM);
00331                         
00332                         // Transform_fix_me NEED TO DO THIS FOR ALL VIEW3D
00333                         if (selected_index == index) {
00334                                 v3d->twmode = V3D_MANIP_GLOBAL; /* fallback to global   */
00335                         }
00336                         else if (selected_index > index) {
00337                                 v3d->twmode--;
00338                         }
00339                         
00340                 }
00341 
00342                 BLI_freelinkN(transform_spaces, ts);
00343         }
00344 }
00345 
00346 void BIF_selectTransformOrientation(bContext *C, TransformOrientation *target) {
00347         ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces;
00348         View3D *v3d = CTX_wm_view3d(C);
00349         TransformOrientation *ts;
00350         int i;
00351         
00352         for (i = 0, ts = transform_spaces->first; ts; ts = ts->next, i++) {
00353                 if (ts == target) {
00354                         v3d->twmode = V3D_MANIP_CUSTOM + i;
00355                         break;
00356                 }
00357         }
00358 }
00359 
00360 void BIF_selectTransformOrientationValue(bContext *C, int orientation) {
00361         View3D *v3d = CTX_wm_view3d(C);
00362         if(v3d) /* currently using generic poll */
00363                 v3d->twmode = orientation;
00364 }
00365 
00366 EnumPropertyItem *BIF_enumTransformOrientation(bContext *C)
00367 {
00368         Scene *scene;
00369         ListBase *transform_spaces;
00370         TransformOrientation *ts= NULL;
00371 
00372         EnumPropertyItem global = {V3D_MANIP_GLOBAL, "GLOBAL", 0, "Global", ""};
00373         EnumPropertyItem normal = {V3D_MANIP_NORMAL, "NORMAL", 0, "Normal", ""};
00374         EnumPropertyItem local = {V3D_MANIP_LOCAL, "LOCAL", 0, "Local", ""};
00375         EnumPropertyItem view = {V3D_MANIP_VIEW, "VIEW", 0, "View", ""};
00376         EnumPropertyItem tmp = {0, "", 0, "", ""};
00377         EnumPropertyItem *item= NULL;
00378         int i = V3D_MANIP_CUSTOM, totitem= 0;
00379 
00380         RNA_enum_item_add(&item, &totitem, &global);
00381         RNA_enum_item_add(&item, &totitem, &normal);
00382         RNA_enum_item_add(&item, &totitem, &local);
00383         RNA_enum_item_add(&item, &totitem, &view);
00384 
00385         if(C) {
00386                 scene= CTX_data_scene(C);
00387 
00388                 if(scene) {
00389                         transform_spaces = &scene->transform_spaces;
00390                         ts = transform_spaces->first;
00391                 }
00392         }
00393                 
00394         if(ts)
00395                 RNA_enum_item_add_separator(&item, &totitem);
00396 
00397         for(; ts; ts = ts->next) {
00398                 tmp.identifier = "CUSTOM";
00399                 tmp.name= ts->name;
00400                 tmp.value = i++;
00401                 RNA_enum_item_add(&item, &totitem, &tmp);
00402         }
00403 
00404         RNA_enum_item_end(&item, &totitem);
00405 
00406         return item;
00407 }
00408 
00409 const char * BIF_menustringTransformOrientation(const bContext *C, const char *title) {
00410         char menu[] = "%t|Global%x0|Local%x1|Gimbal%x4|Normal%x2|View%x3";
00411         ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces;
00412         TransformOrientation *ts;
00413         int i = V3D_MANIP_CUSTOM;
00414         char *str_menu, *p;
00415         
00416         
00417         str_menu = MEM_callocN(strlen(menu) + strlen(title) + 1 + 40 * BIF_countTransformOrientation(C), "UserTransSpace from matrix");
00418         p = str_menu;
00419         
00420         p += sprintf(str_menu, "%s", title);
00421         p += sprintf(p, "%s", menu);
00422         
00423         for (ts = transform_spaces->first; ts; ts = ts->next) {
00424                 p += sprintf(p, "|%s%%x%d", ts->name, i++);
00425         }
00426         
00427         return str_menu;
00428 }
00429 
00430 int BIF_countTransformOrientation(const bContext *C) {
00431         ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces;
00432         TransformOrientation *ts;
00433         int count = 0;
00434 
00435         for (ts = transform_spaces->first; ts; ts = ts->next) {
00436                 count++;
00437         }
00438         
00439         return count;
00440 }
00441 
00442 void applyTransformOrientation(const bContext *C, float mat[3][3], char *name) {
00443         TransformOrientation *ts;
00444         View3D *v3d = CTX_wm_view3d(C);
00445         int selected_index = (v3d->twmode - V3D_MANIP_CUSTOM);
00446         int i;
00447         
00448         if (selected_index >= 0) {
00449                 for (i = 0, ts = CTX_data_scene(C)->transform_spaces.first; ts; ts = ts->next, i++) {
00450                         if (selected_index == i) {
00451                                 
00452                                 if (name)
00453                                         strcpy(name, ts->name);
00454                                 
00455                                 copy_m3_m3(mat, ts->mat);
00456                                 break;
00457                         }
00458                 }
00459           }
00460 }
00461 
00462 static int count_bone_select(bArmature *arm, ListBase *lb, int do_it) 
00463 {
00464         Bone *bone;
00465         int do_next;
00466         int total = 0;
00467         
00468         for(bone= lb->first; bone; bone= bone->next) {
00469                 bone->flag &= ~BONE_TRANSFORM;
00470                 do_next = do_it;
00471                 if(do_it) {
00472                         if(bone->layer & arm->layer) {
00473                                 if (bone->flag & BONE_SELECTED) {
00474                                         bone->flag |= BONE_TRANSFORM;
00475                                         total++;
00476                                         do_next= 0;     // no transform on children if one parent bone is selected
00477                                 }
00478                         }
00479                 }
00480                 total += count_bone_select(arm, &bone->childbase, do_next);
00481         }
00482         
00483         return total;
00484 }
00485 
00486 void initTransformOrientation(bContext *C, TransInfo *t)
00487 {
00488         View3D *v3d = CTX_wm_view3d(C);
00489         Object *ob = CTX_data_active_object(C);
00490         Object *obedit = CTX_data_active_object(C);
00491 
00492         switch(t->current_orientation) {
00493         case V3D_MANIP_GLOBAL:
00494                 unit_m3(t->spacemtx);
00495                 strcpy(t->spacename, "global");
00496                 break;
00497 
00498         case V3D_MANIP_GIMBAL:
00499                 unit_m3(t->spacemtx);
00500                 if (gimbal_axis(ob, t->spacemtx)) {
00501                         strcpy(t->spacename, "gimbal");
00502                         break;
00503                 }
00504                 /* no gimbal fallthrough to normal */
00505         case V3D_MANIP_NORMAL:
00506                 if(obedit || (ob && ob->mode & OB_MODE_POSE)) {
00507                         strcpy(t->spacename, "normal");
00508                         ED_getTransformOrientationMatrix(C, t->spacemtx, (v3d->around == V3D_ACTIVE));
00509                         break;
00510                 }
00511                 /* no break we define 'normal' as 'local' in Object mode */
00512         case V3D_MANIP_LOCAL:
00513                 strcpy(t->spacename, "local");
00514                 
00515                 if(ob) {
00516                         copy_m3_m4(t->spacemtx, ob->obmat);
00517                         normalize_m3(t->spacemtx);
00518                 } else {
00519                         unit_m3(t->spacemtx);
00520                 }
00521                 
00522                 break;
00523                 
00524         case V3D_MANIP_VIEW:
00525                 if (t->ar->regiontype == RGN_TYPE_WINDOW)
00526                 {
00527                         RegionView3D *rv3d = t->ar->regiondata;
00528                         float mat[3][3];
00529 
00530                         strcpy(t->spacename, "view");
00531                         copy_m3_m4(mat, rv3d->viewinv);
00532                         normalize_m3(mat);
00533                         copy_m3_m3(t->spacemtx, mat);
00534                 }
00535                 else
00536                 {
00537                         unit_m3(t->spacemtx);
00538                 }
00539                 break;
00540         default: /* V3D_MANIP_CUSTOM */
00541                 applyTransformOrientation(C, t->spacemtx, t->spacename);
00542                 break;
00543         }
00544 }
00545 
00546 int getTransformOrientation(const bContext *C, float normal[3], float plane[3], int activeOnly)
00547 {
00548         Scene *scene = CTX_data_scene(C);
00549         View3D *v3d = CTX_wm_view3d(C);
00550         Object *obedit= CTX_data_edit_object(C);
00551         Base *base;
00552         Object *ob = OBACT;
00553         int result = ORIENTATION_NONE;
00554 
00555         normal[0] = normal[1] = normal[2] = 0;
00556         plane[0] = plane[1] = plane[2] = 0;
00557 
00558         if(obedit)
00559         {
00560                 float imat[3][3], mat[3][3];
00561                 
00562                 /* we need the transpose of the inverse for a normal... */
00563                 copy_m3_m4(imat, ob->obmat);
00564                 
00565                 invert_m3_m3(mat, imat);
00566                 transpose_m3(mat);
00567 
00568                 ob= obedit;
00569 
00570                 if(ob->type==OB_MESH)
00571                 {
00572                         Mesh *me= ob->data;
00573                         EditMesh *em = me->edit_mesh;
00574                         EditVert *eve;
00575                         EditSelection ese;
00576                         float vec[3]= {0,0,0};
00577                         
00578                         /* USE LAST SELECTED WITH ACTIVE */
00579                         if (activeOnly && EM_get_actSelection(em, &ese))
00580                         {
00581                                 EM_editselection_normal(normal, &ese);
00582                                 EM_editselection_plane(plane, &ese);
00583                                 
00584                                 switch (ese.type)
00585                                 {
00586                                         case EDITVERT:
00587                                                 result = ORIENTATION_VERT;
00588                                                 break;
00589                                         case EDITEDGE:
00590                                                 result = ORIENTATION_EDGE;
00591                                                 break;
00592                                         case EDITFACE:
00593                                                 result = ORIENTATION_FACE;
00594                                                 break;
00595                                 }
00596                         }
00597                         else
00598                         {
00599                                 if (em->totfacesel >= 1)
00600                                 {
00601                                         EditFace *efa;
00602                                         
00603                                         for(efa= em->faces.first; efa; efa= efa->next)
00604                                         {
00605                                                 if(efa->f & SELECT)
00606                                                 {
00607                                                         VECADD(normal, normal, efa->n);
00608                                                         sub_v3_v3v3(vec, efa->v2->co, efa->v1->co);
00609                                                         VECADD(plane, plane, vec);
00610                                                 }
00611                                         }
00612                                         
00613                                         result = ORIENTATION_FACE;
00614                                 }
00615                                 else if (em->totvertsel == 3)
00616                                 {
00617                                         EditVert *v1 = NULL, *v2 = NULL, *v3 = NULL;
00618                                         float cotangent[3];
00619                                         
00620                                         for (eve = em->verts.first; eve; eve = eve->next)
00621                                         {
00622                                                 if ( eve->f & SELECT ) {
00623                                                         if (v1 == NULL) {
00624                                                                 v1 = eve; 
00625                                                         }
00626                                                         else if (v2 == NULL) {
00627                                                                 v2 = eve;
00628                                                         }
00629                                                         else {
00630                                                                 v3 = eve;
00631 
00632                                                                 sub_v3_v3v3(plane, v2->co, v1->co);
00633                                                                 sub_v3_v3v3(cotangent, v3->co, v2->co);
00634                                                                 cross_v3_v3v3(normal, cotangent, plane);
00635                                                                 break;
00636                                                         }
00637                                                 }
00638                                         }
00639 
00640                                         /* if there's an edge available, use that for the tangent */
00641                                         if (em->totedgesel >= 1)
00642                                         {
00643                                                 EditEdge *eed = NULL;
00644         
00645                                                 for(eed= em->edges.first; eed; eed= eed->next) {
00646                                                         if(eed->f & SELECT) {
00647                                                                 sub_v3_v3v3(plane, eed->v2->co, eed->v1->co);
00648                                                                 break;
00649                                                         }
00650                                                 }
00651                                         }
00652 
00653                                         result = ORIENTATION_FACE;
00654                                 }
00655                                 else if (em->totedgesel == 1)
00656                                 {
00657                                         EditEdge *eed;
00658 
00659                                         for(eed= em->edges.first; eed; eed= eed->next) {
00660                                                 if(eed->f & SELECT) {
00661                                                         /* use average vert normals as plane and edge vector as normal */
00662                                                         VECCOPY(plane, eed->v1->no);
00663                                                         VECADD(plane, plane, eed->v2->no);
00664                                                         sub_v3_v3v3(normal, eed->v2->co, eed->v1->co);
00665                                                         break;
00666                                                 }
00667                                         }
00668                                         result = ORIENTATION_EDGE;
00669                                 }
00670                                 else if (em->totvertsel == 2)
00671                                 {
00672                                         EditVert *v1 = NULL, *v2 = NULL;
00673                 
00674                                         for (eve = em->verts.first; eve; eve = eve->next)
00675                                         {
00676                                                 if ( eve->f & SELECT ) {
00677                                                         if (v1 == NULL) {
00678                                                                 v1 = eve; 
00679                                                         }
00680                                                         else {
00681                                                                 v2 = eve;
00682                                                                 
00683                                                                 VECCOPY(plane, v1->no);
00684                                                                 VECADD(plane, plane, v2->no);
00685                                                                 sub_v3_v3v3(normal, v2->co, v1->co);
00686                                                                 break; 
00687                                                         }
00688                                                 }
00689                                         }
00690                                         result = ORIENTATION_EDGE;
00691                                 }
00692                                 else if (em->totvertsel == 1)
00693                                 {
00694                                         for (eve = em->verts.first; eve; eve = eve->next)
00695                                         {
00696                                                 if ( eve->f & SELECT ) {
00697                                                         VECCOPY(normal, eve->no);
00698                                                         break;
00699                                                 }
00700                                         }
00701                                         result = ORIENTATION_VERT;
00702                                 }
00703                                 else if (em->totvertsel > 3)
00704                                 {
00705                                         normal[0] = normal[1] = normal[2] = 0;
00706                                         
00707                                         for (eve = em->verts.first; eve; eve = eve->next)
00708                                         {
00709                                                 if ( eve->f & SELECT ) {
00710                                                         add_v3_v3(normal, eve->no);
00711                                                 }
00712                                         }
00713                                         normalize_v3(normal);
00714                                         result = ORIENTATION_VERT;
00715                                 }
00716                         }
00717                 } /* end editmesh */
00718                 else if ELEM(obedit->type, OB_CURVE, OB_SURF)
00719                 {
00720                         Curve *cu= obedit->data;
00721                         Nurb *nu;
00722                         BezTriple *bezt;
00723                         int a;
00724                         ListBase *nurbs= ED_curve_editnurbs(cu);
00725 
00726                         for (nu = nurbs->first; nu; nu = nu->next)
00727                         {
00728                                 /* only bezier has a normal */
00729                                 if(nu->type == CU_BEZIER)
00730                                 {
00731                                         bezt= nu->bezt;
00732                                         a= nu->pntsu;
00733                                         while(a--)
00734                                         {
00735                                                 /* exception */
00736                                                 if ( (bezt->f1 & SELECT) + (bezt->f2 & SELECT) + (bezt->f3 & SELECT) > SELECT )
00737                                                 {
00738                                                         sub_v3_v3v3(normal, bezt->vec[0], bezt->vec[2]);
00739                                                 }
00740                                                 else
00741                                                 {
00742                                                         if(bezt->f1)
00743                                                         {
00744                                                                 sub_v3_v3v3(normal, bezt->vec[0], bezt->vec[1]);
00745                                                         }
00746                                                         if(bezt->f2)
00747                                                         {
00748                                                                 sub_v3_v3v3(normal, bezt->vec[0], bezt->vec[2]);
00749                                                         }
00750                                                         if(bezt->f3)
00751                                                         {
00752                                                                 sub_v3_v3v3(normal, bezt->vec[1], bezt->vec[2]);
00753                                                         }
00754                                                 }
00755                                                 bezt++;
00756                                         }
00757                                 }
00758                         }
00759                         
00760                         if (normal[0] != 0 || normal[1] != 0 || normal[2] != 0)
00761                         {
00762                                 result = ORIENTATION_NORMAL;
00763                         }
00764                 }
00765                 else if(obedit->type==OB_MBALL)
00766                 {
00767 #if 0 // XXX
00768                         /* editmball.c */
00769                         extern ListBase editelems;  /* go away ! */
00770                         MetaElem *ml, *ml_sel = NULL;
00771         
00772                         /* loop and check that only one element is selected */  
00773                         for (ml = editelems.first; ml; ml = ml->next)
00774                         {
00775                                 if (ml->flag & SELECT) {
00776                                         if (ml_sel == NULL)
00777                                         {
00778                                                 ml_sel = ml;
00779                                         }
00780                                         else
00781                                         {
00782                                                 ml_sel = NULL;
00783                                                 break;
00784                                         }
00785                                 }
00786                         }
00787                         
00788                         if (ml_sel)
00789                         {       
00790                                 float mat[4][4];
00791 
00792                                 /* Rotation of MetaElem is stored in quat */
00793                                  quat_to_mat4( mat,ml_sel->quat);
00794 
00795                                 VECCOPY(normal, mat[2]);
00796 
00797                                 negate_v3_v3(plane, mat[1]);
00798                                 
00799                                 result = ORIENTATION_NORMAL;
00800                         }
00801 #endif
00802                         
00803                 }
00804                 else if (obedit->type == OB_ARMATURE)
00805                 {
00806                         bArmature *arm = obedit->data;
00807                         EditBone *ebone;
00808                         
00809                         for (ebone = arm->edbo->first; ebone; ebone=ebone->next) {
00810                                 if (arm->layer & ebone->layer)
00811                                 {
00812                                         if (ebone->flag & BONE_SELECTED)
00813                                         {
00814                                                 float tmat[3][3];
00815                                                 float vec[3];
00816                                                 sub_v3_v3v3(vec, ebone->tail, ebone->head);
00817                                                 normalize_v3(vec);
00818                                                 add_v3_v3(normal, vec);
00819                                                 
00820                                                 vec_roll_to_mat3(vec, ebone->roll, tmat);
00821                                                 add_v3_v3(plane, tmat[2]);
00822                                         }
00823                                 }
00824                         }
00825                         
00826                         normalize_v3(normal);
00827                         normalize_v3(plane);
00828 
00829                         if (plane[0] != 0 || plane[1] != 0 || plane[2] != 0)
00830                         {
00831                                 result = ORIENTATION_EDGE;
00832                         }
00833 
00834                 }
00835 
00836                 /* Vectors from edges don't need the special transpose inverse multiplication */
00837                 if (result == ORIENTATION_EDGE)
00838                 {
00839                         mul_mat3_m4_v3(ob->obmat, normal);
00840                         mul_mat3_m4_v3(ob->obmat, plane);
00841                 }
00842                 else
00843                 {
00844                         mul_m3_v3(mat, normal);
00845                         mul_m3_v3(mat, plane);
00846                 }
00847         }
00848         else if(ob && (ob->mode & OB_MODE_POSE))
00849         {
00850                 bArmature *arm= ob->data;
00851                 bPoseChannel *pchan;
00852                 int totsel;
00853                 
00854                 totsel = count_bone_select(arm, &arm->bonebase, 1);
00855                 if(totsel) {
00856                         float imat[3][3], mat[3][3];
00857 
00858                         /* use channels to get stats */
00859                         for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
00860                                 if (pchan->bone && pchan->bone->flag & BONE_TRANSFORM) {
00861                                         add_v3_v3(normal, pchan->pose_mat[2]);
00862                                         add_v3_v3(plane, pchan->pose_mat[1]);
00863                                 }
00864                         }
00865                         negate_v3(plane);
00866                         
00867                         /* we need the transpose of the inverse for a normal... */
00868                         copy_m3_m4(imat, ob->obmat);
00869                         
00870                         invert_m3_m3(mat, imat);
00871                         transpose_m3(mat);
00872                         mul_m3_v3(mat, normal);
00873                         mul_m3_v3(mat, plane);
00874                         
00875                         result = ORIENTATION_EDGE;
00876                 }
00877         }
00878         else if(ob && (ob->mode & (OB_MODE_ALL_PAINT|OB_MODE_PARTICLE_EDIT)))
00879         {
00880         }
00881         else {
00882                 /* we need the one selected object, if its not active */
00883                 ob = OBACT;
00884                 if(ob && !(ob->flag & SELECT)) ob = NULL;
00885                 
00886                 for(base= scene->base.first; base; base= base->next) {
00887                         if TESTBASELIB(v3d, base) {
00888                                 if(ob == NULL) { 
00889                                         ob= base->object;
00890                                         break;
00891                                 }
00892                         }
00893                 }
00894                 
00895                 if (ob) {
00896                         VECCOPY(normal, ob->obmat[2]);
00897                         VECCOPY(plane, ob->obmat[1]);
00898                 }
00899                 result = ORIENTATION_NORMAL;
00900         }
00901         
00902         return result;
00903 }
00904 
00905 void ED_getTransformOrientationMatrix(const bContext *C, float orientation_mat[][3], int activeOnly)
00906 {
00907         float normal[3]={0.0, 0.0, 0.0};
00908         float plane[3]={0.0, 0.0, 0.0};
00909 
00910         int type;
00911 
00912         type = getTransformOrientation(C, normal, plane, activeOnly);
00913 
00914         switch (type)
00915         {
00916                 case ORIENTATION_NORMAL:
00917                         if (createSpaceNormalTangent(orientation_mat, normal, plane) == 0)
00918                         {
00919                                 type = ORIENTATION_NONE;
00920                         }
00921                         break;
00922                 case ORIENTATION_VERT:
00923                         if (createSpaceNormal(orientation_mat, normal) == 0)
00924                         {
00925                                 type = ORIENTATION_NONE;
00926                         }
00927                         break;
00928                 case ORIENTATION_EDGE:
00929                         if (createSpaceNormalTangent(orientation_mat, normal, plane) == 0)
00930                         {
00931                                 type = ORIENTATION_NONE;
00932                         }
00933                         break;
00934                 case ORIENTATION_FACE:
00935                         if (createSpaceNormalTangent(orientation_mat, normal, plane) == 0)
00936                         {
00937                                 type = ORIENTATION_NONE;
00938                         }
00939                         break;
00940         }
00941 
00942         if (type == ORIENTATION_NONE)
00943         {
00944                 unit_m3(orientation_mat);
00945         }
00946 }