Begin port of edge subdivide (with multicut) to

bmesh.  Basic infrastructure is in place, and
subdivision patterns for quads are implemented. 
Properly handling of the (many) flags and options
related to edge subdivide isn't complete, but I've
made a good start.  

Goal is eventual 100% api compatibility with old
esubdivide function, with some of the uglier design
aspects refactored after some of the tools that rely
on them are redone.

Some notes: Customdata interpolation wasn't working
right.  I thought maybe the weights were off, so I
swapped them, which surprising made it work.  It's
still not completely identical to old edge
subdivide though.
This commit is contained in:
Joseph Eagar
2009-02-02 03:25:23 +00:00
parent a64260263e
commit a6156d2ad2
9 changed files with 546 additions and 253 deletions

View File

@@ -204,5 +204,34 @@
#define SET_INT_IN_POINTER(i) ((void*)(intptr_t)(i))
#define GET_INT_FROM_POINTER(i) ((int)(intptr_t)(i))
/*little pointer array macro library. example of usage:
int *arr = NULL;
V_DECLARE(arr);
int i;
for (i=0; i<10; i++) {
V_GROW(arr);
arr[i] = something;
}
V_FREE(arr);
*/
#define V_DECLARE(vec) int _##vec##_count=0; void *_##vec##_tmp
#define V_SIZE(vec) ((vec)==NULL ? 0 : MEM_allocN_len(vec) / sizeof(*vec))
#define V_COUNT(vec) _##vec##_count
#define MSTR(s) #s
#define V_GROW(vec) \
V_SIZE(vec) > _##vec##_count ? _##vec##_count++ : \
((_##vec##_tmp = MEM_callocN(sizeof(*vec)*(_##vec##_count*2+2), #vec " " __FILE__ " ")),\
(vec && memcpy(_##vec##_tmp, vec, sizeof(*vec) * _##vec##_count)),\
(vec && (MEM_freeN(vec),1)),\
(vec = _##vec##_tmp),\
_##vec##_count++)
//(vec) ? WMEM_freeN(vec), 1 : 0
#define V_FREE(vec) if (vec) MEM_freeN(vec);
#define V_RESET(vec) _##vec##_count=0
#endif

View File

@@ -22,7 +22,7 @@ typedef struct BMOpSlot{
int len;
int index; /*index within slot array*/
union {
int i;
int i;
float f;
void *p;
float vec[3]; /*vector*/
@@ -52,7 +52,6 @@ typedef struct BMOpDefine {
/*BMOpDefine->flag*/
//doesn't do anything at the moment.
#define BMO_NOFLAGS 1
/*API for operators*/
void BMO_Init_Op(struct BMOperator *op, int opcode);
@@ -152,16 +151,31 @@ enum {
/*edge subdivide op*/
#define BMOP_ESUBDIVIDE 5
#define BMOP_ESUBDIVIDE_EDGES 0
#define BMOP_ESUBDIVIDE_TOTSLOT 1
enum {
BMOP_ESUBDIVIDE_EDGES,
BMOP_ESUBDIVIDE_NUMCUTS,
BMOP_ESUBDIVIDE_FLAG, //beauty flag in esubdivide
BMOP_ESUBDIVIDE_RADIUS,
BMOP_ESUBDIVIDE_SELACTION,
BMOP_ESUBDIVIDE_TOTSLOT,
};
/*
SUBDIV_SELECT_INNER
SUBDIV_SELECT_ORIG
SUBDIV_SELECT_INNER_SEL
SUBDIV_SELECT_LOOPCUT
DOUBLEOPFILL
*/
/*triangulate*/
#define BMOP_TRIANGULATE 6
#define BMOP_TRIANG_FACEIN 0
#define BMOP_TRIANG_NEW_EDGES 1
#define BMOP_TRIANG_NEW_FACES 2
#define BMOP_TRIANG_TOTSLOT 3
enum {
BMOP_TRIANG_FACEIN,
BMOP_TRIANG_NEW_EDGES,
BMOP_TRIANG_NEW_FACES,
BMOP_TRIANG_TOTSLOT,
};
/*dissolve faces*/
#define BMOP_DISSOLVE_FACES 7

View File

@@ -79,8 +79,8 @@ void BM_Data_Facevert_Edgeinterp(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v, B
float w[2];
BMLoop *l=NULL, *v1loop = NULL, *vloop = NULL, *v2loop = NULL;
w[0] = 1.0f - fac;
w[1] = fac;
w[1] = 1.0f - fac;
w[0] = fac;
if(!e1->loop) return;
l = e1->loop;

View File

@@ -39,7 +39,7 @@
* Returns -
* 1 for success, 0 for failure.
*/
#if 1
void BM_Dissolve_Disk(BMesh *bm, BMVert *v) {
BMFace *f, *f2;
BMEdge *e, *keepedge=NULL, *baseedge=NULL;
@@ -111,6 +111,38 @@ void BM_Dissolve_Disk(BMesh *bm, BMVert *v) {
BM_Join_Faces(bm, f, f2, NULL, 0, 0);
}
}
#else
void BM_Dissolve_Disk(BMesh *bm, BMVert *v){
BMFace *f;
BMEdge *e;
BMIter iter;
int done, len;
if(v->edge){
done = 0;
while(!done){
done = 1;
/*loop the edges looking for an edge to dissolve*/
for (e=BMIter_New(&iter, bm, BM_EDGES_OF_VERT, v); e;
e = BMIter_Step(&iter)) {
f = NULL;
len = bmesh_cycle_length(&(e->loop->radial));
if(len == 2){
f = BM_Join_Faces(bm,e->loop->f,((BMLoop*)
(e->loop->radial.next->data))->f,
e, 1, 0);
}
if(f){
done = 0;
break;
}
};
}
BM_Collapse_Vert(bm, v->edge, v, 1.0, 1);
}
}
#endif
/**
* bmesh_join_faces

View File

@@ -34,7 +34,11 @@ BMOpDefine def_triangop = {
};
BMOpDefine def_subdop = {
{BMOP_OPSLOT_PNT_BUF},
{BMOP_OPSLOT_PNT_BUF,
BMOP_OPSLOT_INT,
BMOP_OPSLOT_INT,
BMOP_OPSLOT_FLT,
BMOP_OPSLOT_INT},
esubdivide_exec,
BMOP_ESUBDIVIDE_TOTSLOT,
0

View File

@@ -80,9 +80,6 @@ void BMO_Init_Op(BMOperator *op, int opcode)
memset(op, 0, sizeof(BMOperator));
op->type = opcode;
//currently not used, flags are always allocated
op->needflag = !(opdefines[opcode]->flag & BMO_NOFLAGS);
/*initialize the operator slot types*/
for(i = 0; i < opdefines[opcode]->totslot; i++) {
op->slots[i].slottype = opdefines[opcode]->slottypes[i];

View File

@@ -2,45 +2,37 @@
#include "BKE_utildefines.h"
#include "bmesh.h"
#include "BLI_arithb.h"
#include "BLI_rand.h"
#include "DNA_object_types.h"
#include "ED_mesh.h"
#include "bmesh.h"
#include "mesh_intern.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#define SUBD_SPLIT 1
#define FACE_NEW 1
#define MAX_FACE 800
/*
note: this is a pattern-based edge subdivider.
it tries to match a pattern to edge selections on faces.
it was a fairly easy exercise to test the bmesh api; it
doesn't support multicuts, so it won't actually be used.
the patterns are defined as followed:
the patterns are defined for the state of the face after
initial splitting. each edge that was split is flagged, as is
the new resulting edge.
subdpattern pattern = {
//boolean flags for if an edge should have been split or not
{1, 0, 0, 0},
//connection values for verts,
{2, -1, -1, -1},
//second stage split flags, splits newly created edges
{0, 0, 0, 0, 1},
//second stage connection values for verts, connects stuff again.
{-1, -1, -1, -1, 3},
4 //len of face before second stage splits, but after initial edge splits
};
it tries to match a pattern to edge selections on faces,
then executes functions to cut them.
*/
typedef struct subdpattern {
int seledges[20]; //selected edges mask, for splitting
int connectverts[20]; //verts to connect;
int secondstage_splitedges[20];
//verts to connect afterwards. size must be len + number
//of edges split in secondstage_splitedges
int secondstage_connect[20];
/*verts starts at the first new vert cut, not the first vert in the
face*/
void (*connectexec)(BMesh *bm, BMFace *face, BMVert **verts,
int numcuts, int beauty, float rad);
int len; /*total number of verts*/
} subdpattern;
@@ -53,269 +45,485 @@ typedef struct subdpattern {
split the edge only?
*/
/* calculates offset for co, based on fractal, sphere or smooth settings */
static void alter_co(float *co, BMEdge *edge, float rad, int beauty, float perc)
{
float vec1[3], fac;
if(beauty & B_SMOOTH) {
/* we calculate an offset vector vec1[], to be added to *co */
float len, fac, nor[3], nor1[3], nor2[3];
VecSubf(nor, edge->v1->co, edge->v2->co);
len= 0.5f*Normalize(nor);
VECCOPY(nor1, edge->v1->no);
VECCOPY(nor2, edge->v2->no);
/* cosine angle */
fac= nor[0]*nor1[0] + nor[1]*nor1[1] + nor[2]*nor1[2] ;
vec1[0]= fac*nor1[0];
vec1[1]= fac*nor1[1];
vec1[2]= fac*nor1[2];
/* cosine angle */
fac= -nor[0]*nor2[0] - nor[1]*nor2[1] - nor[2]*nor2[2] ;
vec1[0]+= fac*nor2[0];
vec1[1]+= fac*nor2[1];
vec1[2]+= fac*nor2[2];
vec1[0]*= rad*len;
vec1[1]*= rad*len;
vec1[2]*= rad*len;
co[0] += vec1[0];
co[1] += vec1[1];
co[2] += vec1[2];
}
else {
if(rad > 0.0) { /* subdivide sphere */
Normalize(co);
co[0]*= rad;
co[1]*= rad;
co[2]*= rad;
}
else if(rad< 0.0) { /* fractal subdivide */
fac= rad* VecLenf(edge->v1->co, edge->v2->co);
vec1[0]= fac*(float)(0.5-BLI_drand());
vec1[1]= fac*(float)(0.5-BLI_drand());
vec1[2]= fac*(float)(0.5-BLI_drand());
VecAddf(co, co, vec1);
}
}
}
/* assumes in the edge is the correct interpolated vertices already */
/* percent defines the interpolation, rad and beauty are for special options */
/* results in new vertex with correct coordinate, vertex normal and weight group info */
static BMVert *bm_subdivide_edge_addvert(BMesh *bm, BMEdge *edge, float rad,
int beauty, float percent, BMEdge **out)
{
BMVert *ev;
// float co[3];
ev = BM_Split_Edge(bm, edge->v1, edge, out, percent, 1);
/* offset for smooth or sphere or fractal */
alter_co(ev->co, edge, rad, beauty, percent);
#if 0 //TODO
/* clip if needed by mirror modifier */
if (edge->v1->f2) {
if ( edge->v1->f2 & edge->v2->f2 & 1) {
co[0]= 0.0f;
}
if ( edge->v1->f2 & edge->v2->f2 & 2) {
co[1]= 0.0f;
}
if ( edge->v1->f2 & edge->v2->f2 & 4) {
co[2]= 0.0f;
}
}
#endif
return ev;
}
static BMVert *subdivideedgenum(BMesh *bm, BMEdge *edge,
int curpoint, int totpoint, float rad,
int beauty, BMEdge **newe)
{
BMVert *ev;
float percent;
if (beauty & (B_PERCENTSUBD) && totpoint == 1)
/*I guess the idea is vertices store what
percent to use?*/
//percent=(float)(edge->tmp.l)/32768.0f;
percent= 1.0; //edge->tmp.fp;
else {
percent= 1.0f/(float)(totpoint+1-curpoint);
}
/*{
float co[3], co2[3];
VecSubf(co, edge->v2->co, edge->v1->co);
VecMulf(co, 1.0f/(float)(totpoint+1-curpoint));
VecAddf(co2, edge->v1->co, co);
*/
ev= bm_subdivide_edge_addvert(bm, edge, rad, beauty, percent, newe);
/* VECCOPY(ev->co, co2);
}
*/
return ev;
}
static void bm_subdivide_multicut(BMesh *bm, BMEdge *edge, float rad,
int beauty, int numcuts) {
BMEdge *eed = edge, *newe;
BMVert *v;
int i;
for(i=0;i<numcuts;i++) {
v = subdivideedgenum(bm, eed, i, numcuts, rad, beauty, &newe);
BMO_SetFlag(bm, v, SUBD_SPLIT);
BMO_SetFlag(bm, eed, SUBD_SPLIT);
}
}
/*note: the patterns are rotated as necassary to
match the input geometry. they're also based on the
post-splitted state of the faces. note that
second stage splitted stuff doesn't count
for pattern->len!*/
match the input geometry. they're based on the
pre-split state of the face*/
/*
v2
/ \
v1 s_e1 e2
/e0 \
v0---e3----v3
handle case of one edge selected.
*/
subdpattern t_1edge = {
{1, 1, 0, 0},
{-1, 3, -1, -1},
{0},
{-1, -1, -1, -1, -1, -1, -1, -1, -1},
4
};
/*
v2
/ \e2
v1 e1 e3 v3
/e0 \
v0---e4----v4
handle case of two edges selected.
*/
subdpattern t_2edge = {
{1, 1, 1, 1, 0},
{-1, 3, -1, -1, -1},
{0},
{-1, -1, -1, -1, -1, -1, -1, -1, -1},
5
};
/*
v2
/ \e2
v1 e1 e3 v3
/e0 \
v0--e5--e4-v4
v5
handle case of one edge selected.
make an edge between v1 and v5,
v5 and v3, and v3 and v1
*/
subdpattern t_3edge = {
{1, 1, 1, 1, 1, 1},
{-1, 5, -1, 1, -1, 3}, //creates e6
{0},
{-1, -1, -1, -1, -1, -1, -1},
6
};
/*
e3
v4---------v3
v3---------v2
| |
|e4 | e2
| |
|e0 e1 |
v0---v1----v2
connect v1 to v4 and v3
| |
| |
v4---v0---v1
*/
static void q_1edge_split(BMesh *bm, BMFace *face, BMVert **vlist, int numcuts,
int beauty, float rad) {
BMFace *nf;
int i, add;
/*if it's odd, the middle face is a quad, otherwise it's a triangle*/
if (numcuts % 2==0) {
add = 2;
for (i=0; i<numcuts; i++) {
if (i == numcuts/2) add -= 1;
BM_Connect_Verts(bm, vlist[i], vlist[numcuts+add], &nf);
}
} else {
add = 2;
for (i=0; i<numcuts; i++) {
BM_Connect_Verts(bm, vlist[i], vlist[numcuts+add], &nf);
if (i == numcuts/2) {
add -= 1;
BM_Connect_Verts(bm, vlist[i], vlist[numcuts+add], &nf);
}
}
}
}
subdpattern q_1edge = {
{1, 1, 0, 0, 0},
{-1, 3, -1, -1, 1},
{0},
{-1, -1, -1, -1, -1, -1, -1, -1, -1},
5
{1, 0, 0, 0},
q_1edge_split,
4,
};
/*
e4
v5---------v4
v4---v3---v2
| s |
| |
|e5 | e3
| |v3
|e0 e1 | e2
v0---v1----v2
connect v1 to v3
*/
subdpattern q_2adjedge = {
{1, 1, 1, 1, 0, 0},
{-1, 3, -1, -1, -1, -1},
{0, 0, 0, 0, 0, 0, 1},
{-1, -1, -1, -1, -1, 6, -1, -1, -1},
6
};
/*
e4 v4 e3
v5---------v3
| |
|e5 |
| | e2
| e0 e1 |
v0---v1----v2
connect v1 to v4
| s |
v5---v0---v1
*/
subdpattern q_2opedge = {
{1, 1, 0, 1, 1, 0},
{-1, 4, -1, -1, -1, -1},
{0},
{-1, -1, -1, -1, -1, -1, -1, -1, -1},
6
static void q_2edge_op_split(BMesh *bm, BMFace *face, BMVert **vlist,
int numcuts, int beauty, float rad) {
BMFace *nf;
int i;
for (i=0; i<numcuts; i++) {
BM_Connect_Verts(bm, vlist[i], vlist[(numcuts-i-1)+numcuts+2], &nf);
}
}
subdpattern q_2edge_op = {
{1, 0, 1, 0},
q_2edge_op_split,
4,
};
/*
e5 v5 e4
v6---------v4
| |
|e6 | e3
| | v3
| e0 e1 | e2
v0---v1----v2
connect v1 to v5, v1 to v3, and v3 to v5
v6--------v5
| |
| |v4s
| |v3s
| s s |
v7-v0--v1-v2
*/
static void q_2edge_split(BMesh *bm, BMFace *face, BMVert **vlist,
int numcuts, int beauty, float rad) {
BMFace *nf;
int i;
for (i=0; i<numcuts; i++) {
BM_Connect_Verts(bm, vlist[i], vlist[numcuts+(numcuts-i)], &nf);
}
BM_Connect_Verts(bm, vlist[numcuts*2+3], vlist[numcuts*2+1], &nf);
}
subdpattern q_2edge = {
{1, 1, 0, 0},
q_2edge_split,
4,
};
/* s s
v8--v7--v6-v5
| |
| v4 s
| |
| v3 s
| s s |
v9-v0--v1-v2
*/
static void q_3edge_split(BMesh *bm, BMFace *face, BMVert **vlist,
int numcuts, int beauty, float rad) {
BMFace *nf;
int i, add=0;
for (i=0; i<numcuts; i++) {
if (i == numcuts/2) {
if (numcuts % 2 != 0) {
BM_Connect_Verts(bm, vlist[numcuts-i-1+add], vlist[i+numcuts+1], &nf);
}
add = numcuts*2+2;
}
BM_Connect_Verts(bm, vlist[numcuts-i-1+add], vlist[i+numcuts+1], &nf);
}
for (i=0; i<numcuts/2+1; i++) {
BM_Connect_Verts(bm, vlist[i], vlist[(numcuts-i)+numcuts*2+1], &nf);
}
}
subdpattern q_3edge = {
{1, 1, 1, 1, 1, 1, 0},
{-1, 3, -1, 5, -1, 1, -1},
{0},
{-1, -1, -1, -1, -1, -1, -1, -1, -1},
7
{1, 1, 1, 0},
q_3edge_split,
4,
};
/*
e5 v5 e4
v6---------v4
| |
|e6 | e3
|v7 | v3
|e7 e0 e1 | e2
v0---v1----v2
connect v1 to v5, split edge, than connect
v3 and v7 to v8 (new vert from split)
v8--v7-v6--v5
| s |
|v9 s s|v4
first line | | last line
|v10s s s|v3
v11-v0--v1-v2
it goes from bottom up
*/
static void q_4edge_split(BMesh *bm, BMFace *face, BMVert **vlist, int numcuts,
int beauty, float rad) {
BMFace *nf;
BMVert *v;
BMEdge *e, *ne;
BMVert **lines = MEM_callocN(sizeof(BMVert*)*(numcuts+2)*(numcuts+2),
"q_4edge_split");
int i, j, a, b, s=numcuts+2, totv=numcuts*4+4;
/*build a 2-dimensional array of verts,
containing every vert (and all new ones)
in the face.*/
/*first line*/
for (i=0; i<numcuts+2; i++) {
lines[i] = vlist[numcuts*3+2+(numcuts-i+1)];
}
/*last line*/
for (i=0; i<numcuts+2; i++) {
lines[(s-1)*s+i] = vlist[numcuts+i];
}
/*first and last members of middle lines*/
for (i=0; i<numcuts; i++) {
a = i;
b = numcuts + 1 + numcuts + 1 + (numcuts - i - 1);
e = BM_Connect_Verts(bm, vlist[a], vlist[b], &nf);
lines[(i+1)*s] = vlist[a];
lines[(i+1)*s + s-1] = vlist[b];
for (a=0; a<numcuts; a++) {
v = subdivideedgenum(bm, e, a, numcuts, rad, beauty, &ne);
lines[(i+1)*s+a+1] = v;
}
}
for (i=1; i<numcuts+2; i++) {
for (j=1; j<numcuts+1; j++) {
a = i*s + j;
b = (i-1)*s + j;
BM_Connect_Verts(bm, lines[a], lines[b], &nf);
}
}
/*
for (i=0; i<numcuts; i++) {
a = i;
b = numcuts + 1 + numcuts + 1 + (numcuts - i - 1);
BM_Connect_Verts(bm, vlist[a], vlist[b], &nf);
}*/
MEM_freeN(lines);
}
subdpattern q_4edge = {
{1, 1, 1, 1, 1, 1, 1, 1},
{-1, 5, -1, -1, -1, -1, -1, -1},
{0, 0, 0, 0, 0, 0, 0, 0, 1},
{-1, -1, -1, 8, -1, -1, -1, 8, -1},
8
{1, 1, 1, 1},
q_4edge_split,
4,
};
subdpattern *patterns[] = {
&t_1edge,
&t_2edge,
&t_3edge,
&q_1edge,
&q_2adjedge,
&q_2opedge,
&q_3edge,
&q_2edge_op,
&q_4edge,
&q_3edge,
&q_2edge,
};
#define PLEN (sizeof(patterns) / sizeof(void*))
#define SUBD_SPLIT 1
#define FACE_NEW 1
#define MAX_FACE 10
typedef struct subd_facedata {
BMVert *start; subdpattern *pat;
} subd_facedata;
void esubdivide_exec(BMesh *bmesh, BMOperator *op)
{
BMOpSlot *einput;
BMEdge *edge, *nedge, *edges[MAX_FACE];
BMFace *face, *nf;
BMLoop *nl, *loop;
BMVert *v1, *verts[MAX_FACE], *lastv;
BMIter fiter, eiter;
BMEdge *edge, *edges[MAX_FACE];
BMFace *face;
BMLoop *nl;
BMVert *verts[MAX_FACE];
BMIter fiter, liter;
subdpattern *pat;
int i, j, matched, a, b, newlen, newvlen;
float rad;
int i, j, matched, a, b, numcuts, flag, selaction;
subd_facedata *facedata = NULL;
V_DECLARE(facedata);
BMO_Flag_Buffer(bmesh, op, BMOP_ESUBDIVIDE_EDGES, SUBD_SPLIT);
numcuts = BMO_GetSlot(op, BMOP_ESUBDIVIDE_NUMCUTS)->data.i;
flag = BMO_GetSlot(op, BMOP_ESUBDIVIDE_FLAG)->data.i;
rad = BMO_GetSlot(op, BMOP_ESUBDIVIDE_RADIUS)->data.f;
selaction = BMO_GetSlot(op, BMOP_ESUBDIVIDE_SELACTION)->data.i;
einput = BMO_GetSlot(op, BMOP_ESUBDIVIDE_EDGES);
/*first go through and split edges*/
for (i=0; i<einput->len; i++) {
edge = ((BMEdge**)einput->data.p)[i];
v1 = BM_Split_Edge(bmesh, edge->v1, edge, &nedge, 0.5, 1);
BMO_SetFlag(bmesh, v1, SUBD_SPLIT);
BMO_SetFlag(bmesh, nedge, SUBD_SPLIT);
BMO_SetFlag(bmesh, edge, SUBD_SPLIT);
}
for (face=BMIter_New(&fiter, bmesh, BM_FACES, NULL);
face; face=BMIter_Step(&fiter)) {
/*figure out which pattern to use*/
if (face->len > MAX_FACE) continue;
/*now go through all the faces and connect the new geometry*/
for (face = BMIter_New(&fiter, bmesh, BM_FACES, NULL); face; face=BMIter_Step(&fiter)) {
matched = 0;
if (BMO_TestFlag(bmesh, face, FACE_NEW)) continue;
i = 0;
for (nl=BMIter_New(&liter, bmesh, BM_LOOPS_OF_FACE, face);
nl; nl=BMIter_Step(&liter)) {
edges[i] = nl->e;
verts[i] = nl->v;
i++;
}
if (face->len < MAX_FACE) {
/*try all possible pattern rotations*/
for (i=0; i<PLEN; i++) {
if (patterns[i]->len != face->len) continue;
lastv = NULL;
for (j=0; j<patterns[i]->len; j++) {
for (a=0, loop=BMIter_New(&eiter, bmesh, BM_LOOPS_OF_FACE,face); loop; a++, loop=BMIter_Step(&eiter)) {
b = (j + a) % patterns[i]->len;
edge = loop->e;
verts[b] = loop->v;
edges[b] = edge;
if (!(patterns[i]->seledges[b] == BMO_TestFlag(bmesh, edge, SUBD_SPLIT))) break;
lastv = verts[b];
}
if (a == face->len) {
matched = 1;
pat = patterns[i];
break;
for (i=0; i<PLEN; i++) {
pat = patterns[i];
if (pat->len == face->len) {
for (a=0; a<pat->len; a++) {
matched = 1;
for (b=0; b<pat->len; b++) {
j = (b + a) % pat->len;
if ((!!BMO_TestFlag(bmesh, edges[j], SUBD_SPLIT))
!= (!!pat->seledges[b])) {
matched = 0;
break;
}
}
if (matched) break;
}
}
if (matched) {
/*first stage*/
newlen = pat->len;
for (i=0; i<pat->len; i++) {
if (pat->connectverts[i] != -1) {
edges[newlen++] = BM_Connect_Verts(bmesh, verts[i], verts[pat->connectverts[i]], &nf);
BMO_SetFlag(bmesh, nf, FACE_NEW);
}
if (matched) {
V_GROW(facedata);
BMO_SetFlag(bmesh, face, SUBD_SPLIT);
j = V_COUNT(facedata) - 1;
facedata[j].pat = pat;
facedata[j].start = verts[a];
break;
}
}
newvlen = pat->len;
/*second stage*/
for (i; i<newlen; i++) {
if (pat->secondstage_splitedges[i]) {
v1 = BM_Split_Edge(bmesh, edges[i]->v1, edges[i], &nedge, 0.5, 1);
verts[newvlen++] = v1;
}
}
for (i=0; i<newvlen; i++) {
if (pat->secondstage_connect[i] != -1) {
edges[newlen++] = BM_Connect_Verts(bmesh, verts[i], verts[pat->secondstage_connect[i]], &nf);
BMO_SetFlag(bmesh, nf, FACE_NEW);
}
}
} else { /*no match in the pattern*/
/*this should do some sort of generic subdivision*/
}
}
}
/*go through and split edges*/
for (i=0; i<einput->len; i++) {
edge = ((BMEdge**)einput->data.p)[i];
bm_subdivide_multicut(bmesh, edge, rad, flag, numcuts);
//BM_Split_Edge_Multi(bmesh, edge, numcuts);
}
//if (facedata) V_FREE(facedata);
//return;
i = 0;
for (face=BMIter_New(&fiter, bmesh, BM_FACES, NULL);
face; face=BMIter_Step(&fiter)) {
/*figure out which pattern to use*/
if (face->len > MAX_FACE) continue;
if (BMO_TestFlag(bmesh, face, SUBD_SPLIT) == 0) continue;
pat = facedata[i].pat;
if (!pat) continue;
j = a = 0;
for (nl=BMIter_New(&liter, bmesh, BM_LOOPS_OF_FACE, face);
nl; nl=BMIter_Step(&liter)) {
if (nl->v == facedata[i].start) {
a = j+1;
break;
}
j++;
}
j = 0;
for (nl=BMIter_New(&liter, bmesh, BM_LOOPS_OF_FACE, face);
nl; nl=BMIter_Step(&liter)) {
b = (j-a+face->len) % face->len;
verts[b] = nl->v;
j += 1;
}
pat->connectexec(bmesh, face, verts, numcuts, flag, rad);
i++;
}
if (facedata) V_FREE(facedata);
}
/*editmesh-emulating function*/
void BM_esubdivideflag(Object *obedit, BMesh *bm, int flag, float rad,
int beauty, int numcuts, int seltype) {
BMOperator op;
BMO_Init_Op(&op, BMOP_ESUBDIVIDE);
BMO_Set_Int(&op, BMOP_ESUBDIVIDE_NUMCUTS, numcuts);
BMO_Set_Int(&op, BMOP_ESUBDIVIDE_FLAG, beauty);
BMO_Set_Float(&op, BMOP_ESUBDIVIDE_RADIUS, rad);
BMO_Set_Int(&op, BMOP_ESUBDIVIDE_SELACTION, seltype);
BMO_HeaderFlag_To_Slot(bm, &op, BMOP_ESUBDIVIDE_EDGES, flag, BM_EDGE);
BMO_Exec_Op(bm, &op);
BMO_Finish_Op(bm, &op);
}

View File

@@ -3301,7 +3301,11 @@ static int bmesh_test_exec(bContext *C, wmOperator *op)
bm = editmesh_to_bmesh(em);
#if 1
#if 1 /*edge subdivide test*/
BM_esubdivideflag(obedit, bm, SELECT, 0, 0, G.rt==0?1:G.rt, 0);
#endif
#if 0
/*dissolve vert test*/
{
BMOperator op;

View File

@@ -32,6 +32,11 @@
#ifndef MESH_INTERN_H
#define MESH_INTERN_H
#include "BLI_editVert.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
#include "DNA_mesh_types.h"
struct bContext;
struct wmOperatorType;
struct ViewContext;