1 #include "MEM_guardedalloc.h"
3 #include "BKE_utildefines.h"
6 #include "BLI_arithb.h"
11 note: this is a pattern-based edge subdivider.
12 it tries to match a pattern to edge selections on faces.
13 it was a fairly easy exercise to test the bmesh api; it
14 doesn't support multicuts, so it won't actually be used.
16 the patterns are defined as followed:
18 the patterns are defined for the state of the face after
19 initial splitting. each edge that was split is flagged, as is
20 the new resulting edge.
22 subdpattern pattern = {
23 //boolean flags for if an edge should have been split or not
25 //connection values for verts,
27 //second stage split flags, splits newly created edges
29 //second stage connection values for verts, connects stuff again.
31 4 //len of face before second stage splits, but after initial edge splits
35 typedef struct subdpattern {
36 int seledges[20]; //selected edges mask, for splitting
37 int connectverts[20]; //verts to connect;
39 int secondstage_splitedges[20];
40 //verts to connect afterwards. size must be len + number
41 //of edges split in secondstage_splitedges
42 int secondstage_connect[20];
44 int len; /*total number of verts*/
47 /*generic subdivision rules:
49 * two selected edges in a face should make a link
52 * one edge should do, what? make pretty topology, or just
56 /*note: the patterns are rotated as necassary to
57 match the input geometry. they're also based on the
58 post-splitted state of the faces. note that
59 second stage splitted stuff doesn't count
69 handle case of one edge selected.
72 subdpattern t_1edge = {
76 {-1, -1, -1, -1, -1, -1, -1, -1, -1},
88 handle case of two edges selected.
90 subdpattern t_2edge = {
94 {-1, -1, -1, -1, -1, -1, -1, -1, -1},
106 handle case of one edge selected.
107 make an edge between v1 and v5,
108 v5 and v3, and v3 and v1
110 subdpattern t_3edge = {
112 {-1, 5, -1, 1, -1, 3}, //creates e6
114 {-1, -1, -1, -1, -1, -1, -1},
127 connect v1 to v4 and v3
130 subdpattern q_1edge = {
134 {-1, -1, -1, -1, -1, -1, -1, -1, -1},
150 subdpattern q_2adjedge = {
152 {-1, 3, -1, -1, -1, -1},
153 {0, 0, 0, 0, 0, 0, 1},
154 {-1, -1, -1, -1, -1, 6, -1, -1, -1},
171 subdpattern q_2opedge = {
173 {-1, 4, -1, -1, -1, -1},
175 {-1, -1, -1, -1, -1, -1, -1, -1, -1},
188 connect v1 to v5, v1 to v3, and v3 to v5
191 subdpattern q_3edge = {
192 {1, 1, 1, 1, 1, 1, 0},
193 {-1, 3, -1, 5, -1, 1, -1},
195 {-1, -1, -1, -1, -1, -1, -1, -1, -1},
208 connect v1 to v5, split edge, than connect
209 v3 and v7 to v8 (new vert from split)
212 subdpattern q_4edge = {
213 {1, 1, 1, 1, 1, 1, 1, 1},
214 {-1, 5, -1, -1, -1, -1, -1, -1},
215 {0, 0, 0, 0, 0, 0, 0, 0, 1},
216 {-1, -1, -1, 8, -1, -1, -1, 8, -1},
220 subdpattern *patterns[] = {
231 #define PLEN (sizeof(patterns) / sizeof(void*))
237 void esubdivide_exec(BMesh *bmesh, BMOperator *op)
240 BMEdge *edge, *nedge, *edges[MAX_FACE];
243 BMVert *v1, *verts[MAX_FACE], *lastv;
246 int i, j, matched, a, b, newlen, newvlen;
248 BMO_Flag_Buffer(bmesh, op, BMOP_ESUBDIVIDE_EDGES, SUBD_SPLIT);
250 einput = BMO_GetSlot(op, BMOP_ESUBDIVIDE_EDGES);
252 /*first go through and split edges*/
253 for (i=0; i<einput->len; i++) {
254 edge = ((BMEdge**)einput->data.p)[i];
255 v1 = BM_Split_Edge(bmesh, edge->v1, edge, &nedge, 0.5, 1);
256 BMO_SetFlag(bmesh, v1, SUBD_SPLIT);
257 BMO_SetFlag(bmesh, nedge, SUBD_SPLIT);
260 /*now go through all the faces and connect the new geometry*/
261 for (face = BMIter_New(&fiter, bmesh, BM_FACES, NULL); face; face=BMIter_Step(&fiter)) {
263 if (BMO_TestFlag(bmesh, face, FACE_NEW)) continue;
265 if (face->len < MAX_FACE) {
266 /*try all possible pattern rotations*/
267 for (i=0; i<PLEN; i++) {
268 if (patterns[i]->len != face->len) continue;
270 for (j=0; j<patterns[i]->len; j++) {
271 for (a=0, loop=BMIter_New(&eiter, bmesh, BM_LOOPS_OF_FACE,face); loop; a++, loop=BMIter_Step(&eiter)) {
272 b = (j + a) % patterns[i]->len;
277 if (!(patterns[i]->seledges[b] == BMO_TestFlag(bmesh, edge, SUBD_SPLIT))) break;
282 if (a == face->len) {
295 for (i=0; i<pat->len; i++) {
296 if (pat->connectverts[i] != -1) {
297 edges[newlen++] = BM_Connect_Verts(bmesh, verts[i], verts[pat->connectverts[i]], &nf);
298 BMO_SetFlag(bmesh, nf, FACE_NEW);
304 for (i; i<newlen; i++) {
305 if (pat->secondstage_splitedges[i]) {
306 v1 = BM_Split_Edge(bmesh, edges[i]->v1, edges[i], &nedge, 0.5, 1);
307 verts[newvlen++] = v1;
311 for (i=0; i<newvlen; i++) {
312 if (pat->secondstage_connect[i] != -1) {
313 edges[newlen++] = BM_Connect_Verts(bmesh, verts[i], verts[pat->secondstage_connect[i]], &nf);
314 BMO_SetFlag(bmesh, nf, FACE_NEW);
317 } else { /*no match in the pattern*/
318 /*this should do some sort of generic subdivision*/