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