4 * ***** BEGIN GPL LICENSE BLOCK *****
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 * Contributor(s): Martin Poirier
22 * ***** END GPL LICENSE BLOCK *****
27 #include "MEM_guardedalloc.h"
29 #include "DNA_armature_types.h"
30 #include "DNA_action_types.h"
31 #include "DNA_curve_types.h"
32 #include "DNA_listBase.h"
33 #include "DNA_object_types.h"
34 #include "DNA_meshdata_types.h"
35 #include "DNA_mesh_types.h"
36 #include "DNA_meta_types.h"
37 #include "DNA_scene_types.h"
38 #include "DNA_screen_types.h"
39 #include "DNA_space_types.h"
40 #include "DNA_view3d_types.h"
42 #include "BKE_global.h"
43 #include "BKE_utildefines.h"
44 #include "BKE_armature.h"
45 #include "BKE_context.h"
47 #include "BLI_arithb.h"
48 #include "BLI_blenlib.h"
49 #include "BLI_editVert.h"
51 //#include "BIF_editmesh.h"
52 //#include "BIF_interface.h"
53 //#include "BIF_space.h"
54 //#include "BIF_toolbox.h"
56 #include "ED_armature.h"
60 #include "UI_interface.h"
62 #include "RNA_define.h"
64 #include "transform.h"
66 /* *********************** TransSpace ************************** */
68 void BIF_clearTransformOrientation(bContext *C)
70 ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces;
71 BLI_freelistN(transform_spaces);
74 // Need to loop over all view3d
75 // if (G.vd->twmode >= V3D_MANIP_CUSTOM)
76 // G.vd->twmode = V3D_MANIP_GLOBAL; /* fallback to global */
79 void BIF_manageTransformOrientation(bContext *C, int confirm, int set) {
80 Object *obedit = CTX_data_edit_object(C);
81 Object *ob = CTX_data_active_object(C);
85 if (obedit->type == OB_MESH)
86 index = manageMeshSpace(C, confirm, set);
87 else if (obedit->type == OB_ARMATURE)
88 index = manageBoneSpace(C, confirm, set);
90 else if (ob && (ob->flag & OB_POSEMODE)) {
91 index = manageBoneSpace(C, confirm, set);
94 index = manageObjectSpace(C, confirm, set);
97 if (set && index != -1)
99 BIF_selectTransformOrientationValue(C, V3D_MANIP_CUSTOM + index);
103 int manageObjectSpace(bContext *C, int confirm, int set) {
104 Base *base = CTX_data_active_base(C);
109 //XXX if (confirm == 0) {
110 // if (set && pupmenu("Custom Orientation %t|Add and Use Active Object%x1") != 1) {
113 // else if (set == 0 && pupmenu("Custom Orientation %t|Add Active Object%x1") != 1) {
118 return addObjectSpace(C, base->object);
121 /* return 1 on confirm */
122 int confirmSpace(int set, char text[])
127 sprintf(menu, "Custom Orientation %%t|Add and Use %s%%x1", text);
130 sprintf(menu, "Custom Orientation %%t|Add %s%%x1", text);
133 //XXX if (pupmenu(menu) == 1) {
141 int manageBoneSpace(bContext *C, int confirm, int set) {
143 float normal[3], plane[3];
147 getTransformOrientation(C, normal, plane, 0);
149 if (confirm == 0 && confirmSpace(set, "Bone") == 0) {
153 if (createSpaceNormalTangent(mat, normal, plane) == 0) {
154 //XXX error("Cannot use zero-length bone");
158 strcpy(name, "Bone");
161 //XXX sbutton(name, 1, 35, "name: ");
163 index = addMatrixSpace(C, mat, name);
167 int manageMeshSpace(bContext *C, int confirm, int set) {
169 float normal[3], plane[3];
174 type = getTransformOrientation(C, normal, plane, 0);
178 case ORIENTATION_VERT:
179 if (confirm == 0 && confirmSpace(set, "vertex") == 0) {
183 if (createSpaceNormal(mat, normal) == 0) {
184 // XXX error("Cannot use vertex with zero-length normal");
188 strcpy(name, "Vertex");
190 case ORIENTATION_EDGE:
191 if (confirm == 0 && confirmSpace(set, "Edge") == 0) {
195 if (createSpaceNormalTangent(mat, normal, plane) == 0) {
196 // XXX error("Cannot use zero-length edge");
200 strcpy(name, "Edge");
202 case ORIENTATION_FACE:
203 if (confirm == 0 && confirmSpace(set, "Face") == 0) {
207 if (createSpaceNormalTangent(mat, normal, plane) == 0) {
208 // XXX error("Cannot use zero-area face");
212 strcpy(name, "Face");
220 //XXX sbutton(name, 1, 35, "name: ");
222 index = addMatrixSpace(C, mat, name);
226 int createSpaceNormal(float mat[3][3], float normal[3])
228 float tangent[3] = {0.0f, 0.0f, 1.0f};
230 VECCOPY(mat[2], normal);
231 if (Normalize(mat[2]) == 0.0f) {
232 return 0; /* error return */
235 Crossf(mat[0], mat[2], tangent);
236 if (Inpf(mat[0], mat[0]) == 0.0f) {
238 tangent[1] = tangent[2] = 0.0f;
239 Crossf(mat[0], tangent, mat[2]);
242 Crossf(mat[1], mat[2], mat[0]);
249 int createSpaceNormalTangent(float mat[3][3], float normal[3], float tangent[3])
251 VECCOPY(mat[2], normal);
252 if (Normalize(mat[2]) == 0.0f) {
253 return 0; /* error return */
256 /* preempt zero length tangent from causing trouble */
257 if (tangent[0] == 0 && tangent[1] == 0 && tangent[2] == 0)
262 Crossf(mat[0], mat[2], tangent);
263 if (Normalize(mat[0]) == 0.0f) {
264 return 0; /* error return */
267 Crossf(mat[1], mat[2], mat[0]);
275 int addObjectSpace(bContext *C, Object *ob) {
279 Mat3CpyMat4(mat, ob->obmat);
282 strncpy(name, ob->id.name+2, 35);
285 //XXX sbutton(name, 1, 35, "name: ");
287 return addMatrixSpace(C, mat, name);
290 int addMatrixSpace(bContext *C, float mat[3][3], char name[]) {
291 ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces;
292 TransformOrientation *ts;
295 /* if name is found in list, reuse that transform space */
296 for (index = 0, ts = transform_spaces->first; ts; ts = ts->next, index++) {
297 if (strncmp(ts->name, name, 35) == 0) {
302 /* if not, create a new one */
305 ts = MEM_callocN(sizeof(TransformOrientation), "UserTransSpace from matrix");
306 BLI_addtail(transform_spaces, ts);
307 strncpy(ts->name, name, 35);
310 /* copy matrix into transform space */
311 Mat3CpyMat3(ts->mat, mat);
313 ED_undo_push(C, "Add/Update Transform Orientation");
318 void BIF_removeTransformOrientation(bContext *C, TransformOrientation *target) {
319 ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces;
320 TransformOrientation *ts = transform_spaces->first;
321 //int selected_index = (G.vd->twmode - V3D_MANIP_CUSTOM);
324 for (i = 0, ts = transform_spaces->first; ts; ts = ts->next, i++) {
326 // Transform_fix_me NEED TO DO THIS FOR ALL VIEW3D
327 // if (selected_index == i) {
328 // G.vd->twmode = V3D_MANIP_GLOBAL; /* fallback to global */
330 // else if (selected_index > i)
333 BLI_freelinkN(transform_spaces, ts);
337 ED_undo_push(C, "Remove Transform Orientation");
340 void BIF_selectTransformOrientation(bContext *C, TransformOrientation *target) {
341 ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces;
342 View3D *v3d = CTX_wm_view3d(C);
343 TransformOrientation *ts = transform_spaces->first;
346 for (i = 0, ts = transform_spaces->first; ts; ts = ts->next, i++) {
348 v3d->twmode = V3D_MANIP_CUSTOM + i;
354 void BIF_selectTransformOrientationValue(bContext *C, int orientation) {
355 View3D *v3d = CTX_wm_view3d(C);
356 v3d->twmode = orientation;
359 EnumPropertyItem *BIF_enumTransformOrientation(bContext *C)
362 ListBase *transform_spaces;
363 TransformOrientation *ts= NULL;
365 EnumPropertyItem global = {V3D_MANIP_GLOBAL, "GLOBAL", 0, "Global", ""};
366 EnumPropertyItem normal = {V3D_MANIP_NORMAL, "NORMAL", 0, "Normal", ""};
367 EnumPropertyItem local = {V3D_MANIP_LOCAL, "LOCAL", 0, "Local", ""};
368 EnumPropertyItem view = {V3D_MANIP_VIEW, "VIEW", 0, "View", ""};
369 EnumPropertyItem tmp = {0, "", 0, "", ""};
370 EnumPropertyItem *item= NULL;
371 int i = V3D_MANIP_CUSTOM, totitem= 0;
373 RNA_enum_item_add(&item, &totitem, &global);
374 RNA_enum_item_add(&item, &totitem, &normal);
375 RNA_enum_item_add(&item, &totitem, &local);
376 RNA_enum_item_add(&item, &totitem, &view);
379 scene= CTX_data_scene(C);
382 transform_spaces = &scene->transform_spaces;
383 ts = transform_spaces->first;
388 RNA_enum_item_add_separator(&item, &totitem);
390 for(; ts; ts = ts->next) {
391 tmp.identifier = "CUSTOM";
394 RNA_enum_item_add(&item, &totitem, &tmp);
397 RNA_enum_item_end(&item, &totitem);
402 char * BIF_menustringTransformOrientation(const bContext *C, char *title) {
403 char menu[] = "%t|Global%x0|Local%x1|Normal%x2|View%x3";
404 ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces;
405 TransformOrientation *ts;
406 int i = V3D_MANIP_CUSTOM;
410 str_menu = MEM_callocN(strlen(menu) + strlen(title) + 1 + 40 * BIF_countTransformOrientation(C), "UserTransSpace from matrix");
413 p += sprintf(str_menu, "%s", title);
414 p += sprintf(p, "%s", menu);
416 for (ts = transform_spaces->first; ts; ts = ts->next) {
417 p += sprintf(p, "|%s%%x%d", ts->name, i++);
423 int BIF_countTransformOrientation(const bContext *C) {
424 ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces;
425 TransformOrientation *ts;
428 for (ts = transform_spaces->first; ts; ts = ts->next) {
435 void applyTransformOrientation(const bContext *C, TransInfo *t) {
436 TransformOrientation *ts;
437 View3D *v3d = CTX_wm_view3d(C);
438 int selected_index = (v3d->twmode - V3D_MANIP_CUSTOM);
441 if (selected_index >= 0) {
442 for (i = 0, ts = CTX_data_scene(C)->transform_spaces.first; ts; ts = ts->next, i++) {
443 if (selected_index == i) {
444 strcpy(t->spacename, ts->name);
445 Mat3CpyMat3(t->spacemtx, ts->mat);
452 static int count_bone_select(bArmature *arm, ListBase *lb, int do_it)
458 for(bone= lb->first; bone; bone= bone->next) {
459 bone->flag &= ~BONE_TRANSFORM;
462 if(bone->layer & arm->layer) {
463 if (bone->flag & BONE_SELECTED) {
464 bone->flag |= BONE_TRANSFORM;
466 do_next= 0; // no transform on children if one parent bone is selected
470 total += count_bone_select(arm, &bone->childbase, do_next);
476 void initTransformOrientation(bContext *C, TransInfo *t)
478 View3D *v3d = CTX_wm_view3d(C);
479 Object *ob = CTX_data_active_object(C);
480 Object *obedit = CTX_data_active_object(C);
481 float normal[3]={0.0, 0.0, 0.0};
482 float plane[3]={0.0, 0.0, 0.0};
484 switch(t->current_orientation) {
485 case V3D_MANIP_GLOBAL:
486 strcpy(t->spacename, "global");
489 case V3D_MANIP_NORMAL:
490 if(obedit || ob->flag & OB_POSEMODE) {
494 strcpy(t->spacename, "normal");
496 type = getTransformOrientation(C, normal, plane, (v3d->around == V3D_ACTIVE));
500 case ORIENTATION_NORMAL:
501 if (createSpaceNormalTangent(mat, normal, plane) == 0)
503 type = ORIENTATION_NONE;
506 case ORIENTATION_VERT:
507 if (createSpaceNormal(mat, normal) == 0)
509 type = ORIENTATION_NONE;
512 case ORIENTATION_EDGE:
513 if (createSpaceNormalTangent(mat, normal, plane) == 0)
515 type = ORIENTATION_NONE;
518 case ORIENTATION_FACE:
519 if (createSpaceNormalTangent(mat, normal, plane) == 0)
521 type = ORIENTATION_NONE;
526 if (type == ORIENTATION_NONE)
528 Mat3One(t->spacemtx);
532 Mat3CpyMat3(t->spacemtx, mat);
536 /* no break we define 'normal' as 'local' in Object mode */
537 case V3D_MANIP_LOCAL:
538 strcpy(t->spacename, "local");
539 Mat3CpyMat4(t->spacemtx, ob->obmat);
540 Mat3Ortho(t->spacemtx);
544 if (t->ar->regiontype == RGN_TYPE_WINDOW)
546 RegionView3D *rv3d = t->ar->regiondata;
549 strcpy(t->spacename, "view");
550 Mat3CpyMat4(mat, rv3d->viewinv);
552 Mat3CpyMat3(t->spacemtx, mat);
556 Mat3One(t->spacemtx);
559 default: /* V3D_MANIP_CUSTOM */
560 applyTransformOrientation(C, t);
565 int getTransformOrientation(const bContext *C, float normal[3], float plane[3], int activeOnly)
567 Scene *scene = CTX_data_scene(C);
568 View3D *v3d = CTX_wm_view3d(C);
569 Object *obedit= CTX_data_edit_object(C);
572 int result = ORIENTATION_NONE;
574 normal[0] = normal[1] = normal[2] = 0;
575 plane[0] = plane[1] = plane[2] = 0;
579 float imat[3][3], mat[3][3];
581 /* we need the transpose of the inverse for a normal... */
582 Mat3CpyMat4(imat, ob->obmat);
589 if(ob->type==OB_MESH)
592 EditMesh *em = me->edit_mesh;
595 float vec[3]= {0,0,0};
597 /* USE LAST SELECTED WITH ACTIVE */
598 if (activeOnly && EM_get_actSelection(em, &ese))
600 EM_editselection_normal(normal, &ese);
601 EM_editselection_plane(plane, &ese);
606 result = ORIENTATION_VERT;
609 result = ORIENTATION_EDGE;
612 result = ORIENTATION_FACE;
618 if (em->totfacesel >= 1)
622 for(efa= em->faces.first; efa; efa= efa->next)
626 VECADD(normal, normal, efa->n);
627 VecSubf(vec, efa->v2->co, efa->v1->co);
628 VECADD(plane, plane, vec);
632 result = ORIENTATION_FACE;
634 else if (em->totvertsel == 3)
636 EditVert *v1 = NULL, *v2 = NULL, *v3 = NULL;
639 for (eve = em->verts.first; eve; eve = eve->next)
641 if ( eve->f & SELECT ) {
645 else if (v2 == NULL) {
651 VecSubf(plane, v2->co, v1->co);
652 VecSubf(cotangent, v3->co, v2->co);
653 Crossf(normal, cotangent, plane);
659 /* if there's an edge available, use that for the tangent */
660 if (em->totedgesel >= 1)
662 EditEdge *eed = NULL;
664 for(eed= em->edges.first; eed; eed= eed->next) {
665 if(eed->f & SELECT) {
666 VecSubf(plane, eed->v2->co, eed->v1->co);
672 result = ORIENTATION_FACE;
674 else if (em->totedgesel == 1)
678 for(eed= em->edges.first; eed; eed= eed->next) {
679 if(eed->f & SELECT) {
680 /* use average vert normals as plane and edge vector as normal */
681 VECCOPY(plane, eed->v1->no);
682 VECADD(plane, plane, eed->v2->no);
683 VecSubf(normal, eed->v2->co, eed->v1->co);
687 result = ORIENTATION_EDGE;
689 else if (em->totvertsel == 2)
691 EditVert *v1 = NULL, *v2 = NULL;
693 for (eve = em->verts.first; eve; eve = eve->next)
695 if ( eve->f & SELECT ) {
702 VECCOPY(plane, v1->no);
703 VECADD(plane, plane, v2->no);
704 VecSubf(normal, v2->co, v1->co);
709 result = ORIENTATION_EDGE;
711 else if (em->totvertsel == 1)
713 for (eve = em->verts.first; eve; eve = eve->next)
715 if ( eve->f & SELECT ) {
716 VECCOPY(normal, eve->no);
720 result = ORIENTATION_VERT;
722 else if (em->totvertsel > 3)
724 normal[0] = normal[1] = normal[2] = 0;
726 for (eve = em->verts.first; eve; eve = eve->next)
728 if ( eve->f & SELECT ) {
729 VecAddf(normal, normal, eve->no);
733 result = ORIENTATION_VERT;
737 else if ELEM(obedit->type, OB_CURVE, OB_SURF)
739 Curve *cu= obedit->data;
744 for (nu = cu->editnurb->first; nu; nu = nu->next)
746 /* only bezier has a normal */
747 if((nu->type & 7) == CU_BEZIER)
754 if ( (bezt->f1 & SELECT) + (bezt->f2 & SELECT) + (bezt->f3 & SELECT) > SELECT )
756 VecSubf(normal, bezt->vec[0], bezt->vec[2]);
762 VecSubf(normal, bezt->vec[0], bezt->vec[1]);
766 VecSubf(normal, bezt->vec[0], bezt->vec[2]);
770 VecSubf(normal, bezt->vec[1], bezt->vec[2]);
778 if (normal[0] != 0 || normal[1] != 0 || normal[2] != 0)
780 result = ORIENTATION_NORMAL;
783 else if(obedit->type==OB_MBALL)
787 extern ListBase editelems; /* go away ! */
788 MetaElem *ml, *ml_sel = NULL;
790 /* loop and check that only one element is selected */
791 for (ml = editelems.first; ml; ml = ml->next)
793 if (ml->flag & SELECT) {
810 /* Rotation of MetaElem is stored in quat */
811 QuatToMat4(ml_sel->quat, mat);
813 VECCOPY(normal, mat[2]);
814 VECCOPY(plane, mat[1]);
816 VecMulf(plane, -1.0);
818 result = ORIENTATION_NORMAL;
823 else if (obedit->type == OB_ARMATURE)
825 bArmature *arm = obedit->data;
828 for (ebone = arm->edbo->first; ebone; ebone=ebone->next) {
829 if (arm->layer & ebone->layer)
831 if (ebone->flag & BONE_SELECTED)
835 VecSubf(vec, ebone->tail, ebone->head);
837 VecAddf(normal, normal, vec);
839 vec_roll_to_mat3(vec, ebone->roll, mat);
840 VecAddf(plane, plane, mat[2]);
848 if (plane[0] != 0 || plane[1] != 0 || plane[2] != 0)
850 result = ORIENTATION_EDGE;
855 /* Vectors from edges don't need the special transpose inverse multiplication */
856 if (result == ORIENTATION_EDGE)
858 Mat4Mul3Vecfl(ob->obmat, normal);
859 Mat4Mul3Vecfl(ob->obmat, plane);
863 Mat3MulVecfl(mat, normal);
864 Mat3MulVecfl(mat, plane);
867 else if(ob && (ob->flag & OB_POSEMODE))
869 bArmature *arm= ob->data;
873 totsel = count_bone_select(arm, &arm->bonebase, 1);
875 float imat[3][3], mat[3][3];
877 /* use channels to get stats */
878 for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
879 if (pchan->bone && pchan->bone->flag & BONE_TRANSFORM) {
880 VecAddf(normal, normal, pchan->pose_mat[2]);
881 VecAddf(plane, plane, pchan->pose_mat[1]);
884 VecMulf(plane, -1.0);
886 /* we need the transpose of the inverse for a normal... */
887 Mat3CpyMat4(imat, ob->obmat);
891 Mat3MulVecfl(mat, normal);
892 Mat3MulVecfl(mat, plane);
894 result = ORIENTATION_EDGE;
897 else if(ob && (ob->mode & OB_MODE_SCULPT))
900 else if(G.f & (G_VERTEXPAINT + G_TEXTUREPAINT + G_WEIGHTPAINT))
903 else if(G.f & G_PARTICLEEDIT)
907 /* we need the one selected object, if its not active */
909 if(ob && !(ob->flag & SELECT)) ob = NULL;
911 for(base= scene->base.first; base; base= base->next) {
912 if TESTBASELIB(v3d, base) {
920 VECCOPY(normal, ob->obmat[2]);
921 VECCOPY(plane, ob->obmat[1]);
922 result = ORIENTATION_NORMAL;