1 #include "MEM_guardedalloc.h"
3 #include "BKE_utildefines.h"
5 #include "BLI_arithb.h"
8 #include "DNA_object_types.h"
13 #include "mesh_intern.h"
24 /*stuff for the flag paramter. note that
25 what used to live in "beauty" and
26 in "seltype" live here. still have to
27 convert the beauty flags over, which
28 is why it starts at 128 (to avoid
30 #define SELTYPE_INNER 128
34 NOTE: beauty has been renamed to flag!
38 note: this is a pattern-based edge subdivider.
39 it tries to match a pattern to edge selections on faces,
40 then executes functions to cut them.
42 typedef struct subdpattern {
43 int seledges[20]; //selected edges mask, for splitting
45 /*verts starts at the first new vert cut, not the first vert in the
47 void (*connectexec)(BMesh *bm, BMFace *face, BMVert **verts,
48 int numcuts, int flag, float rad);
49 int len; /*total number of verts*/
52 /*generic subdivision rules:
54 * two selected edges in a face should make a link
57 * one edge should do, what? make pretty topology, or just
61 /* calculates offset for co, based on fractal, sphere or smooth settings */
62 static void alter_co(float *co, BMEdge *edge, float rad, int flag, float perc,
63 BMVert *vsta, BMVert *vend)
68 /* we calculate an offset vector vec1[], to be added to *co */
69 float len, fac, nor[3], nor1[3], nor2[3];
71 VecSubf(nor, vsta->co, vend->co);
72 len= 0.5f*Normalize(nor);
74 VECCOPY(nor1, vsta->no);
75 VECCOPY(nor2, vend->no);
78 fac= nor[0]*nor1[0] + nor[1]*nor1[1] + nor[2]*nor1[2] ;
85 fac= -nor[0]*nor2[0] - nor[1]*nor2[1] - nor[2]*nor2[2] ;
87 vec1[0]+= fac*nor2[0];
88 vec1[1]+= fac*nor2[1];
89 vec1[2]+= fac*nor2[2];
100 if(rad > 0.0) { /* subdivide sphere */
106 else if(rad< 0.0) { /* fractal subdivide */
107 fac= rad* VecLenf(vsta->co, vend->co);
108 vec1[0]= fac*(float)(0.5-BLI_drand());
109 vec1[1]= fac*(float)(0.5-BLI_drand());
110 vec1[2]= fac*(float)(0.5-BLI_drand());
111 VecAddf(co, co, vec1);
117 /* assumes in the edge is the correct interpolated vertices already */
118 /* percent defines the interpolation, rad and flag are for special options */
119 /* results in new vertex with correct coordinate, vertex normal and weight group info */
120 static BMVert *bm_subdivide_edge_addvert(BMesh *bm, BMEdge *edge, float rad,
121 int flag, float percent, BMEdge **out,
122 BMVert *vsta, BMVert *vend)
127 ev = BM_Split_Edge(bm, edge->v1, edge, out, percent, 1);
128 if (flag & SELTYPE_INNER) BM_Select_Vert(bm, ev, 1);
130 /* offset for smooth or sphere or fractal */
131 alter_co(ev->co, edge, rad, flag, percent, vsta, vend);
134 /* clip if needed by mirror modifier */
136 if ( edge->v1->f2 & edge->v2->f2 & 1) {
139 if ( edge->v1->f2 & edge->v2->f2 & 2) {
142 if ( edge->v1->f2 & edge->v2->f2 & 4) {
151 static BMVert *subdivideedgenum(BMesh *bm, BMEdge *edge,
152 int curpoint, int totpoint, float rad,
153 int flag, BMEdge **newe,
154 BMVert *vsta, BMVert *vend)
159 if (flag & (B_PERCENTSUBD) && totpoint == 1)
160 /*I guess the idea is vertices store what
162 //percent=(float)(edge->tmp.l)/32768.0f;
163 percent= 1.0; //edge->tmp.fp;
165 percent= 1.0f/(float)(totpoint+1-curpoint);
171 VecSubf(co, edge->v2->co, edge->v1->co);
172 VecMulf(co, 1.0f/(float)(totpoint+1-curpoint));
173 VecAddf(co2, edge->v1->co, co);
175 ev= bm_subdivide_edge_addvert(bm, edge, rad, flag, percent,
178 /* VECCOPY(ev->co, co2);
184 static void bm_subdivide_multicut(BMesh *bm, BMEdge *edge, float rad,
185 int flag, int numcuts,
186 BMVert *vsta, BMVert *vend) {
187 BMEdge *eed = edge, *newe;
191 for(i=0;i<numcuts;i++) {
192 v = subdivideedgenum(bm, eed, i, numcuts, rad,
193 flag, &newe, vsta, vend);
194 BMO_SetFlag(bm, v, SUBD_SPLIT);
195 BMO_SetFlag(bm, eed, SUBD_SPLIT);
199 /*note: the patterns are rotated as necassary to
200 match the input geometry. they're based on the
201 pre-split state of the face*/
213 static void q_1edge_split(BMesh *bm, BMFace *face, BMVert **vlist, int numcuts,
214 int flag, float rad) {
218 /*if it's odd, the middle face is a quad, otherwise it's a triangle*/
219 if (numcuts % 2==0) {
221 for (i=0; i<numcuts; i++) {
222 if (i == numcuts/2) add -= 1;
223 BM_Connect_Verts(bm, vlist[i], vlist[numcuts+add],
228 for (i=0; i<numcuts; i++) {
229 BM_Connect_Verts(bm, vlist[i], vlist[numcuts+add],
231 if (i == numcuts/2) {
233 BM_Connect_Verts(bm, vlist[i],
242 subdpattern q_1edge = {
259 static void q_2edge_op_split(BMesh *bm, BMFace *face, BMVert **vlist,
260 int numcuts, int flag, float rad) {
264 for (i=0; i<numcuts; i++) {
265 BM_Connect_Verts(bm, vlist[i],vlist[(numcuts-i-1)+numcuts+2],
270 subdpattern q_2edge_op = {
285 static void q_2edge_split(BMesh *bm, BMFace *face, BMVert **vlist,
286 int numcuts, int flag, float rad) {
290 for (i=0; i<numcuts; i++) {
291 BM_Connect_Verts(bm, vlist[i], vlist[numcuts+(numcuts-i)],
294 BM_Connect_Verts(bm, vlist[numcuts*2+3], vlist[numcuts*2+1], &nf);
297 subdpattern q_2edge = {
313 static void q_3edge_split(BMesh *bm, BMFace *face, BMVert **vlist,
314 int numcuts, int flag, float rad) {
318 for (i=0; i<numcuts; i++) {
319 if (i == numcuts/2) {
320 if (numcuts % 2 != 0) {
321 BM_Connect_Verts(bm, vlist[numcuts-i-1+add],
322 vlist[i+numcuts+1], &nf);
326 BM_Connect_Verts(bm, vlist[numcuts-i-1+add],
327 vlist[i+numcuts+1], &nf);
330 for (i=0; i<numcuts/2+1; i++) {
331 BM_Connect_Verts(bm, vlist[i],vlist[(numcuts-i)+numcuts*2+1],
336 subdpattern q_3edge = {
347 first line | | last line
351 it goes from bottom up
353 static void q_4edge_split(BMesh *bm, BMFace *face, BMVert **vlist, int numcuts,
354 int flag, float rad) {
358 BMVert **lines = MEM_callocN(sizeof(BMVert*)*(numcuts+2)*(numcuts+2),
360 int i, j, a, b, s=numcuts+2, totv=numcuts*4+4;
362 /*build a 2-dimensional array of verts,
363 containing every vert (and all new ones)
367 for (i=0; i<numcuts+2; i++) {
368 lines[i] = vlist[numcuts*3+2+(numcuts-i+1)];
372 for (i=0; i<numcuts+2; i++) {
373 lines[(s-1)*s+i] = vlist[numcuts+i];
376 /*first and last members of middle lines*/
377 for (i=0; i<numcuts; i++) {
379 b = numcuts + 1 + numcuts + 1 + (numcuts - i - 1);
381 e = BM_Connect_Verts(bm, vlist[a], vlist[b], &nf);
382 if (flag & SELTYPE_INNER) {
383 BM_Select_Edge(bm, e, 1);
384 BM_Select_Face(bm, nf, 1);
387 v1 = lines[(i+1)*s] = vlist[a];
388 v2 = lines[(i+1)*s + s-1] = vlist[b];
390 for (a=0; a<numcuts; a++) {
391 v = subdivideedgenum(bm, e, a, numcuts, rad, flag, &ne,
393 if (flag & SELTYPE_INNER) {
394 BM_Select_Edge(bm, ne, 1);
396 lines[(i+1)*s+a+1] = v;
400 for (i=1; i<numcuts+2; i++) {
401 for (j=1; j<numcuts+1; j++) {
404 e = BM_Connect_Verts(bm, lines[a], lines[b], &nf);
405 if (flag & SELTYPE_INNER) {
406 BM_Select_Edge(bm, e, 1);
407 BM_Select_Face(bm, nf, 1);
424 static void t_1edge_split(BMesh *bm, BMFace *face, BMVert **vlist,
425 int numcuts, int flag, float rad) {
429 for (i=0; i<numcuts; i++) {
430 BM_Connect_Verts(bm, vlist[i], vlist[numcuts+1], &nf);
434 subdpattern t_1edge = {
449 static void t_2edge_split(BMesh *bm, BMFace *face, BMVert **vlist,
450 int numcuts, int flag, float rad) {
454 for (i=0; i<numcuts; i++) {
455 BM_Connect_Verts(bm, vlist[i], vlist[numcuts+numcuts-i], &nf);
459 subdpattern t_2edge = {
475 static void t_3edge_split(BMesh *bm, BMFace *face, BMVert **vlist,
476 int numcuts, int flag, float rad) {
483 /*number of verts in each line*/
484 lines = MEM_callocN(sizeof(void*)*(numcuts+2), "triangle vert table");
486 lines[0] = (BMVert**) stackarr;
487 lines[0][0] = vlist[numcuts*2+1];
489 lines[1+numcuts] = MEM_callocN(sizeof(void*)*(numcuts+2),
490 "triangle vert table 2");
491 for (i=0; i<numcuts; i++) {
492 lines[1+numcuts][1+i] = vlist[i];
494 lines[1+numcuts][0] = vlist[numcuts*3+2];
495 lines[1+numcuts][1+numcuts] = vlist[numcuts];
497 for (i=0; i<numcuts; i++) {
498 lines[i+1] = MEM_callocN(sizeof(void*)*(2+i),
499 "triangle vert table row");
500 a = numcuts*2 + 2 + i;
501 b = numcuts + numcuts - i;
502 e = BM_Connect_Verts(bm, vlist[a], vlist[b], &nf);
504 if (flag & SELTYPE_INNER) {
505 BM_Select_Edge(bm, e, 1);
506 BM_Select_Face(bm, nf, 1);
509 lines[i+1][0] = vlist[a];
510 lines[i+1][1+i] = vlist[b];
512 for (j=0; j<i; j++) {
513 v = subdivideedgenum(bm, e, j, i, rad, flag, &ne,
517 if (flag & SELTYPE_INNER) {
518 BM_Select_Edge(bm, ne, 1);
533 for (i=1; i<numcuts+1; i++) {
534 for (j=0; j<i; j++) {
535 e= BM_Connect_Verts(bm, lines[i][j], lines[i+1][j+1],
537 if (flag & SELTYPE_INNER) {
538 BM_Select_Edge(bm, e, 1);
539 BM_Select_Face(bm, nf, 1);
542 e= BM_Connect_Verts(bm,lines[i][j+1],lines[i+1][j+1],
544 if (flag & SELTYPE_INNER) {
545 BM_Select_Edge(bm, e, 1);
546 BM_Select_Face(bm, nf, 1);
551 for (i=1; i<numcuts+2; i++) {
558 subdpattern t_3edge = {
565 subdpattern q_4edge = {
571 subdpattern *patterns[] = {
582 #define PLEN (sizeof(patterns) / sizeof(void*))
584 typedef struct subd_facedata {
585 BMVert *start; subdpattern *pat;
588 void esubdivide_exec(BMesh *bmesh, BMOperator *op)
591 BMEdge *edge, **edges = NULL;
595 BMVert **verts = NULL;
600 int i, j, matched, a, b, numcuts, flag, selaction;
601 subd_facedata *facedata = NULL;
604 BMO_Flag_Buffer(bmesh, op, BMOP_ESUBDIVIDE_EDGES, SUBD_SPLIT);
606 numcuts = BMO_GetSlot(op, BMOP_ESUBDIVIDE_NUMCUTS)->data.i;
607 flag = BMO_GetSlot(op, BMOP_ESUBDIVIDE_FLAG)->data.i;
608 rad = BMO_GetSlot(op, BMOP_ESUBDIVIDE_RADIUS)->data.f;
610 selaction = BMO_GetSlot(op, BMOP_ESUBDIVIDE_SELACTION)->data.i;
611 if (selaction == SUBDIV_SELECT_INNER) flag |= SELTYPE_INNER;
613 einput = BMO_GetSlot(op, BMOP_ESUBDIVIDE_EDGES);
615 /*first go through and split edges*/
616 for (i=0; i<einput->len; i++) {
617 edge = ((BMEdge**)einput->data.p)[i];
618 BMO_SetFlag(bmesh, edge, SUBD_SPLIT);
621 for (face=BMIter_New(&fiter, bmesh, BM_FACES, NULL);
622 face; face=BMIter_Step(&fiter)) {
623 /*figure out which pattern to use*/
627 for (nl=BMIter_New(&liter, bmesh, BM_LOOPS_OF_FACE, face);
628 nl; nl=BMIter_Step(&liter)) {
636 for (i=0; i<PLEN; i++) {
638 if (pat->len == face->len) {
639 for (a=0; a<pat->len; a++) {
641 for (b=0; b<pat->len; b++) {
642 j = (b + a) % pat->len;
643 if ((!!BMO_TestFlag(bmesh, edges[j], SUBD_SPLIT))
644 != (!!pat->seledges[b])) {
653 BMO_SetFlag(bmesh, face, SUBD_SPLIT);
654 j = V_COUNT(facedata) - 1;
655 facedata[j].pat = pat;
656 facedata[j].start = verts[a];
663 /*go through and split edges*/
664 for (i=0; i<einput->len; i++) {
665 edge = ((BMEdge**)einput->data.p)[i];
666 bm_subdivide_multicut(bmesh, edge, rad, flag, numcuts,
668 //BM_Split_Edge_Multi(bmesh, edge, numcuts);
671 //if (facedata) V_FREE(facedata);
675 for (face=BMIter_New(&fiter, bmesh, BM_FACES, NULL);
676 face; face=BMIter_Step(&fiter)) {
677 /*figure out which pattern to use*/
679 if (BMO_TestFlag(bmesh, face, SUBD_SPLIT) == 0) continue;
681 pat = facedata[i].pat;
685 for (nl=BMIter_New(&liter, bmesh, BM_LOOPS_OF_FACE, face);
686 nl; nl=BMIter_Step(&liter)) {
687 if (nl->v == facedata[i].start) {
695 for (nl=BMIter_New(&liter, bmesh, BM_LOOPS_OF_FACE, face);
696 nl; nl=BMIter_Step(&liter)) {
697 b = (j-a+face->len) % face->len;
703 pat->connectexec(bmesh, face, verts, numcuts, flag, rad);
707 if (facedata) V_FREE(facedata);
708 if (edges) V_FREE(edges);
709 if (verts) V_FREE(verts);
712 /*editmesh-emulating function*/
713 void BM_esubdivideflag(Object *obedit, BMesh *bm, int selflag, float rad,
714 int flag, int numcuts, int seltype) {
717 BMO_Init_Op(&op, BMOP_ESUBDIVIDE);
719 BMO_Set_Int(&op, BMOP_ESUBDIVIDE_NUMCUTS, numcuts);
720 BMO_Set_Int(&op, BMOP_ESUBDIVIDE_FLAG, flag);
721 BMO_Set_Float(&op, BMOP_ESUBDIVIDE_RADIUS, rad);
722 BMO_Set_Int(&op, BMOP_ESUBDIVIDE_SELACTION, seltype);
723 BMO_HeaderFlag_To_Slot(bm, &op, BMOP_ESUBDIVIDE_EDGES, selflag, BM_EDGE);
725 BMO_Exec_Op(bm, &op);
726 BMO_Finish_Op(bm, &op);
729 void BM_esubdivideflag_conv(Object *obedit,EditMesh *em,int selflag, float rad,
730 int flag, int numcuts, int seltype) {
731 BMesh *bm = editmesh_to_bmesh(em);
734 BM_esubdivideflag(obedit, bm, selflag, rad, flag, numcuts, seltype);
735 em2 = bmesh_to_editmesh(bm);