1043ff1020c14f74507fb4a1aeb6be6b14d40e21
[blender.git] / source / blender / bmesh / operators / extrudeops.c
1 #include "MEM_guardedalloc.h"
2
3 #include "BKE_utildefines.h"
4
5 #include "BLI_ghash.h"
6 #include "BLI_memarena.h"
7 #include "BLI_blenlib.h"
8 #include "BLI_arithb.h"
9
10 #include "bmesh.h"
11 #include "bmesh_operators_private.h"
12
13 #include <math.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17
18 #define EXT_INPUT       1
19 #define EXT_KEEP        2
20 #define EXT_DEL         4
21
22 void bmesh_extrude_face_indiv_exec(BMesh *bm, BMOperator *op)
23 {
24         BMOIter siter;
25         BMIter liter, liter2;
26         BMFace *f, *f2, *f3;
27         BMLoop *l, *l2, *l3, *l4;
28         BMEdge **edges = NULL, *e, *laste;
29         BMVert *v, *lastv, *firstv;
30         V_DECLARE(edges);
31         int i;
32
33         BMO_ITER(f, &siter, bm, op, "faces", BM_FACE) {
34                 V_RESET(edges);
35                 i = 0;
36                 firstv = lastv = NULL;
37                 BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
38                         V_GROW(edges);
39
40                         v = BM_Make_Vert(bm, l->v->co, NULL);
41                         BM_Copy_Attributes(bm, bm, l->v, v);
42
43                         if (lastv) {
44                                 e = BM_Make_Edge(bm, lastv, v, l->e, 0);
45                                 edges[i++] = e;
46                         }
47
48                         lastv = v;
49                         laste = l->e;
50                         if (!firstv) firstv = v;
51                 }
52
53                 V_GROW(edges);
54                 e = BM_Make_Edge(bm, v, firstv, laste, 0);
55                 edges[i++] = e;
56
57                 BMO_SetFlag(bm, f, EXT_DEL);
58
59                 f2 = BM_Make_Ngon(bm, edges[0]->v1, edges[0]->v2, edges, f->len, 0);
60                 BMO_SetFlag(bm, f2, EXT_KEEP);
61                 BM_Copy_Attributes(bm, bm, f, f2);
62
63                 l2 = BMIter_New(&liter2, bm, BM_LOOPS_OF_FACE, f2);
64                 BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
65                         BM_Copy_Attributes(bm, bm, l, l2);
66                         l3 = l->head.next;
67                         l4 = l2->head.next;
68
69                         f3 = BM_Make_QuadTri(bm, l3->v, l4->v, l2->v, l->v, f, 0);
70                         
71                         BM_Copy_Attributes(bm, bm, l->head.next, f3->loopbase);
72                         BM_Copy_Attributes(bm, bm, l->head.next, f3->loopbase->head.next);
73                         BM_Copy_Attributes(bm, bm, l, f3->loopbase->head.next->next);
74                         BM_Copy_Attributes(bm, bm, l, f3->loopbase->head.next->next->next);
75
76                         l2 = BMIter_Step(&liter2);
77                 }
78         }
79
80         BMO_CallOpf(bm, "del geom=%ff context=%d", EXT_DEL, DEL_ONLYFACES);
81
82         BMO_Flag_To_Slot(bm, op, "faceout", EXT_KEEP, BM_FACE);
83 }
84
85 void bmesh_extrude_onlyedge_exec(BMesh *bm, BMOperator *op)
86 {
87         BMOIter siter;
88         BMOperator dupeop;
89         BMVert *v1, *v2, *v3, *v4;
90         BMEdge *e, *e2;
91         BMFace *f;
92         
93         BMO_ITER(e, &siter, bm, op, "edges", BM_EDGE) {
94                 BMO_SetFlag(bm, e, EXT_INPUT);
95                 BMO_SetFlag(bm, e->v1, EXT_INPUT);
96                 BMO_SetFlag(bm, e->v2, EXT_INPUT);
97         }
98
99         BMO_InitOpf(bm, &dupeop, "dupe geom=%fve", EXT_INPUT);
100         BMO_Exec_Op(bm, &dupeop);
101
102         e = BMO_IterNew(&siter, bm, &dupeop, "boundarymap", 0);
103         for (; e; e=BMO_IterStep(&siter)) {
104                 e2 = BMO_IterMapVal(&siter);
105                 e2 = *(BMEdge**)e2;
106
107                 if (e->loop && e->v1 != e->loop->v) {
108                         v1 = e->v1;
109                         v2 = e->v2;
110                         v3 = e2->v2;
111                         v4 = e2->v1;
112                 } else {
113                         v1 = e2->v1;
114                         v2 = e2->v2;
115                         v3 = e->v2;
116                         v4 = e->v1;
117                 }
118                         /*not sure what to do about example face, pass   NULL for now.*/
119                 f = BM_Make_QuadTri(bm, v1, v2, v3, v4, NULL, 0);               
120                 
121                 if (BMO_TestFlag(bm, e, EXT_INPUT))
122                         e = e2;
123                 
124                 BMO_SetFlag(bm, f, EXT_KEEP);
125                 BMO_SetFlag(bm, e, EXT_KEEP);
126                 BMO_SetFlag(bm, e->v1, EXT_KEEP);
127                 BMO_SetFlag(bm, e->v2, EXT_KEEP);
128                 
129         }
130
131         BMO_Finish_Op(bm, &dupeop);
132
133         BMO_Flag_To_Slot(bm, op, "geomout", EXT_KEEP, BM_ALL);
134 }
135
136 void extrude_vert_indiv_exec(BMesh *bm, BMOperator *op)
137 {
138         BMOIter siter;
139         BMVert *v, *dupev;
140         BMEdge *e;
141
142         v = BMO_IterNew(&siter, bm, op, "verts", BM_VERT);
143         for (; v; v=BMO_IterStep(&siter)) {
144                 dupev = BM_Make_Vert(bm, v->co, NULL);
145                 VECCOPY(dupev->no, v->no);
146                 BM_Copy_Attributes(bm, bm, v, dupev);
147
148                 e = BM_Make_Edge(bm, v, dupev, NULL, 0);
149
150                 BMO_SetFlag(bm, e, EXT_KEEP);
151                 BMO_SetFlag(bm, dupev, EXT_KEEP);
152         }
153
154         BMO_Flag_To_Slot(bm, op, "vertout", EXT_KEEP, BM_VERT);
155         BMO_Flag_To_Slot(bm, op, "edgeout", EXT_KEEP, BM_EDGE);
156 }
157
158 void extrude_edge_context_exec(BMesh *bm, BMOperator *op)
159 {
160         BMOperator dupeop, delop;
161         BMOIter siter;
162         BMIter iter, fiter, viter;
163         BMEdge *e, *newedge, *e2, *ce;
164         BMLoop *l, *l2;
165         BMVert *verts[4], *v, *v2;
166         BMFace *f;
167         int rlen, found, delorig=0, i;
168
169         /*initialize our sub-operators*/
170         BMO_Init_Op(&dupeop, "dupe");
171         
172         BMO_Flag_Buffer(bm, op, "edgefacein", EXT_INPUT, BM_EDGE|BM_FACE);
173         
174         /*if one flagged face is bordered by an unflagged face, then we delete
175           original geometry.*/
176         BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
177                 if (!BMO_TestFlag(bm, e, EXT_INPUT)) continue;
178
179                 found = 0;
180                 f = BMIter_New(&fiter, bm, BM_FACES_OF_EDGE, e);
181                 for (rlen=0; f; f=BMIter_Step(&fiter), rlen++) {
182                         if (!BMO_TestFlag(bm, f, EXT_INPUT)) {
183                                 found = 1;
184                                 delorig = 1;
185                                 break;
186                         }
187                 }
188                 
189                 if (!found && (rlen > 1)) BMO_SetFlag(bm, e, EXT_DEL);
190         }
191
192         /*calculate verts to delete*/
193         BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
194                 found = 0;
195
196                 BM_ITER(e, &viter, bm, BM_EDGES_OF_VERT, v) {
197                         if (!BMO_TestFlag(bm, e, EXT_INPUT)) {
198                                 found = 1;
199                                 break;
200                         }
201                 }
202                 
203                 BM_ITER(f, &viter, bm, BM_FACES_OF_VERT, v) {
204                         if (!BMO_TestFlag(bm, f, EXT_INPUT)) {
205                                 found = 1;
206                                 break;
207                         }
208                 }
209
210                 if (!found) {
211                         BMO_SetFlag(bm, v, EXT_DEL);
212                 }
213         }
214         
215         BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
216                 if (BMO_TestFlag(bm, f, EXT_INPUT))
217                         BMO_SetFlag(bm, f, EXT_DEL);
218         }
219         if (delorig) BMO_InitOpf(bm, &delop, "del geom=%fvef context=%d", 
220                                  EXT_DEL, DEL_ONLYTAGGED);
221
222         BMO_CopySlot(op, &dupeop, "edgefacein", "geom");
223         BMO_Exec_Op(bm, &dupeop);
224
225         if (bm->act_face && BMO_TestFlag(bm, bm->act_face, EXT_INPUT))
226                 bm->act_face = BMO_Get_MapPointer(bm, &dupeop, "facemap", bm->act_face);
227
228         if (delorig) BMO_Exec_Op(bm, &delop);
229         
230         /*if not delorig, reverse loops of original faces*/
231         if (!delorig) {
232                 for (f=BMIter_New(&iter, bm, BM_FACES_OF_MESH, NULL); f; f=BMIter_Step(&iter)) {
233                         if (BMO_TestFlag(bm, f, EXT_INPUT)) {
234                                 BM_flip_normal(bm, f);
235                         }
236                 }
237         }
238         
239         BMO_CopySlot(&dupeop, op, "newout", "geomout");
240         e = BMO_IterNew(&siter, bm, &dupeop, "boundarymap", 0);
241         for (; e; e=BMO_IterStep(&siter)) {
242                 if (BMO_InMap(bm, op, "exclude", e)) continue;
243
244                 newedge = BMO_IterMapVal(&siter);
245                 newedge = *(BMEdge**)newedge;
246                 if (!newedge) continue;
247                 if (!newedge->loop) ce = e;
248                 else ce = newedge;
249                 
250                 if (ce->loop && (ce->loop->v == ce->v1)) {
251                         verts[0] = e->v1;
252                         verts[1] = e->v2;
253                         verts[2] = newedge->v2;
254                         verts[3] = newedge->v1;
255                 } else {
256                         verts[3] = e->v1;
257                         verts[2] = e->v2;
258                         verts[1] = newedge->v2;
259                         verts[0] = newedge->v1;
260                 }
261
262                 /*not sure what to do about example face, pass NULL for now.*/
263                 f = BM_Make_Quadtriangle(bm, verts, NULL, 4, NULL, 0);          
264
265                 /*copy attributes*/
266                 l=BMIter_New(&iter, bm, BM_LOOPS_OF_FACE, f);
267                 for (; l; l=BMIter_Step(&iter)) {
268                         if (l->e != e && l->e != newedge) continue;
269                         l2 = l->radial.next->data;
270                         
271                         if (l2 == l) {
272                                 l2 = newedge->loop;
273                                 BM_Copy_Attributes(bm, bm, l2->f, l->f);
274
275                                 BM_Copy_Attributes(bm, bm, l2, l);
276                                 l2 = (BMLoop*) l2->head.next;
277                                 l = (BMLoop*) l->head.next;
278                                 BM_Copy_Attributes(bm, bm, l2, l);
279                         } else {
280                                 BM_Copy_Attributes(bm, bm, l2->f, l->f);
281
282                                 /*copy data*/
283                                 if (l2->v == l->v) {
284                                         BM_Copy_Attributes(bm, bm, l2, l);
285                                         l2 = (BMLoop*) l2->head.next;
286                                         l = (BMLoop*) l->head.next;
287                                         BM_Copy_Attributes(bm, bm, l2, l);
288                                 } else {
289                                         l2 = (BMLoop*) l2->head.next;
290                                         BM_Copy_Attributes(bm, bm, l2, l);
291                                         l2 = (BMLoop*) l2->head.prev;
292                                         l = (BMLoop*) l->head.next;
293                                         BM_Copy_Attributes(bm, bm, l2, l);
294                                 }
295                         }
296                 }
297         }
298
299         /*link isolated verts*/
300         v = BMO_IterNew(&siter, bm, &dupeop, "isovertmap", 0);
301         for (; v; v=BMO_IterStep(&siter)) {
302                 v2 = *((void**)BMO_IterMapVal(&siter));
303                 BM_Make_Edge(bm, v, v2, v->edge, 1);
304         }
305
306         /*cleanup*/
307         if (delorig) BMO_Finish_Op(bm, &delop);
308         BMO_Finish_Op(bm, &dupeop);
309 }