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