code cleanup: split scons includes onto multiple lines, reduce chance of include...
[blender-staging.git] / source / blender / editors / transform / transform_orientations.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * Contributor(s): Martin Poirier
19  *
20  * ***** END GPL LICENSE BLOCK *****
21  */
22
23 /** \file blender/editors/transform/transform_orientations.c
24  *  \ingroup edtransform
25  */
26
27
28 #include <string.h>
29 #include <ctype.h>
30
31 #include "MEM_guardedalloc.h"
32
33 #include "DNA_armature_types.h"
34 #include "DNA_curve_types.h"
35 #include "DNA_mesh_types.h"
36 #include "DNA_meta_types.h"
37 #include "DNA_object_types.h"
38 #include "DNA_scene_types.h"
39 #include "DNA_screen_types.h"
40 #include "DNA_view3d_types.h"
41
42 #include "BLI_math.h"
43 #include "BLI_blenlib.h"
44 #include "BLI_utildefines.h"
45
46 #include "BKE_action.h"
47 #include "BKE_armature.h"
48 #include "BKE_curve.h"
49 #include "BKE_context.h"
50 #include "BKE_editmesh.h"
51 #include "BKE_report.h"
52
53 #include "BLF_translation.h"
54
55 #include "ED_armature.h"
56 #include "ED_mesh.h"
57
58 #include "RNA_define.h"
59
60 #include "UI_interface.h"
61
62 #include "transform.h"
63
64 /* *********************** TransSpace ************************** */
65
66 void BIF_clearTransformOrientation(bContext *C)
67 {
68         View3D *v3d = CTX_wm_view3d(C);
69
70         ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces;
71         BLI_freelistN(transform_spaces);
72         
73         // Need to loop over all view3d
74         if (v3d && v3d->twmode >= V3D_MANIP_CUSTOM) {
75                 v3d->twmode = V3D_MANIP_GLOBAL; /* fallback to global   */
76         }
77 }
78
79 static TransformOrientation *findOrientationName(ListBase *lb, const char *name)
80 {
81         TransformOrientation *ts = NULL;
82
83         for (ts = lb->first; ts; ts = ts->next) {
84                 if (strncmp(ts->name, name, sizeof(ts->name) - 1) == 0) {
85                         return ts;
86                 }
87         }
88         
89         return NULL;
90 }
91
92 static bool uniqueOrientationNameCheck(void *arg, const char *name)
93 {
94         return findOrientationName((ListBase *)arg, name) != NULL;
95 }
96
97 static void uniqueOrientationName(ListBase *lb, char *name)
98 {
99         BLI_uniquename_cb(uniqueOrientationNameCheck, lb, CTX_DATA_(BLF_I18NCONTEXT_ID_SCENE, "Space"), '.', name,
100                           sizeof(((TransformOrientation *)NULL)->name));
101 }
102
103 static TransformOrientation *createViewSpace(bContext *C, ReportList *UNUSED(reports), char *name, int overwrite)
104 {
105         RegionView3D *rv3d = CTX_wm_region_view3d(C);
106         float mat[3][3];
107
108         if (!rv3d)
109                 return NULL;
110
111         copy_m3_m4(mat, rv3d->viewinv);
112         normalize_m3(mat);
113
114         if (!name[0]) {
115                 View3D *v3d = CTX_wm_view3d(C);
116                 if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
117                         /* If an object is used as camera, then this space is the same as object space! */
118                         strncpy(name, v3d->camera->id.name + 2, MAX_NAME);
119                 }
120                 else {
121                         strcpy(name, "Custom View");
122                 }
123         }
124
125         return addMatrixSpace(C, mat, name, overwrite);
126 }
127
128 static TransformOrientation *createObjectSpace(bContext *C, ReportList *UNUSED(reports), char *name, int overwrite)
129 {
130         Base *base = CTX_data_active_base(C);
131         Object *ob;
132         float mat[3][3];
133
134         if (base == NULL)
135                 return NULL;
136
137         ob = base->object;
138
139         copy_m3_m4(mat, ob->obmat);
140         normalize_m3(mat);
141
142         /* use object name if no name is given */
143         if (name[0] == 0) {
144                 strncpy(name, ob->id.name + 2, MAX_ID_NAME - 2);
145         }
146
147         return addMatrixSpace(C, mat, name, overwrite);
148 }
149
150 static TransformOrientation *createBoneSpace(bContext *C, ReportList *reports, char *name, int overwrite)
151 {
152         float mat[3][3];
153         float normal[3], plane[3];
154
155         getTransformOrientation(C, normal, plane, 0);
156
157         if (createSpaceNormalTangent(mat, normal, plane) == 0) {
158                 BKE_reports_prepend(reports, "Cannot use zero-length bone");
159                 return NULL;
160         }
161
162         if (name[0] == 0) {
163                 strcpy(name, "Bone");
164         }
165
166         return addMatrixSpace(C, mat, name, overwrite);
167 }
168
169 static TransformOrientation *createMeshSpace(bContext *C, ReportList *reports, char *name, int overwrite)
170 {
171         float mat[3][3];
172         float normal[3], plane[3];
173         int type;
174
175         type = getTransformOrientation(C, normal, plane, 0);
176         
177         switch (type) {
178                 case ORIENTATION_VERT:
179                         if (createSpaceNormal(mat, normal) == 0) {
180                                 BKE_reports_prepend(reports, "Cannot use vertex with zero-length normal");
181                                 return NULL;
182                         }
183         
184                         if (name[0] == 0) {
185                                 strcpy(name, "Vertex");
186                         }
187                         break;
188                 case ORIENTATION_EDGE:
189                         if (createSpaceNormalTangent(mat, normal, plane) == 0) {
190                                 BKE_reports_prepend(reports, "Cannot use zero-length edge");
191                                 return NULL;
192                         }
193         
194                         if (name[0] == 0) {
195                                 strcpy(name, "Edge");
196                         }
197                         break;
198                 case ORIENTATION_FACE:
199                         if (createSpaceNormalTangent(mat, normal, plane) == 0) {
200                                 BKE_reports_prepend(reports, "Cannot use zero-area face");
201                                 return NULL;
202                         }
203         
204                         if (name[0] == 0) {
205                                 strcpy(name, "Face");
206                         }
207                         break;
208                 default:
209                         return NULL;
210                         break;
211         }
212
213         return addMatrixSpace(C, mat, name, overwrite);
214 }
215
216 bool createSpaceNormal(float mat[3][3], const float normal[3])
217 {
218         float tangent[3] = {0.0f, 0.0f, 1.0f};
219         
220         copy_v3_v3(mat[2], normal);
221         if (normalize_v3(mat[2]) == 0.0f) {
222                 return false;  /* error return */
223         }
224
225         cross_v3_v3v3(mat[0], mat[2], tangent);
226         if (dot_v3v3(mat[0], mat[0]) == 0.0f) {
227                 tangent[0] = 1.0f;
228                 tangent[1] = tangent[2] = 0.0f;
229                 cross_v3_v3v3(mat[0], tangent, mat[2]);
230         }
231
232         cross_v3_v3v3(mat[1], mat[2], mat[0]);
233
234         normalize_m3(mat);
235         
236         return true;
237 }
238
239 bool createSpaceNormalTangent(float mat[3][3], float normal[3], float tangent[3])
240 {
241         copy_v3_v3(mat[2], normal);
242         if (normalize_v3(mat[2]) == 0.0f) {
243                 return false;  /* error return */
244         }
245         
246         /* preempt zero length tangent from causing trouble */
247         if (tangent[0] == 0 && tangent[1] == 0 && tangent[2] == 0) {
248                 tangent[2] = 1;
249         }
250
251         cross_v3_v3v3(mat[0], mat[2], tangent);
252         if (normalize_v3(mat[0]) == 0.0f) {
253                 return false;  /* error return */
254         }
255         
256         cross_v3_v3v3(mat[1], mat[2], mat[0]);
257
258         normalize_m3(mat);
259         
260         return true;
261 }
262
263 /* name must be a MAX_NAME length string! */
264 void BIF_createTransformOrientation(bContext *C, ReportList *reports, char *name, int use_view, int use, int overwrite)
265 {
266         TransformOrientation *ts = NULL;
267
268         if (use_view) {
269                 ts = createViewSpace(C, reports, name, overwrite);
270         }
271         else {
272                 Object *obedit = CTX_data_edit_object(C);
273                 Object *ob = CTX_data_active_object(C);
274                 if (obedit) {
275                         if (obedit->type == OB_MESH)
276                                 ts = createMeshSpace(C, reports, name, overwrite);
277                         else if (obedit->type == OB_ARMATURE)
278                                 ts = createBoneSpace(C, reports, name, overwrite);
279                 }
280                 else if (ob && (ob->mode & OB_MODE_POSE)) {
281                         ts = createBoneSpace(C, reports, name, overwrite);
282                 }
283                 else {
284                         ts = createObjectSpace(C, reports, name, overwrite);
285                 }
286         }
287
288         if (use && ts != NULL) {
289                 BIF_selectTransformOrientation(C, ts);
290         }
291 }
292
293 TransformOrientation *addMatrixSpace(bContext *C, float mat[3][3], char name[], int overwrite)
294 {
295         ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces;
296         TransformOrientation *ts = NULL;
297
298         if (overwrite) {
299                 ts = findOrientationName(transform_spaces, name);
300         }
301         else {
302                 uniqueOrientationName(transform_spaces, name);
303         }
304
305         /* if not, create a new one */
306         if (ts == NULL) {
307                 ts = MEM_callocN(sizeof(TransformOrientation), "UserTransSpace from matrix");
308                 BLI_addtail(transform_spaces, ts);
309                 strncpy(ts->name, name, sizeof(ts->name));
310         }
311
312         /* copy matrix into transform space */
313         copy_m3_m3(ts->mat, mat);
314
315         return ts;
316 }
317
318 void BIF_removeTransformOrientation(bContext *C, TransformOrientation *target)
319 {
320         ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces;
321         TransformOrientation *ts;
322         int i;
323         
324         for (i = 0, ts = transform_spaces->first; ts; ts = ts->next, i++) {
325                 if (ts == target) {
326                         View3D *v3d = CTX_wm_view3d(C);
327                         if (v3d) {
328                                 int selected_index = (v3d->twmode - V3D_MANIP_CUSTOM);
329                                 
330                                 // Transform_fix_me NEED TO DO THIS FOR ALL VIEW3D
331                                 if (selected_index == i) {
332                                         v3d->twmode = V3D_MANIP_GLOBAL; /* fallback to global   */
333                                 }
334                                 else if (selected_index > i) {
335                                         v3d->twmode--;
336                                 }
337                                 
338                         }
339
340                         BLI_freelinkN(transform_spaces, ts);
341                         break;
342                 }
343         }
344 }
345
346 void BIF_removeTransformOrientationIndex(bContext *C, int index)
347 {
348         ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces;
349         TransformOrientation *ts = BLI_findlink(transform_spaces, index);
350
351         if (ts) {
352                 View3D *v3d = CTX_wm_view3d(C);
353                 if (v3d) {
354                         int selected_index = (v3d->twmode - V3D_MANIP_CUSTOM);
355                         
356                         // Transform_fix_me NEED TO DO THIS FOR ALL VIEW3D
357                         if (selected_index == index) {
358                                 v3d->twmode = V3D_MANIP_GLOBAL; /* fallback to global   */
359                         }
360                         else if (selected_index > index) {
361                                 v3d->twmode--;
362                         }
363                         
364                 }
365
366                 BLI_freelinkN(transform_spaces, ts);
367         }
368 }
369
370 void BIF_selectTransformOrientation(bContext *C, TransformOrientation *target)
371 {
372         ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces;
373         View3D *v3d = CTX_wm_view3d(C);
374         TransformOrientation *ts;
375         int i;
376         
377         for (i = 0, ts = transform_spaces->first; ts; ts = ts->next, i++) {
378                 if (ts == target) {
379                         v3d->twmode = V3D_MANIP_CUSTOM + i;
380                         break;
381                 }
382         }
383 }
384
385 void BIF_selectTransformOrientationValue(bContext *C, int orientation)
386 {
387         View3D *v3d = CTX_wm_view3d(C);
388         if (v3d) /* currently using generic poll */
389                 v3d->twmode = orientation;
390 }
391
392 int BIF_countTransformOrientation(const bContext *C)
393 {
394         ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces;
395         TransformOrientation *ts;
396         int count = 0;
397
398         for (ts = transform_spaces->first; ts; ts = ts->next) {
399                 count++;
400         }
401         
402         return count;
403 }
404
405 void applyTransformOrientation(const bContext *C, float mat[3][3], char name[MAX_NAME])
406 {
407         TransformOrientation *ts;
408         View3D *v3d = CTX_wm_view3d(C);
409         int selected_index = (v3d->twmode - V3D_MANIP_CUSTOM);
410         int i;
411         
412         if (selected_index >= 0) {
413                 for (i = 0, ts = CTX_data_scene(C)->transform_spaces.first; ts; ts = ts->next, i++) {
414                         if (selected_index == i) {
415                                 
416                                 if (name) {
417                                         BLI_strncpy(name, ts->name, MAX_NAME);
418                                 }
419                                 
420                                 copy_m3_m3(mat, ts->mat);
421                                 break;
422                         }
423                 }
424         }
425 }
426
427 static int count_bone_select(bArmature *arm, ListBase *lb, int do_it) 
428 {
429         Bone *bone;
430         int do_next;
431         int total = 0;
432         
433         for (bone = lb->first; bone; bone = bone->next) {
434                 bone->flag &= ~BONE_TRANSFORM;
435                 do_next = do_it;
436                 if (do_it) {
437                         if (bone->layer & arm->layer) {
438                                 if (bone->flag & BONE_SELECTED) {
439                                         bone->flag |= BONE_TRANSFORM;
440                                         total++;
441                                         do_next = FALSE;    // no transform on children if one parent bone is selected
442                                 }
443                         }
444                 }
445                 total += count_bone_select(arm, &bone->childbase, do_next);
446         }
447         
448         return total;
449 }
450
451 void initTransformOrientation(bContext *C, TransInfo *t)
452 {
453         View3D *v3d = CTX_wm_view3d(C);
454         Object *ob = CTX_data_active_object(C);
455         Object *obedit = CTX_data_active_object(C);
456
457         switch (t->current_orientation) {
458                 case V3D_MANIP_GLOBAL:
459                         unit_m3(t->spacemtx);
460                         strcpy(t->spacename, IFACE_("global"));
461                         break;
462
463                 case V3D_MANIP_GIMBAL:
464                         unit_m3(t->spacemtx);
465                         if (gimbal_axis(ob, t->spacemtx)) {
466                                 strcpy(t->spacename, IFACE_("gimbal"));
467                                 break;
468                         }
469                 /* no gimbal fallthrough to normal */
470                 case V3D_MANIP_NORMAL:
471                         if (obedit || (ob && ob->mode & OB_MODE_POSE)) {
472                                 strcpy(t->spacename, IFACE_("normal"));
473                                 ED_getTransformOrientationMatrix(C, t->spacemtx, (v3d->around == V3D_ACTIVE));
474                                 break;
475                         }
476                 /* no break we define 'normal' as 'local' in Object mode */
477                 case V3D_MANIP_LOCAL:
478                         strcpy(t->spacename, IFACE_("local"));
479                 
480                         if (ob) {
481                                 copy_m3_m4(t->spacemtx, ob->obmat);
482                                 normalize_m3(t->spacemtx);
483                         }
484                         else {
485                                 unit_m3(t->spacemtx);
486                         }
487                 
488                         break;
489                 
490                 case V3D_MANIP_VIEW:
491                         if (t->ar->regiontype == RGN_TYPE_WINDOW) {
492                                 RegionView3D *rv3d = t->ar->regiondata;
493                                 float mat[3][3];
494
495                                 strcpy(t->spacename, IFACE_("view"));
496                                 copy_m3_m4(mat, rv3d->viewinv);
497                                 normalize_m3(mat);
498                                 copy_m3_m3(t->spacemtx, mat);
499                         }
500                         else {
501                                 unit_m3(t->spacemtx);
502                         }
503                         break;
504                 default: /* V3D_MANIP_CUSTOM */
505                         applyTransformOrientation(C, t->spacemtx, t->spacename);
506                         break;
507         }
508 }
509
510 int getTransformOrientation(const bContext *C, float normal[3], float plane[3], int activeOnly)
511 {
512         Scene *scene = CTX_data_scene(C);
513         View3D *v3d = CTX_wm_view3d(C);
514         Object *obedit = CTX_data_edit_object(C);
515         Base *base;
516         Object *ob = OBACT;
517         int result = ORIENTATION_NONE;
518
519         zero_v3(normal);
520         zero_v3(plane);
521
522         if (obedit) {
523                 float imat[3][3], mat[3][3];
524                 
525                 /* we need the transpose of the inverse for a normal... */
526                 copy_m3_m4(imat, ob->obmat);
527                 
528                 invert_m3_m3(mat, imat);
529                 transpose_m3(mat);
530
531                 ob = obedit;
532
533                 if (ob->type == OB_MESH) {
534                         BMEditMesh *em = BKE_editmesh_from_object(ob);
535                         BMVert *eve;
536                         BMEditSelection ese;
537                         float vec[3] = {0, 0, 0};
538                         
539                         /* USE LAST SELECTED WITH ACTIVE */
540                         if (activeOnly && BM_select_history_active_get(em->bm, &ese)) {
541                                 BM_editselection_normal(&ese, normal);
542                                 BM_editselection_plane(&ese, plane);
543                                 
544                                 switch (ese.htype) {
545                                         case BM_VERT:
546                                                 result = ORIENTATION_VERT;
547                                                 break;
548                                         case BM_EDGE:
549                                                 result = ORIENTATION_EDGE;
550                                                 break;
551                                         case BM_FACE:
552                                                 result = ORIENTATION_FACE;
553                                                 break;
554                                 }
555                         }
556                         else {
557                                 if (em->bm->totfacesel >= 1) {
558                                         BMFace *efa;
559                                         BMIter iter;
560
561                                         BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
562                                                 if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
563                                                         add_v3_v3(normal, efa->no);
564                                                         sub_v3_v3v3(vec,
565                                                                     BM_FACE_FIRST_LOOP(efa)->v->co,
566                                                                     BM_FACE_FIRST_LOOP(efa)->next->v->co);
567                                                         add_v3_v3(plane, vec);
568                                                 }
569                                         }
570                                         
571                                         result = ORIENTATION_FACE;
572                                 }
573                                 else if (em->bm->totvertsel == 3) {
574                                         BMVert *v1 = NULL, *v2 = NULL, *v3 = NULL;
575                                         BMIter iter;
576                                         float cotangent[3];
577                                         
578                                         BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
579                                                 if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
580                                                         if (v1 == NULL) {
581                                                                 v1 = eve; 
582                                                         }
583                                                         else if (v2 == NULL) {
584                                                                 v2 = eve;
585                                                         }
586                                                         else {
587                                                                 v3 = eve;
588
589                                                                 sub_v3_v3v3(plane, v2->co, v1->co);
590                                                                 sub_v3_v3v3(cotangent, v3->co, v2->co);
591                                                                 cross_v3_v3v3(normal, cotangent, plane);
592                                                                 break;
593                                                         }
594                                                 }
595                                         }
596
597                                         /* if there's an edge available, use that for the tangent */
598                                         if (em->bm->totedgesel >= 1) {
599                                                 BMEdge *eed = NULL;
600                                                 
601                                                 BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
602                                                         if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
603                                                                 sub_v3_v3v3(plane, eed->v2->co, eed->v1->co);
604                                                                 break;
605                                                         }
606                                                 }
607                                         }
608
609                                         result = ORIENTATION_FACE;
610                                 }
611                                 else if (em->bm->totedgesel == 1) {
612                                         BMEdge *eed = NULL;
613                                         BMIter iter;
614                                         
615                                         BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
616                                                 if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
617                                                         /* use average vert normals as plane and edge vector as normal */
618                                                         copy_v3_v3(plane, eed->v1->no);
619                                                         add_v3_v3(plane, eed->v2->no);
620                                                         sub_v3_v3v3(normal, eed->v2->co, eed->v1->co);
621                                                         break;
622                                                 }
623                                         }
624                                         result = ORIENTATION_EDGE;
625                                 }
626                                 else if (em->bm->totvertsel == 2) {
627                                         BMVert *v1 = NULL, *v2 = NULL;
628                                         BMIter iter;
629
630                                         BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
631                                                 if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
632                                                         if (v1 == NULL) {
633                                                                 v1 = eve; 
634                                                         }
635                                                         else {
636                                                                 v2 = eve;
637                                                                 
638                                                                 copy_v3_v3(plane, v1->no);
639                                                                 add_v3_v3(plane, v2->no);
640                                                                 sub_v3_v3v3(normal, v2->co, v1->co);
641                                                                 break; 
642                                                         }
643                                                 }
644                                         }
645                                         result = ORIENTATION_EDGE;
646                                 }
647                                 else if (em->bm->totvertsel == 1) {
648                                         BMIter iter;
649
650                                         BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
651                                                 if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
652                                                         copy_v3_v3(normal, eve->no);
653                                                         break;
654                                                 }
655                                         }
656                                         result = ORIENTATION_VERT;
657                                 }
658                                 else if (em->bm->totvertsel > 3) {
659                                         BMIter iter;
660
661                                         zero_v3(normal);
662
663                                         BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
664                                                 if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
665                                                         add_v3_v3(normal, eve->no);
666                                                 }
667                                         }
668                                         normalize_v3(normal);
669                                         result = ORIENTATION_VERT;
670                                 }
671                         }
672                 } /* end editmesh */
673                 else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
674                         Curve *cu = obedit->data;
675                         Nurb *nu;
676                         BezTriple *bezt;
677                         int a;
678                         ListBase *nurbs = BKE_curve_editNurbs_get(cu);
679
680                         for (nu = nurbs->first; nu; nu = nu->next) {
681                                 /* only bezier has a normal */
682                                 if (nu->type == CU_BEZIER) {
683                                         bezt = nu->bezt;
684                                         a = nu->pntsu;
685                                         while (a--) {
686                                                 /* exception */
687                                                 if ((bezt->f1 & SELECT) + (bezt->f2 & SELECT) + (bezt->f3 & SELECT) > SELECT) {
688                                                         sub_v3_v3v3(normal, bezt->vec[0], bezt->vec[2]);
689                                                 }
690                                                 else {
691                                                         if (bezt->f1) {
692                                                                 sub_v3_v3v3(normal, bezt->vec[0], bezt->vec[1]);
693                                                         }
694                                                         if (bezt->f2) {
695                                                                 sub_v3_v3v3(normal, bezt->vec[0], bezt->vec[2]);
696                                                         }
697                                                         if (bezt->f3) {
698                                                                 sub_v3_v3v3(normal, bezt->vec[1], bezt->vec[2]);
699                                                         }
700                                                 }
701                                                 bezt++;
702                                         }
703                                 }
704                         }
705                         
706                         if (!is_zero_v3(normal)) {
707                                 result = ORIENTATION_NORMAL;
708                         }
709                 }
710                 else if (obedit->type == OB_MBALL) {
711                         MetaBall *mb = obedit->data;
712                         
713                         if (mb->lastelem) {
714                                 float qmat[3][3];
715
716                                 /* Rotation of MetaElem is stored in quat */
717                                 quat_to_mat3(qmat, mb->lastelem->quat);
718
719                                 copy_v3_v3(normal, qmat[2]);
720
721                                 negate_v3_v3(plane, qmat[1]);
722                                 
723                                 result = ORIENTATION_FACE;
724                         }
725                 }
726                 else if (obedit->type == OB_ARMATURE) {
727                         bArmature *arm = obedit->data;
728                         EditBone *ebone;
729                         int ok = FALSE;
730                         
731                         /* grr. but better then duplicate code */
732 #define EBONE_CALC_NORMAL_PLANE  { \
733                         float tmat[3][3]; \
734                         float vec[3]; \
735                         sub_v3_v3v3(vec, ebone->tail, ebone->head); \
736                         normalize_v3(vec); \
737                         add_v3_v3(normal, vec); \
738                         \
739                         vec_roll_to_mat3(vec, ebone->roll, tmat); \
740                         add_v3_v3(plane, tmat[2]); \
741                 } (void)0
742
743
744                         if (activeOnly && (ebone = arm->act_edbone)) {
745                                 EBONE_CALC_NORMAL_PLANE;
746                                 ok = TRUE;
747                         }
748                         else {
749                                 for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
750                                         if (arm->layer & ebone->layer) {
751                                                 if (ebone->flag & BONE_SELECTED) {
752                                                         EBONE_CALC_NORMAL_PLANE;
753                                                         ok = TRUE;
754                                                 }
755                                         }
756                                 }
757                         }
758                         
759                         if (ok) {
760                                 normalize_v3(normal);
761                                 normalize_v3(plane);
762
763                                 if (!is_zero_v3(plane)) {
764                                         result = ORIENTATION_EDGE;
765                                 }
766                         }
767 #undef EBONE_CALC_NORMAL_PLANE
768                 }
769
770                 /* Vectors from edges don't need the special transpose inverse multiplication */
771                 if (result == ORIENTATION_EDGE) {
772                         mul_mat3_m4_v3(ob->obmat, normal);
773                         mul_mat3_m4_v3(ob->obmat, plane);
774                 }
775                 else {
776                         mul_m3_v3(mat, normal);
777                         mul_m3_v3(mat, plane);
778                 }
779         }
780         else if (ob && (ob->mode & OB_MODE_POSE)) {
781                 bArmature *arm = ob->data;
782                 bPoseChannel *pchan;
783                 float imat[3][3], mat[3][3];
784                 int ok = FALSE;
785
786                 if (activeOnly && (pchan = BKE_pose_channel_active(ob))) {
787                         add_v3_v3(normal, pchan->pose_mat[2]);
788                         add_v3_v3(plane, pchan->pose_mat[1]);
789                         ok = TRUE;
790                 }
791                 else {
792                         int totsel;
793
794                         totsel = count_bone_select(arm, &arm->bonebase, 1);
795                         if (totsel) {
796                                 /* use channels to get stats */
797                                 for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
798                                         if (pchan->bone && pchan->bone->flag & BONE_TRANSFORM) {
799                                                 add_v3_v3(normal, pchan->pose_mat[2]);
800                                                 add_v3_v3(plane, pchan->pose_mat[1]);
801                                         }
802                                 }
803                                 ok = TRUE;
804                         }
805                 }
806
807                 /* use for both active & all */
808                 if (ok) {
809                         negate_v3(plane);
810                         
811                         /* we need the transpose of the inverse for a normal... */
812                         copy_m3_m4(imat, ob->obmat);
813                         
814                         invert_m3_m3(mat, imat);
815                         transpose_m3(mat);
816                         mul_m3_v3(mat, normal);
817                         mul_m3_v3(mat, plane);
818                         
819                         result = ORIENTATION_EDGE;
820                 }
821         }
822         else if (ob && (ob->mode & (OB_MODE_ALL_PAINT | OB_MODE_PARTICLE_EDIT))) {
823                 /* pass */
824         }
825         else {
826                 /* we need the one selected object, if its not active */
827                 ob = OBACT;
828                 if (ob && !(ob->flag & SELECT)) ob = NULL;
829                 
830                 for (base = scene->base.first; base; base = base->next) {
831                         if (TESTBASELIB(v3d, base)) {
832                                 if (ob == NULL) {
833                                         ob = base->object;
834                                         break;
835                                 }
836                         }
837                 }
838                 
839                 if (ob) {
840                         copy_v3_v3(normal, ob->obmat[2]);
841                         copy_v3_v3(plane, ob->obmat[1]);
842                 }
843                 result = ORIENTATION_NORMAL;
844         }
845         
846         return result;
847 }
848
849 void ED_getTransformOrientationMatrix(const bContext *C, float orientation_mat[3][3], const bool activeOnly)
850 {
851         float normal[3] = {0.0, 0.0, 0.0};
852         float plane[3] = {0.0, 0.0, 0.0};
853
854         int type;
855
856         type = getTransformOrientation(C, normal, plane, activeOnly);
857
858         switch (type) {
859                 case ORIENTATION_NORMAL:
860                         if (createSpaceNormalTangent(orientation_mat, normal, plane) == 0) {
861                                 type = ORIENTATION_NONE;
862                         }
863                         break;
864                 case ORIENTATION_VERT:
865                         if (createSpaceNormal(orientation_mat, normal) == 0) {
866                                 type = ORIENTATION_NONE;
867                         }
868                         break;
869                 case ORIENTATION_EDGE:
870                         if (createSpaceNormalTangent(orientation_mat, normal, plane) == 0) {
871                                 type = ORIENTATION_NONE;
872                         }
873                         break;
874                 case ORIENTATION_FACE:
875                         if (createSpaceNormalTangent(orientation_mat, normal, plane) == 0) {
876                                 type = ORIENTATION_NONE;
877                         }
878                         break;
879         }
880
881         if (type == ORIENTATION_NONE) {
882                 unit_m3(orientation_mat);
883         }
884 }