301ac8aa24835a48fc584a60c565ca80bd724593
[blender.git] / source / blender / src / transform_orientations.c
1 /**
2  * $Id: 
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
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.
10  *
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.
15  *
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.
19  *
20  * Contributor(s): Martin Poirier
21  *
22  * ***** END GPL LICENSE BLOCK *****
23  */
24
25 #include <string.h>
26
27 #include "MEM_guardedalloc.h"
28
29 #include "DNA_curve_types.h"
30 #include "DNA_listBase.h"
31 #include "DNA_object_types.h"
32 #include "DNA_meshdata_types.h"
33 #include "DNA_mesh_types.h"
34 #include "DNA_meta_types.h"
35 #include "DNA_scene_types.h"
36 #include "DNA_space_types.h"
37 #include "DNA_view3d_types.h"
38
39 #include "BKE_global.h"
40 #include "BKE_utildefines.h"
41
42 #include "BLI_arithb.h"
43 #include "BLI_blenlib.h"
44 #include "BLI_editVert.h"
45
46 #include "BIF_editmesh.h"
47 #include "BIF_interface.h"
48 #include "BIF_space.h"
49 #include "BIF_toolbox.h"
50
51 #include "blendef.h"
52
53
54 #include "transform.h"
55
56
57 /* *********************** TransSpace ************************** */
58
59 void BIF_clearTransformOrientation(void)
60 {
61         ListBase *transform_spaces = &G.scene->transform_spaces;
62         BLI_freelistN(transform_spaces);
63         
64         if (G.vd->twmode >= V3D_MANIP_CUSTOM)
65                 G.vd->twmode = V3D_MANIP_GLOBAL;        /* fallback to global   */
66 }
67  
68 void BIF_manageTransformOrientation(int confirm, int set) {
69         int index = -1; 
70         
71         if (G.obedit) {
72                 if (G.obedit->type == OB_MESH)
73                         index = manageMeshSpace(confirm, set);
74         }
75         else {
76                 index = manageObjectSpace(confirm, set);
77         }
78         
79         if (set && index != -1)
80         {
81                 BIF_selectTransformOrientationFromIndex(index);
82         }
83 }
84
85 int manageObjectSpace(int confirm, int set) {
86         Base *base = BASACT;
87
88         if (base == NULL)
89                 return -1;
90
91         if (confirm == 0) {
92                 if (set && pupmenu("Custom Orientation %t|Add and Use Active Object%x1") != 1) {
93                         return -1;
94                 }
95                 else if (set == 0 && pupmenu("Custom Orientation %t|Add Active Object%x1") != 1) {
96                         return -1;
97                 }
98         }
99
100         return addObjectSpace(base->object);
101 }
102
103 /* return 1 on confirm */
104 int confirmSpace(int set, char text[])
105 {
106         char menu[64];
107         
108         if (set) {
109                 sprintf(menu, "Custom Orientation %%t|Add and Use %s%%x1", text);
110         }
111         else {
112                 sprintf(menu, "Custom Orientation %%t|Add %s%%x1", text);
113         }
114         
115         if (pupmenu(menu) == 1) {
116                 return 1;
117         }
118         else {
119                 return 0;
120         }
121 }
122
123
124 int manageMeshSpace(int confirm, int set) {
125         float mat[3][3];
126         float normal[3], plane[3];
127         char name[36] = "";
128         int index;
129         int type;
130
131         type = getTransformOrientation(normal, plane, 0);
132         
133         switch (type)
134         {
135                 case ORIENTATION_VERT:
136                         if (confirm == 0 && confirmSpace(set, "vertex") == 0) {
137                                 return -1;
138                         }
139         
140                         if (createSpaceNormal(mat, normal) == 0) {
141                                 error("Cannot use vertex with zero-length normal");
142                                 return -1;
143                         }
144         
145                         strcpy(name, "Vertex");
146                         break;
147                 case ORIENTATION_EDGE:
148                         if (confirm == 0 && confirmSpace(set, "Edge") == 0) {
149                                 return -1;
150                         }
151         
152                         if (createSpaceNormalTangent(mat, normal, plane) == 0) {
153                                 error("Cannot use zero-length edge");
154                                 return -1;
155                         }
156         
157                         strcpy(name, "Edge");
158                         break;
159                 case ORIENTATION_FACE:
160                         if (confirm == 0 && confirmSpace(set, "Face") == 0) {
161                                 return -1;
162                         }
163         
164                         if (createSpaceNormalTangent(mat, normal, plane) == 0) {
165                                 error("Cannot use zero-area face");
166                                 return -1;
167                         }
168         
169                         strcpy(name, "Face");
170                         break;
171                 default:
172                         return -1;
173                         break;
174         }
175
176         /* Input name */
177         sbutton(name, 1, 35, "name: ");
178
179         index = addMatrixSpace(mat, name);
180         return index;
181 }
182
183 int createSpaceNormal(float mat[3][3], float normal[3])
184 {
185         float tangent[3] = {0.0f, 0.0f, 1.0f};
186         
187         VECCOPY(mat[2], normal);
188         if (Normalize(mat[2]) == 0.0f) {
189                 return 0; /* error return */
190         }
191
192         Crossf(mat[0], mat[2], tangent);
193         if (Inpf(mat[0], mat[0]) == 0.0f) {
194                 tangent[0] = 1.0f;
195                 tangent[1] = tangent[2] = 0.0f;
196                 Crossf(mat[0], tangent, mat[2]);
197         }
198
199         Crossf(mat[1], mat[2], mat[0]);
200
201         Mat3Ortho(mat);
202         
203         return 1;
204 }
205
206 int createSpaceNormalTangent(float mat[3][3], float normal[3], float tangent[3])
207 {
208         VECCOPY(mat[2], normal);
209         if (Normalize(mat[2]) == 0.0f) {
210                 return 0; /* error return */
211         }
212         
213         /* preempt zero length tangent from causing trouble */
214         if (tangent[0] == 0 && tangent[1] == 0 && tangent[2] == 0)
215         {
216                 tangent[2] = 1;
217         }
218
219         Crossf(mat[0], mat[2], tangent);
220         if (Normalize(mat[0]) == 0.0f) {
221                 return 0; /* error return */
222         }
223         
224         Crossf(mat[1], mat[2], mat[0]);
225
226         Mat3Ortho(mat);
227         
228         return 1;
229 }
230
231
232 int addObjectSpace(Object *ob) {
233         float mat[3][3];
234         char name[36] = "";
235
236         Mat3CpyMat4(mat, ob->obmat);
237         Mat3Ortho(mat);
238
239         strncpy(name, ob->id.name+2, 35);
240
241         /* Input name */
242         sbutton(name, 1, 35, "name: ");
243
244         return addMatrixSpace(mat, name);
245 }
246
247 int addMatrixSpace(float mat[3][3], char name[]) {
248         ListBase *transform_spaces = &G.scene->transform_spaces;
249         TransformOrientation *ts;
250         int index = 0;
251
252         /* if name is found in list, reuse that transform space */      
253         for (index = 0, ts = transform_spaces->first; ts; ts = ts->next, index++) {
254                 if (strncmp(ts->name, name, 35) == 0) {
255                         break;
256                 }
257         }
258
259         /* if not, create a new one */
260         if (ts == NULL)
261         {
262                 ts = MEM_callocN(sizeof(TransformOrientation), "UserTransSpace from matrix");
263                 BLI_addtail(transform_spaces, ts);
264                 strncpy(ts->name, name, 35);
265         }
266
267         /* copy matrix into transform space */
268         Mat3CpyMat3(ts->mat, mat);
269
270         BIF_undo_push("Add/Update Transform Orientation");
271         
272         return index;
273 }
274
275 void BIF_removeTransformOrientation(TransformOrientation *target) {
276         ListBase *transform_spaces = &G.scene->transform_spaces;
277         TransformOrientation *ts = transform_spaces->first;
278         int selected_index = (G.vd->twmode - V3D_MANIP_CUSTOM);
279         int i;
280         
281         for (i = 0, ts = transform_spaces->first; ts; ts = ts->next, i++) {
282                 if (ts == target) {
283                         if (selected_index == i) {
284                                 G.vd->twmode = V3D_MANIP_GLOBAL;        /* fallback to global   */
285                         }
286                         else if (selected_index > i)
287                                 G.vd->twmode--;
288
289                         BLI_freelinkN(transform_spaces, ts);
290                         break;
291                 }
292         }
293         BIF_undo_push("Remove Transform Orientation");
294 }
295
296 void BIF_selectTransformOrientation(TransformOrientation *target) {
297         ListBase *transform_spaces = &G.scene->transform_spaces;
298         TransformOrientation *ts = transform_spaces->first;
299         int i;
300         
301         for (i = 0, ts = transform_spaces->first; ts; ts = ts->next, i++) {
302                 if (ts == target) {
303                         G.vd->twmode = V3D_MANIP_CUSTOM + i;
304                         break;
305                 }
306         }
307 }
308
309 void BIF_selectTransformOrientationFromIndex(int index) {
310         G.vd->twmode = V3D_MANIP_CUSTOM + index;
311 }
312
313 char * BIF_menustringTransformOrientation(char *title) {
314         char menu[] = "%t|Global%x0|Local%x1|Normal%x2|View%x3";
315         ListBase *transform_spaces = &G.scene->transform_spaces;
316         TransformOrientation *ts;
317         int i = V3D_MANIP_CUSTOM;
318         char *str_menu, *p;
319         
320         
321         str_menu = MEM_callocN(strlen(menu) + strlen(title) + 40 * BIF_countTransformOrientation(), "UserTransSpace from matrix");
322         p = str_menu;
323         
324         p += sprintf(str_menu, "%s", title);
325         p += sprintf(p, "%s", menu);
326         
327         for (ts = transform_spaces->first; ts; ts = ts->next) {
328                 p += sprintf(p, "|%s%%x%d", ts->name, i++);
329         }
330         
331         return str_menu;
332 }
333
334 int BIF_countTransformOrientation() {
335         ListBase *transform_spaces = &G.scene->transform_spaces;
336         TransformOrientation *ts;
337         int count = 0;
338
339         for (ts = transform_spaces->first; ts; ts = ts->next) {
340                 count++;
341         }
342         
343         return count;
344 }
345
346 void applyTransformOrientation() {
347         TransInfo *t = BIF_GetTransInfo();
348         TransformOrientation *ts;
349         int selected_index = (G.vd->twmode - V3D_MANIP_CUSTOM);
350         int i;
351         
352         if (selected_index >= 0) {
353                 for (i = 0, ts = G.scene->transform_spaces.first; ts; ts = ts->next, i++) {
354                         if (selected_index == i) {
355                                 strcpy(t->spacename, ts->name);
356                                 Mat3CpyMat3(t->spacemtx, ts->mat);
357                                 Mat4CpyMat3(G.vd->twmat, ts->mat);
358                                 break;
359                         }
360                 }
361         }
362 }
363
364
365 int getTransformOrientation(float normal[3], float plane[3], int activeOnly)
366 {
367         Base *base;
368         Object *ob = OBACT;
369         int result = ORIENTATION_NONE;
370
371         normal[0] = normal[1] = normal[2] = 0;
372         plane[0] = plane[1] = plane[2] = 0;
373
374         if(G.obedit)
375         {
376                 ob= G.obedit;
377
378                 if(G.obedit->type==OB_MESH)
379                 {
380                         EditMesh *em = G.editMesh;
381                         EditVert *eve;
382                         EditSelection ese;
383                         float vec[3]= {0,0,0};
384                         
385                         /* USE LAST SELECTED WITH ACTIVE */
386                         if (activeOnly && EM_get_actSelection(&ese))
387                         {
388                                 EM_editselection_normal(normal, &ese);
389                                 EM_editselection_plane(plane, &ese);
390                                 
391                                 switch (ese.type)
392                                 {
393                                         case EDITVERT:
394                                                 result = ORIENTATION_VERT;
395                                                 break;
396                                         case EDITEDGE:
397                                                 result = ORIENTATION_EDGE;
398                                                 break;
399                                         case EDITFACE:
400                                                 result = ORIENTATION_FACE;
401                                                 break;
402                                 }
403                         }
404                         else
405                         {
406                                 if (G.totfacesel >= 1)
407                                 {
408                                         EditFace *efa;
409                                         
410                                         for(efa= em->faces.first; efa; efa= efa->next)
411                                         {
412                                                 if(efa->f & SELECT)
413                                                 {
414                                                         VECADD(normal, normal, efa->n);
415                                                         VecSubf(vec, efa->v2->co, efa->v1->co);
416                                                         VECADD(plane, plane, vec);
417                                                 }
418                                         }
419                                         
420                                         result = ORIENTATION_FACE;
421                                 }
422                                 else if (G.totvertsel == 3)
423                                 {
424                                         EditVert *v1 = NULL, *v2 = NULL, *v3 = NULL;
425                                         float cotangent[3];
426                                         
427                                         for (eve = em->verts.first; eve; eve = eve->next)
428                                         {
429                                                 if ( eve->f & SELECT ) {
430                                                         if (v1 == NULL) {
431                                                                 v1 = eve; 
432                                                         }
433                                                         else if (v2 == NULL) {
434                                                                 v2 = eve;
435                                                         }
436                                                         else {
437                                                                 v3 = eve;
438
439                                                                 VecSubf(plane, v2->co, v1->co);
440                                                                 VecSubf(cotangent, v3->co, v2->co);
441                                                                 Crossf(normal, cotangent, plane);
442                                                                 break;
443                                                         }
444                                                 }
445                                         }
446
447                                         /* if there's an edge available, use that for the tangent */
448                                         if (G.totedgesel >= 1)
449                                         {
450                                                 EditEdge *eed = NULL;
451         
452                                                 for(eed= em->edges.first; eed; eed= eed->next) {
453                                                         if(eed->f & SELECT) {
454                                                                 VecSubf(plane, eed->v2->co, eed->v1->co);
455                                                                 break;
456                                                         }
457                                                 }
458                                         }
459
460                                         result = ORIENTATION_FACE;
461                                 }
462                                 else if (G.totedgesel == 1)
463                                 {
464                                         EditEdge *eed;
465
466                                         for(eed= em->edges.first; eed; eed= eed->next) {
467                                                 if(eed->f & SELECT) {
468                                                         /* use average vert normals as plane and edge vector as normal */
469                                                         VECCOPY(plane, eed->v1->no);
470                                                         VECADD(plane, plane, eed->v2->no);
471                                                         VecSubf(normal, eed->v2->co, eed->v1->co);
472                                                         break;
473                                                 }
474                                         }
475                                         result = ORIENTATION_EDGE;
476                                 }
477                                 else if (G.totvertsel == 2)
478                                 {
479                                         EditVert *v1 = NULL, *v2 = NULL;
480                 
481                                         for (eve = em->verts.first; eve; eve = eve->next)
482                                         {
483                                                 if ( eve->f & SELECT ) {
484                                                         if (v1 == NULL) {
485                                                                 v1 = eve; 
486                                                         }
487                                                         else {
488                                                                 v2 = eve;
489                                                                 
490                                                                 VECCOPY(plane, v1->no);
491                                                                 VECADD(plane, plane, v2->no);
492                                                                 VecSubf(normal, v2->co, v1->co);
493                                                                 break; 
494                                                         }
495                                                 }
496                                         }
497                                         result = ORIENTATION_EDGE;
498                                 }
499                                 else if (G.totvertsel == 1)
500                                 {
501                                         for (eve = em->verts.first; eve; eve = eve->next)
502                                         {
503                                                 if ( eve->f & SELECT ) {
504                                                         VECCOPY(normal, eve->no);
505                                                         break;
506                                                 }
507                                         }
508                                         result = ORIENTATION_VERT;
509                                 }
510                                 else if (G.totvertsel > 3)
511                                 {
512                                         normal[0] = normal[1] = normal[2] = 0;
513                                         
514                                         for (eve = em->verts.first; eve; eve = eve->next)
515                                         {
516                                                 if ( eve->f & SELECT ) {
517                                                         VecAddf(normal, normal, eve->no);
518                                                 }
519                                         }
520                                         Normalize(normal);
521                                         result = ORIENTATION_VERT;
522                                 }
523                         }
524                 } /* end editmesh */
525                 else if ELEM3(G.obedit->type, OB_CURVE, OB_SURF, OB_FONT)
526                 {
527                         extern ListBase editNurb; /* BOOO! go away stupid extern */
528                         Nurb *nu;
529                         BezTriple *bezt;
530                         int a;
531                         
532                         for (nu = editNurb.first; nu; nu = nu->next)
533                         {
534                                 /* only bezier has a normal */
535                                 if((nu->type & 7) == CU_BEZIER)
536                                 {
537                                         bezt= nu->bezt;
538                                         a= nu->pntsu;
539                                         while(a--)
540                                         {
541                                                 /* exception */
542                                                 if ( (bezt->f1 & SELECT) + (bezt->f2 & SELECT) + (bezt->f3 & SELECT) > SELECT )
543                                                 {
544                                                         VecSubf(normal, bezt->vec[0], bezt->vec[2]);
545                                                 }
546                                                 else
547                                                 {
548                                                         if(bezt->f1)
549                                                         {
550                                                                 VecSubf(normal, bezt->vec[0], bezt->vec[1]);
551                                                         }
552                                                         if(bezt->f2)
553                                                         {
554                                                                 VecSubf(normal, bezt->vec[0], bezt->vec[2]);
555                                                         }
556                                                         if(bezt->f3)
557                                                         {
558                                                                 VecSubf(normal, bezt->vec[1], bezt->vec[2]);
559                                                         }
560                                                 }
561                                                 bezt++;
562                                         }
563                                 }
564                         }
565                         
566                         if (normal[0] != 0 || normal[1] != 0 || normal[2] != 0)
567                         {
568                                 result = ORIENTATION_NORMAL;
569                         }
570                 }
571                 else if(G.obedit->type==OB_MBALL)
572                 {
573                         /* editmball.c */
574                         extern ListBase editelems;  /* go away ! */
575                         MetaElem *ml, *ml_sel = NULL;
576         
577                         /* loop and check that only one element is selected */  
578                         for (ml = editelems.first; ml; ml = ml->next)
579                         {
580                                 if (ml->flag & SELECT) {
581                                         if (ml_sel == NULL)
582                                         {
583                                                 ml_sel = ml;
584                                         }
585                                         else
586                                         {
587                                                 ml_sel = NULL;
588                                                 break;
589                                         }
590                                 }
591                         }
592                         
593                         if (ml_sel)
594                         {       
595                                 float mat[4][4];
596
597                                 /* Rotation of MetaElem is stored in quat */
598                                 QuatToMat4(ml_sel->quat, mat);
599
600                                 VECCOPY(normal, mat[2]);
601                                 VECCOPY(plane, mat[1]);
602
603                                 VecMulf(plane, -1.0);
604                                 
605                                 result = ORIENTATION_NORMAL;
606                         }
607                 }
608                 
609                 Mat4Mul3Vecfl(G.obedit->obmat, plane);
610                 Mat4Mul3Vecfl(G.obedit->obmat, normal);
611         }
612         else if(ob && (ob->flag & OB_POSEMODE))
613         {
614         }
615         else if(G.f & (G_VERTEXPAINT + G_TEXTUREPAINT + G_WEIGHTPAINT + G_SCULPTMODE))
616         {
617         }
618         else if(G.f & G_PARTICLEEDIT)
619         {
620         }
621         else {
622                 /* we need the one selected object, if its not active */
623                 ob = OBACT;
624                 if(ob && !(ob->flag & SELECT)) ob = NULL;
625                 
626                 for(base= G.scene->base.first; base; base= base->next) {
627                         if TESTBASELIB(base) {
628                                 if(ob == NULL) { 
629                                         ob= base->object;
630                                         break;
631                                 }
632                         }
633                 }
634                 
635                 VECCOPY(normal, ob->obmat[2]);
636                 VECCOPY(plane, ob->obmat[1]);
637                 result = ORIENTATION_NORMAL;
638         }
639         
640         return result;
641 }