2009-01-07 15:17:58 +00:00
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
|
|
|
|
|
#include "BKE_utildefines.h"
|
|
|
|
|
|
|
|
|
|
#include "BLI_arithb.h"
|
2009-02-02 03:25:23 +00:00
|
|
|
#include "BLI_rand.h"
|
2009-02-08 14:25:04 +00:00
|
|
|
#include "BLI_ghash.h"
|
2009-01-07 15:17:58 +00:00
|
|
|
|
2009-02-02 03:25:23 +00:00
|
|
|
#include "DNA_object_types.h"
|
2009-01-07 15:17:58 +00:00
|
|
|
|
2009-02-02 03:25:23 +00:00
|
|
|
#include "ED_mesh.h"
|
2009-01-07 15:17:58 +00:00
|
|
|
|
2009-02-02 03:25:23 +00:00
|
|
|
#include "bmesh.h"
|
|
|
|
|
#include "mesh_intern.h"
|
2009-02-08 14:25:04 +00:00
|
|
|
#include "subdivideop.h"
|
2009-01-07 15:17:58 +00:00
|
|
|
|
2009-02-02 03:25:23 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <math.h>
|
2009-01-07 15:17:58 +00:00
|
|
|
|
2009-02-09 07:08:35 +00:00
|
|
|
/*flags for all elements share a common bitfield space*/
|
2009-02-02 03:25:23 +00:00
|
|
|
#define SUBD_SPLIT 1
|
2009-02-08 14:25:04 +00:00
|
|
|
|
2009-02-08 17:01:28 +00:00
|
|
|
#define EDGE_PERCENT 2
|
|
|
|
|
|
2009-02-08 14:25:04 +00:00
|
|
|
/*I don't think new faces are flagged, currently, but
|
|
|
|
|
better safe than sorry.*/
|
2009-02-09 07:08:35 +00:00
|
|
|
#define FACE_NEW 4
|
|
|
|
|
#define FACE_CUSTOMFILL 8
|
|
|
|
|
#define ELE_INNER 16
|
|
|
|
|
#define ELE_SPLIT 32
|
|
|
|
|
#define ELE_CONNECT 64
|
2009-01-07 15:17:58 +00:00
|
|
|
|
2009-02-08 11:53:14 +00:00
|
|
|
/*stuff for the flag paramter. note that
|
|
|
|
|
what used to live in "beauty" and
|
|
|
|
|
in "seltype" live here. still have to
|
|
|
|
|
convert the beauty flags over, which
|
|
|
|
|
is why it starts at 128 (to avoid
|
|
|
|
|
collision).*/
|
|
|
|
|
#define SELTYPE_INNER 128
|
|
|
|
|
|
2009-02-03 06:22:30 +00:00
|
|
|
/*
|
|
|
|
|
NOTE: beauty has been renamed to flag!
|
|
|
|
|
*/
|
|
|
|
|
|
2009-01-07 15:17:58 +00:00
|
|
|
/*generic subdivision rules:
|
|
|
|
|
|
|
|
|
|
* two selected edges in a face should make a link
|
|
|
|
|
between them.
|
|
|
|
|
|
|
|
|
|
* one edge should do, what? make pretty topology, or just
|
|
|
|
|
split the edge only?
|
|
|
|
|
*/
|
|
|
|
|
|
2009-03-13 13:11:50 +00:00
|
|
|
/*connects face with smallest len, which I think should always be correct for
|
|
|
|
|
edge subdivision*/
|
|
|
|
|
BMEdge *connect_smallest_face(BMesh *bm, BMVert *v1, BMVert *v2, BMFace **nf) {
|
|
|
|
|
BMIter iter, iter2;
|
|
|
|
|
BMVert *v;
|
|
|
|
|
BMLoop *nl;
|
|
|
|
|
BMFace *face, *curf = NULL;
|
|
|
|
|
|
|
|
|
|
/*this isn't the best thing in the world. it doesn't handle cases where there's
|
|
|
|
|
multiple faces yet. that might require a convexity test to figure out which
|
|
|
|
|
face is "best," and who knows what for non-manifold conditions.*/
|
|
|
|
|
for (face = BMIter_New(&iter, bm, BM_FACES_OF_VERT, v1); face; face=BMIter_Step(&iter)) {
|
|
|
|
|
for (v=BMIter_New(&iter2, bm, BM_VERTS_OF_FACE, face); v; v=BMIter_Step(&iter2)) {
|
|
|
|
|
if (v == v2) {
|
|
|
|
|
if (!curf || face->len < curf->len) curf = face;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (curf) {
|
|
|
|
|
face = BM_Split_Face(bm, curf, v1, v2, &nl, NULL);
|
|
|
|
|
|
|
|
|
|
if (nf) *nf = face;
|
|
|
|
|
return nl ? nl->e : NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2009-02-02 03:25:23 +00:00
|
|
|
/* calculates offset for co, based on fractal, sphere or smooth settings */
|
2009-02-08 17:01:28 +00:00
|
|
|
static void alter_co(float *co, BMEdge *edge, subdparams *params, float perc,
|
2009-02-03 06:22:30 +00:00
|
|
|
BMVert *vsta, BMVert *vend)
|
2009-02-02 03:25:23 +00:00
|
|
|
{
|
|
|
|
|
float vec1[3], fac;
|
|
|
|
|
|
2009-02-08 17:01:28 +00:00
|
|
|
if(params->flag & B_SMOOTH) {
|
2009-02-02 03:25:23 +00:00
|
|
|
/* we calculate an offset vector vec1[], to be added to *co */
|
|
|
|
|
float len, fac, nor[3], nor1[3], nor2[3];
|
|
|
|
|
|
2009-02-03 06:22:30 +00:00
|
|
|
VecSubf(nor, vsta->co, vend->co);
|
2009-02-02 03:25:23 +00:00
|
|
|
len= 0.5f*Normalize(nor);
|
|
|
|
|
|
2009-02-03 06:22:30 +00:00
|
|
|
VECCOPY(nor1, vsta->no);
|
|
|
|
|
VECCOPY(nor2, vend->no);
|
2009-02-02 03:25:23 +00:00
|
|
|
|
|
|
|
|
/* 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];
|
|
|
|
|
|
2009-02-08 17:01:28 +00:00
|
|
|
vec1[0]*= params->rad*len;
|
|
|
|
|
vec1[1]*= params->rad*len;
|
|
|
|
|
vec1[2]*= params->rad*len;
|
2009-02-02 03:25:23 +00:00
|
|
|
|
|
|
|
|
co[0] += vec1[0];
|
|
|
|
|
co[1] += vec1[1];
|
|
|
|
|
co[2] += vec1[2];
|
|
|
|
|
}
|
|
|
|
|
else {
|
2009-02-08 17:01:28 +00:00
|
|
|
if(params->rad > 0.0) { /* subdivide sphere */
|
2009-02-02 03:25:23 +00:00
|
|
|
Normalize(co);
|
2009-02-08 17:01:28 +00:00
|
|
|
co[0]*= params->rad;
|
|
|
|
|
co[1]*= params->rad;
|
|
|
|
|
co[2]*= params->rad;
|
2009-02-02 03:25:23 +00:00
|
|
|
}
|
2009-02-08 17:01:28 +00:00
|
|
|
else if(params->rad< 0.0) { /* fractal subdivide */
|
|
|
|
|
fac= params->rad* VecLenf(vsta->co, vend->co);
|
2009-02-02 03:25:23 +00:00
|
|
|
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);
|
|
|
|
|
}
|
2009-01-07 15:17:58 +00:00
|
|
|
|
2009-02-02 03:25:23 +00:00
|
|
|
}
|
|
|
|
|
}
|
2009-01-07 15:17:58 +00:00
|
|
|
|
2009-02-02 03:25:23 +00:00
|
|
|
/* assumes in the edge is the correct interpolated vertices already */
|
2009-02-03 06:22:30 +00:00
|
|
|
/* percent defines the interpolation, rad and flag are for special options */
|
2009-02-02 03:25:23 +00:00
|
|
|
/* results in new vertex with correct coordinate, vertex normal and weight group info */
|
2009-03-16 14:15:18 +00:00
|
|
|
static BMVert *bm_subdivide_edge_addvert(BMesh *bm, BMEdge *edge,BMEdge *oedge,
|
|
|
|
|
subdparams *params, float percent,
|
|
|
|
|
float percent2,
|
2009-02-08 17:01:28 +00:00
|
|
|
BMEdge **out,BMVert *vsta,BMVert *vend)
|
2009-02-02 03:25:23 +00:00
|
|
|
{
|
|
|
|
|
BMVert *ev;
|
|
|
|
|
// float co[3];
|
|
|
|
|
|
2009-03-13 13:11:50 +00:00
|
|
|
ev = BM_Split_Edge(bm, edge->v1, edge, out, percent);
|
2009-03-16 14:15:18 +00:00
|
|
|
BM_Vert_UpdateNormal(bm, ev);
|
|
|
|
|
|
2009-02-09 07:08:35 +00:00
|
|
|
BMO_SetFlag(bm, ev, ELE_INNER);
|
2009-01-07 15:17:58 +00:00
|
|
|
|
2009-02-02 03:25:23 +00:00
|
|
|
/* offset for smooth or sphere or fractal */
|
2009-03-16 14:15:18 +00:00
|
|
|
alter_co(ev->co, oedge, params, percent2, vsta, vend);
|
2009-01-07 15:17:58 +00:00
|
|
|
|
2009-02-02 03:25:23 +00:00
|
|
|
#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;
|
|
|
|
|
}
|
2009-01-07 15:17:58 +00:00
|
|
|
|
2009-03-16 14:15:18 +00:00
|
|
|
static BMVert *subdivideedgenum(BMesh *bm, BMEdge *edge, BMEdge *oedge,
|
2009-02-08 17:01:28 +00:00
|
|
|
int curpoint, int totpoint, subdparams *params,
|
|
|
|
|
BMEdge **newe, BMVert *vsta, BMVert *vend)
|
2009-02-02 03:25:23 +00:00
|
|
|
{
|
|
|
|
|
BMVert *ev;
|
2009-03-16 14:15:18 +00:00
|
|
|
float percent, percent2 = 0.0f;
|
2009-02-02 03:25:23 +00:00
|
|
|
|
2009-02-08 17:01:28 +00:00
|
|
|
if (BMO_TestFlag(bm, edge, EDGE_PERCENT) && totpoint == 1)
|
2009-02-09 06:36:59 +00:00
|
|
|
percent = BMO_Get_MapFloat(bm, params->op,
|
|
|
|
|
BMOP_ESUBDIVIDE_PERCENT_EDGEMAP, edge);
|
2009-02-02 03:25:23 +00:00
|
|
|
else {
|
|
|
|
|
percent= 1.0f/(float)(totpoint+1-curpoint);
|
2009-03-16 14:15:18 +00:00
|
|
|
percent2 = (float)curpoint / (float)(totpoint + 1);
|
2009-01-07 15:17:58 +00:00
|
|
|
|
2009-02-02 03:25:23 +00:00
|
|
|
}
|
|
|
|
|
|
2009-03-16 14:15:18 +00:00
|
|
|
ev= bm_subdivide_edge_addvert(bm, edge, oedge, params, percent,
|
|
|
|
|
percent2, newe, vsta, vend);
|
2009-02-02 03:25:23 +00:00
|
|
|
return ev;
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-08 17:01:28 +00:00
|
|
|
static void bm_subdivide_multicut(BMesh *bm, BMEdge *edge, subdparams *params,
|
2009-02-03 06:22:30 +00:00
|
|
|
BMVert *vsta, BMVert *vend) {
|
2009-03-16 14:15:18 +00:00
|
|
|
BMEdge *eed = edge, *newe, temp = *edge;
|
2009-02-02 03:25:23 +00:00
|
|
|
BMVert *v;
|
2009-02-08 17:01:28 +00:00
|
|
|
int i, numcuts = params->numcuts;
|
2009-02-02 03:25:23 +00:00
|
|
|
|
|
|
|
|
for(i=0;i<numcuts;i++) {
|
2009-03-16 14:15:18 +00:00
|
|
|
v = subdivideedgenum(bm, eed, &temp, i, params->numcuts, params,
|
2009-02-08 17:01:28 +00:00
|
|
|
&newe, vsta, vend);
|
2009-02-02 03:25:23 +00:00
|
|
|
BMO_SetFlag(bm, v, SUBD_SPLIT);
|
|
|
|
|
BMO_SetFlag(bm, eed, SUBD_SPLIT);
|
2009-02-09 07:08:35 +00:00
|
|
|
|
|
|
|
|
BMO_SetFlag(bm, v, ELE_SPLIT);
|
|
|
|
|
BMO_SetFlag(bm, eed, ELE_SPLIT);
|
2009-02-02 03:25:23 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*note: the patterns are rotated as necassary to
|
|
|
|
|
match the input geometry. they're based on the
|
|
|
|
|
pre-split state of the face*/
|
2009-01-07 15:17:58 +00:00
|
|
|
|
|
|
|
|
/*
|
2009-02-02 03:25:23 +00:00
|
|
|
|
|
|
|
|
v3---------v2
|
2009-01-07 15:17:58 +00:00
|
|
|
| |
|
|
|
|
|
| |
|
2009-02-02 03:25:23 +00:00
|
|
|
| |
|
|
|
|
|
| |
|
|
|
|
|
v4---v0---v1
|
2009-01-07 15:17:58 +00:00
|
|
|
|
|
|
|
|
*/
|
2009-02-08 17:01:28 +00:00
|
|
|
static void q_1edge_split(BMesh *bm, BMFace *face,
|
|
|
|
|
BMVert **verts, subdparams *params) {
|
2009-02-02 03:25:23 +00:00
|
|
|
BMFace *nf;
|
2009-02-08 17:01:28 +00:00
|
|
|
int i, add, numcuts = params->numcuts;
|
2009-02-02 03:25:23 +00:00
|
|
|
|
|
|
|
|
/*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;
|
2009-03-13 13:11:50 +00:00
|
|
|
connect_smallest_face(bm, verts[i], verts[numcuts+add],
|
2009-02-08 11:53:14 +00:00
|
|
|
&nf);
|
2009-02-02 03:25:23 +00:00
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
add = 2;
|
|
|
|
|
for (i=0; i<numcuts; i++) {
|
2009-03-13 13:11:50 +00:00
|
|
|
connect_smallest_face(bm, verts[i], verts[numcuts+add],
|
2009-02-08 11:53:14 +00:00
|
|
|
&nf);
|
2009-02-02 03:25:23 +00:00
|
|
|
if (i == numcuts/2) {
|
|
|
|
|
add -= 1;
|
2009-03-13 13:11:50 +00:00
|
|
|
connect_smallest_face(bm, verts[i],
|
2009-02-08 17:01:28 +00:00
|
|
|
verts[numcuts+add],
|
2009-02-08 11:53:14 +00:00
|
|
|
&nf);
|
2009-02-02 03:25:23 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-07 15:17:58 +00:00
|
|
|
subdpattern q_1edge = {
|
2009-02-02 03:25:23 +00:00
|
|
|
{1, 0, 0, 0},
|
|
|
|
|
q_1edge_split,
|
|
|
|
|
4,
|
2009-01-07 15:17:58 +00:00
|
|
|
};
|
|
|
|
|
|
2009-02-02 03:25:23 +00:00
|
|
|
|
2009-01-07 15:17:58 +00:00
|
|
|
/*
|
2009-02-02 03:25:23 +00:00
|
|
|
|
|
|
|
|
v4---v3---v2
|
|
|
|
|
| s |
|
2009-01-07 15:17:58 +00:00
|
|
|
| |
|
2009-02-02 03:25:23 +00:00
|
|
|
| |
|
|
|
|
|
| s |
|
|
|
|
|
v5---v0---v1
|
2009-01-07 15:17:58 +00:00
|
|
|
|
|
|
|
|
*/
|
2009-02-08 14:25:04 +00:00
|
|
|
|
2009-02-08 17:01:28 +00:00
|
|
|
static void q_2edge_op_split(BMesh *bm, BMFace *face, BMVert **verts,
|
|
|
|
|
subdparams *params)
|
|
|
|
|
{
|
2009-02-02 03:25:23 +00:00
|
|
|
BMFace *nf;
|
2009-02-08 17:01:28 +00:00
|
|
|
int i, numcuts = params->numcuts;
|
2009-02-02 03:25:23 +00:00
|
|
|
|
|
|
|
|
for (i=0; i<numcuts; i++) {
|
2009-03-13 13:11:50 +00:00
|
|
|
connect_smallest_face(bm, verts[i],verts[(numcuts-i-1)+numcuts+2],
|
2009-02-08 11:53:14 +00:00
|
|
|
&nf);
|
2009-02-02 03:25:23 +00:00
|
|
|
}
|
|
|
|
|
}
|
2009-01-07 15:17:58 +00:00
|
|
|
|
2009-02-02 03:25:23 +00:00
|
|
|
subdpattern q_2edge_op = {
|
|
|
|
|
{1, 0, 1, 0},
|
|
|
|
|
q_2edge_op_split,
|
|
|
|
|
4,
|
|
|
|
|
};
|
2009-01-07 15:17:58 +00:00
|
|
|
|
|
|
|
|
/*
|
2009-02-02 03:25:23 +00:00
|
|
|
v6--------v5
|
2009-01-07 15:17:58 +00:00
|
|
|
| |
|
2009-02-02 03:25:23 +00:00
|
|
|
| |v4s
|
|
|
|
|
| |v3s
|
|
|
|
|
| s s |
|
|
|
|
|
v7-v0--v1-v2
|
2009-01-07 15:17:58 +00:00
|
|
|
|
|
|
|
|
*/
|
2009-02-08 17:01:28 +00:00
|
|
|
static void q_2edge_split(BMesh *bm, BMFace *face, BMVert **verts,
|
|
|
|
|
subdparams *params)
|
|
|
|
|
{
|
2009-02-02 03:25:23 +00:00
|
|
|
BMFace *nf;
|
2009-02-08 17:01:28 +00:00
|
|
|
int i, numcuts = params->numcuts;
|
2009-02-02 03:25:23 +00:00
|
|
|
|
|
|
|
|
for (i=0; i<numcuts; i++) {
|
2009-03-13 13:11:50 +00:00
|
|
|
connect_smallest_face(bm, verts[i], verts[numcuts+(numcuts-i)],
|
2009-02-08 11:53:14 +00:00
|
|
|
&nf);
|
2009-02-02 03:25:23 +00:00
|
|
|
}
|
2009-03-13 13:11:50 +00:00
|
|
|
connect_smallest_face(bm, verts[numcuts*2+3], verts[numcuts*2+1], &nf);
|
2009-02-02 03:25:23 +00:00
|
|
|
}
|
2009-01-07 15:17:58 +00:00
|
|
|
|
2009-02-02 03:25:23 +00:00
|
|
|
subdpattern q_2edge = {
|
|
|
|
|
{1, 1, 0, 0},
|
|
|
|
|
q_2edge_split,
|
|
|
|
|
4,
|
|
|
|
|
};
|
2009-01-07 15:17:58 +00:00
|
|
|
|
2009-02-02 03:25:23 +00:00
|
|
|
/* s s
|
|
|
|
|
v8--v7--v6-v5
|
|
|
|
|
| |
|
|
|
|
|
| v4 s
|
|
|
|
|
| |
|
|
|
|
|
| v3 s
|
|
|
|
|
| s s |
|
|
|
|
|
v9-v0--v1-v2
|
2009-01-07 15:17:58 +00:00
|
|
|
|
|
|
|
|
*/
|
2009-02-08 17:01:28 +00:00
|
|
|
static void q_3edge_split(BMesh *bm, BMFace *face, BMVert **verts,
|
|
|
|
|
subdparams *params)
|
|
|
|
|
{
|
2009-02-02 03:25:23 +00:00
|
|
|
BMFace *nf;
|
2009-02-08 17:01:28 +00:00
|
|
|
int i, add=0, numcuts = params->numcuts;
|
2009-02-02 03:25:23 +00:00
|
|
|
|
|
|
|
|
for (i=0; i<numcuts; i++) {
|
|
|
|
|
if (i == numcuts/2) {
|
|
|
|
|
if (numcuts % 2 != 0) {
|
2009-03-13 13:11:50 +00:00
|
|
|
connect_smallest_face(bm, verts[numcuts-i-1+add],
|
2009-02-08 17:01:28 +00:00
|
|
|
verts[i+numcuts+1], &nf);
|
2009-02-02 03:25:23 +00:00
|
|
|
}
|
|
|
|
|
add = numcuts*2+2;
|
|
|
|
|
}
|
2009-03-13 13:11:50 +00:00
|
|
|
connect_smallest_face(bm, verts[numcuts-i-1+add],
|
2009-02-08 17:01:28 +00:00
|
|
|
verts[i+numcuts+1], &nf);
|
2009-02-02 03:25:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (i=0; i<numcuts/2+1; i++) {
|
2009-03-13 13:11:50 +00:00
|
|
|
connect_smallest_face(bm, verts[i],verts[(numcuts-i)+numcuts*2+1],
|
2009-02-08 11:53:14 +00:00
|
|
|
&nf);
|
2009-02-02 03:25:23 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-07 15:17:58 +00:00
|
|
|
subdpattern q_3edge = {
|
2009-02-02 03:25:23 +00:00
|
|
|
{1, 1, 1, 0},
|
|
|
|
|
q_3edge_split,
|
|
|
|
|
4,
|
2009-01-07 15:17:58 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*
|
2009-02-02 03:25:23 +00:00
|
|
|
|
|
|
|
|
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
|
|
|
|
|
*/
|
2009-02-08 17:01:28 +00:00
|
|
|
static void q_4edge_split(BMesh *bm, BMFace *face, BMVert **verts,
|
|
|
|
|
subdparams *params)
|
|
|
|
|
{
|
2009-02-02 03:25:23 +00:00
|
|
|
BMFace *nf;
|
2009-02-03 06:22:30 +00:00
|
|
|
BMVert *v, *v1, *v2;
|
2009-03-16 14:15:18 +00:00
|
|
|
BMEdge *e, *ne, temp;
|
2009-02-08 17:01:28 +00:00
|
|
|
BMVert **lines;
|
|
|
|
|
int numcuts = params->numcuts;
|
2009-02-02 03:25:23 +00:00
|
|
|
int i, j, a, b, s=numcuts+2, totv=numcuts*4+4;
|
|
|
|
|
|
2009-02-08 17:01:28 +00:00
|
|
|
lines = MEM_callocN(sizeof(BMVert*)*(numcuts+2)*(numcuts+2),
|
|
|
|
|
"q_4edge_split");
|
2009-02-02 03:25:23 +00:00
|
|
|
/*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++) {
|
2009-02-08 17:01:28 +00:00
|
|
|
lines[i] = verts[numcuts*3+2+(numcuts-i+1)];
|
2009-02-02 03:25:23 +00:00
|
|
|
}
|
2009-01-07 15:17:58 +00:00
|
|
|
|
2009-02-02 03:25:23 +00:00
|
|
|
/*last line*/
|
|
|
|
|
for (i=0; i<numcuts+2; i++) {
|
2009-02-08 17:01:28 +00:00
|
|
|
lines[(s-1)*s+i] = verts[numcuts+i];
|
2009-02-02 03:25:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*first and last members of middle lines*/
|
|
|
|
|
for (i=0; i<numcuts; i++) {
|
|
|
|
|
a = i;
|
|
|
|
|
b = numcuts + 1 + numcuts + 1 + (numcuts - i - 1);
|
|
|
|
|
|
2009-03-13 13:11:50 +00:00
|
|
|
e = connect_smallest_face(bm, verts[a], verts[b], &nf);
|
|
|
|
|
if (!e) continue;
|
|
|
|
|
|
2009-02-09 07:08:35 +00:00
|
|
|
BMO_SetFlag(bm, e, ELE_INNER);
|
|
|
|
|
BMO_SetFlag(bm, nf, ELE_INNER);
|
|
|
|
|
|
2009-02-02 03:25:23 +00:00
|
|
|
|
2009-02-08 17:01:28 +00:00
|
|
|
v1 = lines[(i+1)*s] = verts[a];
|
|
|
|
|
v2 = lines[(i+1)*s + s-1] = verts[b];
|
2009-03-16 14:15:18 +00:00
|
|
|
|
|
|
|
|
temp = *e;
|
2009-02-02 03:25:23 +00:00
|
|
|
for (a=0; a<numcuts; a++) {
|
2009-03-16 14:15:18 +00:00
|
|
|
v = subdivideedgenum(bm, e, &temp, a, numcuts, params, &ne,
|
2009-02-03 06:22:30 +00:00
|
|
|
v1, v2);
|
2009-02-09 07:08:35 +00:00
|
|
|
BMO_SetFlag(bm, ne, ELE_INNER);
|
2009-02-02 03:25:23 +00:00
|
|
|
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;
|
2009-03-13 13:11:50 +00:00
|
|
|
e = connect_smallest_face(bm, lines[a], lines[b], &nf);
|
|
|
|
|
if (!e) continue;
|
|
|
|
|
|
2009-02-09 07:08:35 +00:00
|
|
|
BMO_SetFlag(bm, e, ELE_INNER);
|
|
|
|
|
BMO_SetFlag(bm, nf, ELE_INNER);
|
2009-02-02 03:25:23 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MEM_freeN(lines);
|
|
|
|
|
}
|
2009-01-07 15:17:58 +00:00
|
|
|
|
2009-02-08 08:52:25 +00:00
|
|
|
/* v3
|
|
|
|
|
/ \
|
|
|
|
|
/ \
|
|
|
|
|
/ \
|
|
|
|
|
/ \
|
|
|
|
|
/ \
|
|
|
|
|
v4--v0--v1--v2
|
|
|
|
|
s s
|
|
|
|
|
*/
|
2009-02-08 17:01:28 +00:00
|
|
|
static void t_1edge_split(BMesh *bm, BMFace *face, BMVert **verts,
|
|
|
|
|
subdparams *params)
|
|
|
|
|
{
|
2009-02-08 08:52:25 +00:00
|
|
|
BMFace *nf;
|
2009-02-08 17:01:28 +00:00
|
|
|
int i, numcuts = params->numcuts;
|
2009-02-08 08:52:25 +00:00
|
|
|
|
|
|
|
|
for (i=0; i<numcuts; i++) {
|
2009-03-13 13:11:50 +00:00
|
|
|
connect_smallest_face(bm, verts[i], verts[numcuts+1], &nf);
|
2009-02-08 08:52:25 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
subdpattern t_1edge = {
|
|
|
|
|
{1, 0, 0},
|
|
|
|
|
t_1edge_split,
|
|
|
|
|
3,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* v5
|
|
|
|
|
/ \
|
|
|
|
|
/ \ v4 s
|
|
|
|
|
/ \
|
|
|
|
|
/ \ v3 s
|
|
|
|
|
/ \
|
|
|
|
|
v6--v0--v1--v2
|
|
|
|
|
s s
|
|
|
|
|
*/
|
2009-02-08 17:01:28 +00:00
|
|
|
static void t_2edge_split(BMesh *bm, BMFace *face, BMVert **verts,
|
|
|
|
|
subdparams *params)
|
|
|
|
|
{
|
2009-02-08 08:52:25 +00:00
|
|
|
BMFace *nf;
|
2009-02-08 17:01:28 +00:00
|
|
|
int i, numcuts = params->numcuts;
|
2009-02-08 08:52:25 +00:00
|
|
|
|
|
|
|
|
for (i=0; i<numcuts; i++) {
|
2009-03-13 13:11:50 +00:00
|
|
|
connect_smallest_face(bm, verts[i], verts[numcuts+numcuts-i], &nf);
|
2009-02-08 08:52:25 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
subdpattern t_2edge = {
|
|
|
|
|
{1, 1, 0},
|
|
|
|
|
t_2edge_split,
|
|
|
|
|
3,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* v5
|
|
|
|
|
/ \
|
|
|
|
|
s v6/---\ v4 s
|
|
|
|
|
/ \ / \
|
|
|
|
|
sv7/---v---\ v3 s
|
|
|
|
|
/ \/ \/ \
|
|
|
|
|
v8--v0--v1--v2
|
|
|
|
|
s s
|
|
|
|
|
*/
|
2009-02-08 17:01:28 +00:00
|
|
|
static void t_3edge_split(BMesh *bm, BMFace *face, BMVert **verts,
|
|
|
|
|
subdparams *params)
|
|
|
|
|
{
|
2009-02-08 08:52:25 +00:00
|
|
|
BMFace *nf;
|
2009-03-16 14:15:18 +00:00
|
|
|
BMEdge *e, *ne, temp;
|
2009-02-08 08:52:25 +00:00
|
|
|
BMVert ***lines, *v;
|
|
|
|
|
void *stackarr[1];
|
2009-02-08 17:01:28 +00:00
|
|
|
int i, j, a, b, numcuts = params->numcuts;
|
2009-02-08 08:52:25 +00:00
|
|
|
|
|
|
|
|
/*number of verts in each line*/
|
|
|
|
|
lines = MEM_callocN(sizeof(void*)*(numcuts+2), "triangle vert table");
|
|
|
|
|
|
2009-02-08 11:53:14 +00:00
|
|
|
lines[0] = (BMVert**) stackarr;
|
2009-02-08 17:01:28 +00:00
|
|
|
lines[0][0] = verts[numcuts*2+1];
|
2009-02-08 08:52:25 +00:00
|
|
|
|
|
|
|
|
lines[1+numcuts] = MEM_callocN(sizeof(void*)*(numcuts+2),
|
|
|
|
|
"triangle vert table 2");
|
|
|
|
|
for (i=0; i<numcuts; i++) {
|
2009-02-08 17:01:28 +00:00
|
|
|
lines[1+numcuts][1+i] = verts[i];
|
2009-02-08 08:52:25 +00:00
|
|
|
}
|
2009-02-08 17:01:28 +00:00
|
|
|
lines[1+numcuts][0] = verts[numcuts*3+2];
|
|
|
|
|
lines[1+numcuts][1+numcuts] = verts[numcuts];
|
2009-02-08 08:52:25 +00:00
|
|
|
|
|
|
|
|
for (i=0; i<numcuts; i++) {
|
|
|
|
|
lines[i+1] = MEM_callocN(sizeof(void*)*(2+i),
|
|
|
|
|
"triangle vert table row");
|
|
|
|
|
a = numcuts*2 + 2 + i;
|
|
|
|
|
b = numcuts + numcuts - i;
|
2009-03-13 13:11:50 +00:00
|
|
|
e = connect_smallest_face(bm, verts[a], verts[b], &nf);
|
2009-03-09 15:15:17 +00:00
|
|
|
if (!e) goto cleanup;
|
|
|
|
|
|
2009-02-09 07:08:35 +00:00
|
|
|
BMO_SetFlag(bm, e, ELE_INNER);
|
|
|
|
|
BMO_SetFlag(bm, nf, ELE_INNER);
|
2009-02-08 08:52:25 +00:00
|
|
|
|
2009-02-08 17:01:28 +00:00
|
|
|
lines[i+1][0] = verts[a];
|
|
|
|
|
lines[i+1][1+i] = verts[b];
|
2009-03-16 14:15:18 +00:00
|
|
|
|
|
|
|
|
temp = *e;
|
2009-02-08 08:52:25 +00:00
|
|
|
for (j=0; j<i; j++) {
|
2009-03-16 14:15:18 +00:00
|
|
|
v = subdivideedgenum(bm, e, &temp, j, i, params, &ne,
|
2009-02-08 17:01:28 +00:00
|
|
|
verts[a], verts[b]);
|
2009-02-08 08:52:25 +00:00
|
|
|
lines[i+1][j+1] = v;
|
2009-02-08 11:53:14 +00:00
|
|
|
|
2009-02-09 07:08:35 +00:00
|
|
|
BMO_SetFlag(bm, ne, ELE_INNER);
|
2009-02-08 08:52:25 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* v5
|
|
|
|
|
/ \
|
|
|
|
|
s v6/---\ v4 s
|
|
|
|
|
/ \ / \
|
|
|
|
|
sv7/---v---\ v3 s
|
|
|
|
|
/ \/ \/ \
|
|
|
|
|
v8--v0--v1--v2
|
|
|
|
|
s s
|
|
|
|
|
*/
|
|
|
|
|
for (i=1; i<numcuts+1; i++) {
|
|
|
|
|
for (j=0; j<i; j++) {
|
2009-03-13 13:11:50 +00:00
|
|
|
e= connect_smallest_face(bm, lines[i][j], lines[i+1][j+1],
|
2009-02-08 11:53:14 +00:00
|
|
|
&nf);
|
2009-02-09 07:08:35 +00:00
|
|
|
|
|
|
|
|
BMO_SetFlag(bm, e, ELE_INNER);
|
|
|
|
|
BMO_SetFlag(bm, nf, ELE_INNER);
|
2009-02-08 11:53:14 +00:00
|
|
|
|
2009-03-13 13:11:50 +00:00
|
|
|
e= connect_smallest_face(bm,lines[i][j+1],lines[i+1][j+1],
|
2009-02-08 11:53:14 +00:00
|
|
|
&nf);
|
2009-02-09 07:08:35 +00:00
|
|
|
|
|
|
|
|
BMO_SetFlag(bm, e, ELE_INNER);
|
|
|
|
|
BMO_SetFlag(bm, nf, ELE_INNER);
|
2009-02-08 08:52:25 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-03-09 15:15:17 +00:00
|
|
|
cleanup:
|
2009-02-08 11:53:14 +00:00
|
|
|
for (i=1; i<numcuts+2; i++) {
|
2009-03-09 15:15:17 +00:00
|
|
|
if (lines[i]) MEM_freeN(lines[i]);
|
2009-02-08 08:52:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MEM_freeN(lines);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
subdpattern t_3edge = {
|
|
|
|
|
{1, 1, 1},
|
|
|
|
|
t_3edge_split,
|
|
|
|
|
3,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2009-01-07 15:17:58 +00:00
|
|
|
subdpattern q_4edge = {
|
2009-02-02 03:25:23 +00:00
|
|
|
{1, 1, 1, 1},
|
|
|
|
|
q_4edge_split,
|
|
|
|
|
4,
|
2009-01-07 15:17:58 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
subdpattern *patterns[] = {
|
|
|
|
|
&q_1edge,
|
2009-02-02 03:25:23 +00:00
|
|
|
&q_2edge_op,
|
2009-01-07 15:17:58 +00:00
|
|
|
&q_4edge,
|
2009-02-02 03:25:23 +00:00
|
|
|
&q_3edge,
|
|
|
|
|
&q_2edge,
|
2009-02-08 08:52:25 +00:00
|
|
|
&t_1edge,
|
|
|
|
|
&t_2edge,
|
|
|
|
|
&t_3edge,
|
2009-01-07 15:17:58 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#define PLEN (sizeof(patterns) / sizeof(void*))
|
|
|
|
|
|
2009-02-02 03:25:23 +00:00
|
|
|
typedef struct subd_facedata {
|
|
|
|
|
BMVert *start; subdpattern *pat;
|
|
|
|
|
} subd_facedata;
|
2009-01-07 15:17:58 +00:00
|
|
|
|
|
|
|
|
void esubdivide_exec(BMesh *bmesh, BMOperator *op)
|
|
|
|
|
{
|
2009-02-09 06:36:59 +00:00
|
|
|
BMOpSlot *einput;
|
2009-02-08 14:25:04 +00:00
|
|
|
BMEdge *edge, **edges = NULL;
|
2009-02-08 17:01:28 +00:00
|
|
|
V_DECLARE(edges);
|
2009-02-02 03:25:23 +00:00
|
|
|
BMFace *face;
|
|
|
|
|
BMLoop *nl;
|
2009-02-08 11:53:14 +00:00
|
|
|
BMVert **verts = NULL;
|
2009-02-08 17:01:28 +00:00
|
|
|
V_DECLARE(verts);
|
2009-02-02 03:25:23 +00:00
|
|
|
BMIter fiter, liter;
|
2009-01-07 15:17:58 +00:00
|
|
|
subdpattern *pat;
|
2009-02-08 17:01:28 +00:00
|
|
|
subdparams params;
|
2009-02-02 03:25:23 +00:00
|
|
|
subd_facedata *facedata = NULL;
|
2009-02-08 17:01:28 +00:00
|
|
|
V_DECLARE(facedata);
|
2009-02-08 14:25:04 +00:00
|
|
|
float rad;
|
2009-02-09 07:08:35 +00:00
|
|
|
int i, j, matched, a, b, numcuts, flag;
|
2009-01-07 15:17:58 +00:00
|
|
|
|
|
|
|
|
BMO_Flag_Buffer(bmesh, op, BMOP_ESUBDIVIDE_EDGES, SUBD_SPLIT);
|
2009-02-02 03:25:23 +00:00
|
|
|
|
|
|
|
|
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;
|
2009-02-08 11:53:14 +00:00
|
|
|
|
2009-01-07 15:17:58 +00:00
|
|
|
einput = BMO_GetSlot(op, BMOP_ESUBDIVIDE_EDGES);
|
2009-02-02 03:25:23 +00:00
|
|
|
|
2009-02-11 12:32:29 +00:00
|
|
|
/*first go through and tag edges*/
|
|
|
|
|
BMO_Flag_To_Slot(bmesh, op, BMOP_ESUBDIVIDE_EDGES,
|
|
|
|
|
SUBD_SPLIT, BM_EDGE);
|
|
|
|
|
|
2009-02-08 17:01:28 +00:00
|
|
|
params.flag = flag;
|
|
|
|
|
params.numcuts = numcuts;
|
2009-02-09 06:36:59 +00:00
|
|
|
params.op = op;
|
2009-02-08 17:01:28 +00:00
|
|
|
params.rad = rad;
|
|
|
|
|
|
2009-02-09 06:36:59 +00:00
|
|
|
BMO_Mapping_To_Flag(bmesh, op, BMOP_ESUBDIVIDE_CUSTOMFILL_FACEMAP,
|
|
|
|
|
FACE_CUSTOMFILL);
|
|
|
|
|
|
|
|
|
|
BMO_Mapping_To_Flag(bmesh, op, BMOP_ESUBDIVIDE_PERCENT_EDGEMAP,
|
|
|
|
|
EDGE_PERCENT);
|
|
|
|
|
|
2009-02-02 03:25:23 +00:00
|
|
|
for (face=BMIter_New(&fiter, bmesh, BM_FACES, NULL);
|
|
|
|
|
face; face=BMIter_Step(&fiter)) {
|
|
|
|
|
/*figure out which pattern to use*/
|
2009-02-08 14:25:04 +00:00
|
|
|
|
2009-02-08 11:53:14 +00:00
|
|
|
V_RESET(edges);
|
|
|
|
|
V_RESET(verts);
|
2009-02-08 14:25:04 +00:00
|
|
|
i = 0;
|
2009-02-02 03:25:23 +00:00
|
|
|
for (nl=BMIter_New(&liter, bmesh, BM_LOOPS_OF_FACE, face);
|
|
|
|
|
nl; nl=BMIter_Step(&liter)) {
|
2009-02-08 11:53:14 +00:00
|
|
|
V_GROW(edges);
|
|
|
|
|
V_GROW(verts);
|
2009-02-02 03:25:23 +00:00
|
|
|
edges[i] = nl->e;
|
|
|
|
|
verts[i] = nl->v;
|
|
|
|
|
i++;
|
|
|
|
|
}
|
2009-01-07 15:17:58 +00:00
|
|
|
|
2009-02-08 14:25:04 +00:00
|
|
|
if (BMO_TestFlag(bmesh, face, FACE_CUSTOMFILL)) {
|
2009-02-09 06:36:59 +00:00
|
|
|
pat = BMO_Get_MapData(bmesh, op,
|
|
|
|
|
BMOP_ESUBDIVIDE_CUSTOMFILL_FACEMAP, face);
|
2009-02-08 14:25:04 +00:00
|
|
|
for (i=0; i<pat->len; i++) {
|
|
|
|
|
matched = 1;
|
|
|
|
|
for (j=0; j<pat->len; j++) {
|
|
|
|
|
a = (j + i) % pat->len;
|
|
|
|
|
if ((!!BMO_TestFlag(bmesh, edges[a], SUBD_SPLIT))
|
|
|
|
|
!= (!!pat->seledges[j])) {
|
|
|
|
|
matched = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (matched) {
|
|
|
|
|
V_GROW(facedata);
|
|
|
|
|
b = V_COUNT(facedata)-1;
|
|
|
|
|
facedata[b].pat = pat;
|
|
|
|
|
facedata[b].start = verts[i];
|
Printf-style method of calling operations now take a modified format string,
like so:
[opname] [slotname]=%[format code]
Before it was relying on the input format codes being in the same proper
order as the slots, which seemed like a potential maintainance nightmare to
me. Also the flags for creating buffers from bmop flags or header flags,
now support additional modifiers for combining vert/edge/face inputs.
E.g. %hfvef would accept all geometry with a header flag, and
%fef would accept edges and faces with a certain bmop flag set.
Example from the UI code:
if (!EDBM_CallOpf(em, op, "del geom=%hf context=%d", BM_SELECT, DEL_ONLYFACES))
return OPERATOR_CANCELLED;
(remember EDBM_CallOpf is the UI wrapper for this that does conversion,
error reporting, etc).
On todo is cleaning up/splitting bmesh_operators.h,
since it's kindof a mesh right now. I'm thinking of adding the slot
names in comments next to the slot ids, but I definitely would have to
clean up bmesh_operators.h first, or it'd just be too chaotic for me.
BTW, the operator API should now have enough meta info to wrap with
a scripting language, not that it matters since that's not happening till
much much later.
Also hopefully corrected some SConscripts, fix mostly provided by Elia Sarti,
though I also copied some SConscripts from 2.5 (not sure if doing
so was especially helpful).
Finally, I refactored a few places to use the new operator calling api,
as an example of how this is beneficial.
2009-03-04 08:21:10 +00:00
|
|
|
BMO_SetFlag(bmesh, face, SUBD_SPLIT);
|
2009-02-08 14:25:04 +00:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!matched) {
|
|
|
|
|
/*if no match, append null element to array.*/
|
|
|
|
|
V_GROW(facedata);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*obvously don't test for other patterns matching*/
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-02 03:25:23 +00:00
|
|
|
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;
|
2009-01-07 15:17:58 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (matched) break;
|
2009-02-02 03:25:23 +00:00
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
}
|
2009-01-07 15:17:58 +00:00
|
|
|
}
|
|
|
|
|
}
|
2009-02-02 03:25:23 +00:00
|
|
|
}
|
2009-01-07 15:17:58 +00:00
|
|
|
|
2009-02-08 17:01:28 +00:00
|
|
|
einput = BMO_GetSlot(op, BMOP_ESUBDIVIDE_EDGES);
|
|
|
|
|
|
2009-02-02 03:25:23 +00:00
|
|
|
/*go through and split edges*/
|
|
|
|
|
for (i=0; i<einput->len; i++) {
|
|
|
|
|
edge = ((BMEdge**)einput->data.p)[i];
|
2009-02-08 17:01:28 +00:00
|
|
|
bm_subdivide_multicut(bmesh, edge,¶ms, edge->v1, edge->v2);
|
2009-02-02 03:25:23 +00:00
|
|
|
//BM_Split_Edge_Multi(bmesh, edge, numcuts);
|
|
|
|
|
}
|
2009-01-07 15:17:58 +00:00
|
|
|
|
2009-02-02 03:25:23 +00:00
|
|
|
//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*/
|
2009-02-08 11:53:14 +00:00
|
|
|
V_RESET(verts);
|
2009-02-02 03:25:23 +00:00
|
|
|
if (BMO_TestFlag(bmesh, face, SUBD_SPLIT) == 0) continue;
|
2009-02-08 14:25:04 +00:00
|
|
|
|
2009-02-02 03:25:23 +00:00
|
|
|
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;
|
2009-01-07 15:17:58 +00:00
|
|
|
}
|
2009-02-02 03:25:23 +00:00
|
|
|
j++;
|
|
|
|
|
}
|
2009-01-07 15:17:58 +00:00
|
|
|
|
2009-02-08 12:41:13 +00:00
|
|
|
for (j=0; j<face->len; j++) {
|
|
|
|
|
V_GROW(verts);
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-02 03:25:23 +00:00
|
|
|
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;
|
2009-01-07 15:17:58 +00:00
|
|
|
}
|
2009-02-02 03:25:23 +00:00
|
|
|
|
2009-02-08 17:01:28 +00:00
|
|
|
pat->connectexec(bmesh, face, verts, ¶ms);
|
2009-02-02 03:25:23 +00:00
|
|
|
i++;
|
2009-01-07 15:17:58 +00:00
|
|
|
}
|
2009-02-02 03:25:23 +00:00
|
|
|
|
|
|
|
|
if (facedata) V_FREE(facedata);
|
2009-02-08 11:53:14 +00:00
|
|
|
if (edges) V_FREE(edges);
|
|
|
|
|
if (verts) V_FREE(verts);
|
2009-02-09 07:08:35 +00:00
|
|
|
|
|
|
|
|
BMO_Flag_To_Slot(bmesh, op, BMOP_ESUBDIVIDE_INNER_MULTOUT,
|
|
|
|
|
ELE_INNER, BM_ALL);
|
|
|
|
|
BMO_Flag_To_Slot(bmesh, op, BMOP_ESUBDIVIDE_SPLIT_MULTOUT,
|
|
|
|
|
ELE_SPLIT, BM_ALL);
|
2009-02-02 03:25:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*editmesh-emulating function*/
|
2009-02-03 06:22:30 +00:00
|
|
|
void BM_esubdivideflag(Object *obedit, BMesh *bm, int selflag, float rad,
|
|
|
|
|
int flag, int numcuts, int seltype) {
|
2009-02-02 03:25:23 +00:00
|
|
|
BMOperator op;
|
|
|
|
|
|
Printf-style method of calling operations now take a modified format string,
like so:
[opname] [slotname]=%[format code]
Before it was relying on the input format codes being in the same proper
order as the slots, which seemed like a potential maintainance nightmare to
me. Also the flags for creating buffers from bmop flags or header flags,
now support additional modifiers for combining vert/edge/face inputs.
E.g. %hfvef would accept all geometry with a header flag, and
%fef would accept edges and faces with a certain bmop flag set.
Example from the UI code:
if (!EDBM_CallOpf(em, op, "del geom=%hf context=%d", BM_SELECT, DEL_ONLYFACES))
return OPERATOR_CANCELLED;
(remember EDBM_CallOpf is the UI wrapper for this that does conversion,
error reporting, etc).
On todo is cleaning up/splitting bmesh_operators.h,
since it's kindof a mesh right now. I'm thinking of adding the slot
names in comments next to the slot ids, but I definitely would have to
clean up bmesh_operators.h first, or it'd just be too chaotic for me.
BTW, the operator API should now have enough meta info to wrap with
a scripting language, not that it matters since that's not happening till
much much later.
Also hopefully corrected some SConscripts, fix mostly provided by Elia Sarti,
though I also copied some SConscripts from 2.5 (not sure if doing
so was especially helpful).
Finally, I refactored a few places to use the new operator calling api,
as an example of how this is beneficial.
2009-03-04 08:21:10 +00:00
|
|
|
BMO_InitOpf(bm, &op, "esubd edges=%he flag=%d radius=%f numcuts=%d",
|
|
|
|
|
selflag, flag, rad, numcuts);
|
|
|
|
|
|
2009-02-02 03:25:23 +00:00
|
|
|
BMO_Exec_Op(bm, &op);
|
2009-02-09 07:08:35 +00:00
|
|
|
|
|
|
|
|
if (seltype == SUBDIV_SELECT_INNER) {
|
Printf-style method of calling operations now take a modified format string,
like so:
[opname] [slotname]=%[format code]
Before it was relying on the input format codes being in the same proper
order as the slots, which seemed like a potential maintainance nightmare to
me. Also the flags for creating buffers from bmop flags or header flags,
now support additional modifiers for combining vert/edge/face inputs.
E.g. %hfvef would accept all geometry with a header flag, and
%fef would accept edges and faces with a certain bmop flag set.
Example from the UI code:
if (!EDBM_CallOpf(em, op, "del geom=%hf context=%d", BM_SELECT, DEL_ONLYFACES))
return OPERATOR_CANCELLED;
(remember EDBM_CallOpf is the UI wrapper for this that does conversion,
error reporting, etc).
On todo is cleaning up/splitting bmesh_operators.h,
since it's kindof a mesh right now. I'm thinking of adding the slot
names in comments next to the slot ids, but I definitely would have to
clean up bmesh_operators.h first, or it'd just be too chaotic for me.
BTW, the operator API should now have enough meta info to wrap with
a scripting language, not that it matters since that's not happening till
much much later.
Also hopefully corrected some SConscripts, fix mostly provided by Elia Sarti,
though I also copied some SConscripts from 2.5 (not sure if doing
so was especially helpful).
Finally, I refactored a few places to use the new operator calling api,
as an example of how this is beneficial.
2009-03-04 08:21:10 +00:00
|
|
|
BMOIter iter;
|
2009-02-09 07:08:35 +00:00
|
|
|
BMHeader *ele;
|
|
|
|
|
int i;
|
|
|
|
|
|
Printf-style method of calling operations now take a modified format string,
like so:
[opname] [slotname]=%[format code]
Before it was relying on the input format codes being in the same proper
order as the slots, which seemed like a potential maintainance nightmare to
me. Also the flags for creating buffers from bmop flags or header flags,
now support additional modifiers for combining vert/edge/face inputs.
E.g. %hfvef would accept all geometry with a header flag, and
%fef would accept edges and faces with a certain bmop flag set.
Example from the UI code:
if (!EDBM_CallOpf(em, op, "del geom=%hf context=%d", BM_SELECT, DEL_ONLYFACES))
return OPERATOR_CANCELLED;
(remember EDBM_CallOpf is the UI wrapper for this that does conversion,
error reporting, etc).
On todo is cleaning up/splitting bmesh_operators.h,
since it's kindof a mesh right now. I'm thinking of adding the slot
names in comments next to the slot ids, but I definitely would have to
clean up bmesh_operators.h first, or it'd just be too chaotic for me.
BTW, the operator API should now have enough meta info to wrap with
a scripting language, not that it matters since that's not happening till
much much later.
Also hopefully corrected some SConscripts, fix mostly provided by Elia Sarti,
though I also copied some SConscripts from 2.5 (not sure if doing
so was especially helpful).
Finally, I refactored a few places to use the new operator calling api,
as an example of how this is beneficial.
2009-03-04 08:21:10 +00:00
|
|
|
ele = BMO_IterNew(&iter,bm,&op,BMOP_ESUBDIVIDE_INNER_MULTOUT);
|
|
|
|
|
for (; ele; ele=BMO_IterStep(&iter)) {
|
2009-02-09 07:08:35 +00:00
|
|
|
BM_Select(bm, ele, 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-02-02 03:25:23 +00:00
|
|
|
BMO_Finish_Op(bm, &op);
|
|
|
|
|
}
|
2009-02-03 06:22:30 +00:00
|
|
|
|
|
|
|
|
void BM_esubdivideflag_conv(Object *obedit,EditMesh *em,int selflag, float rad,
|
|
|
|
|
int flag, int numcuts, int seltype) {
|
|
|
|
|
BMesh *bm = editmesh_to_bmesh(em);
|
|
|
|
|
EditMesh *em2;
|
|
|
|
|
|
|
|
|
|
BM_esubdivideflag(obedit, bm, selflag, rad, flag, numcuts, seltype);
|
|
|
|
|
em2 = bmesh_to_editmesh(bm);
|
|
|
|
|
|
|
|
|
|
free_editMesh(em);
|
|
|
|
|
*em = *em2;
|
|
|
|
|
MEM_freeN(em2);
|
|
|
|
|
BM_Free_Mesh(bm);
|
|
|
|
|
}
|